]> git.sesse.net Git - vlc/blob - modules/access/rtsp/real.c
Remove WPL module
[vlc] / modules / access / rtsp / real.c
1 /*****************************************************************************
2  * real.c: real rtsp input
3  *****************************************************************************
4  * Copyright (C) 2002-2004 the xine project
5  * Copyright (C) 2005 VideoLAN
6  * $Id$
7  *
8  * Authors: Gildas Bazin <gbazin@videolan.org>
9  *          Adapted from xine which itself adapted it from joschkas real tools.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <vlc_common.h>
31 #include <vlc_memory.h>
32
33 #include "rtsp.h"
34 #include "real.h"
35 #include "real_sdpplin.h"
36
37 #define XOR_TABLE_LEN 37
38 static const unsigned char xor_table[] = {
39     0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
40     0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
41     0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
42     0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
43     0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
44
45 #define BE_32(x) GetDWBE(x)
46 #define LE_32(x) GetDWLE(x)
47 #define BE_16(x) GetWBE(x)
48 #define LE_16(x) GetWLE(x)
49 #define BE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWBE(&in);} while(0)
50 #define LE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWLE(&in);} while(0)
51 #define MAX(x,y) ((x>y) ? x : y)
52
53 static void hash(char *field, char *param)
54 {
55   uint32_t a, b, c, d;
56
57   /* fill variables */
58   a = LE_32(field);
59   b = LE_32(field+4);
60   c = LE_32(field+8);
61   d = LE_32(field+12);
62
63   lprintf("hash input: %x %x %x %x\n", a, b, c, d);
64   lprintf("hash parameter:\n");
65
66   a = ((b & c) | (~b & d)) + LE_32((param+0x00)) + a - 0x28955B88;
67   a = ((a << 0x07) | (a >> 0x19)) + b;
68   d = ((a & b) | (~a & c)) + LE_32((param+0x04)) + d - 0x173848AA;
69   d = ((d << 0x0c) | (d >> 0x14)) + a;
70   c = ((d & a) | (~d & b)) + LE_32((param+0x08)) + c + 0x242070DB;
71   c = ((c << 0x11) | (c >> 0x0f)) + d;
72   b = ((c & d) | (~c & a)) + LE_32((param+0x0c)) + b - 0x3E423112;
73   b = ((b << 0x16) | (b >> 0x0a)) + c;
74   a = ((b & c) | (~b & d)) + LE_32((param+0x10)) + a - 0x0A83F051;
75   a = ((a << 0x07) | (a >> 0x19)) + b;
76   d = ((a & b) | (~a & c)) + LE_32((param+0x14)) + d + 0x4787C62A;
77   d = ((d << 0x0c) | (d >> 0x14)) + a;
78   c = ((d & a) | (~d & b)) + LE_32((param+0x18)) + c - 0x57CFB9ED;
79   c = ((c << 0x11) | (c >> 0x0f)) + d;
80   b = ((c & d) | (~c & a)) + LE_32((param+0x1c)) + b - 0x02B96AFF;
81   b = ((b << 0x16) | (b >> 0x0a)) + c;
82   a = ((b & c) | (~b & d)) + LE_32((param+0x20)) + a + 0x698098D8;
83   a = ((a << 0x07) | (a >> 0x19)) + b;
84   d = ((a & b) | (~a & c)) + LE_32((param+0x24)) + d - 0x74BB0851;
85   d = ((d << 0x0c) | (d >> 0x14)) + a;
86   c = ((d & a) | (~d & b)) + LE_32((param+0x28)) + c - 0x0000A44F;
87   c = ((c << 0x11) | (c >> 0x0f)) + d;
88   b = ((c & d) | (~c & a)) + LE_32((param+0x2C)) + b - 0x76A32842;
89   b = ((b << 0x16) | (b >> 0x0a)) + c;
90   a = ((b & c) | (~b & d)) + LE_32((param+0x30)) + a + 0x6B901122;
91   a = ((a << 0x07) | (a >> 0x19)) + b;
92   d = ((a & b) | (~a & c)) + LE_32((param+0x34)) + d - 0x02678E6D;
93   d = ((d << 0x0c) | (d >> 0x14)) + a;
94   c = ((d & a) | (~d & b)) + LE_32((param+0x38)) + c - 0x5986BC72;
95   c = ((c << 0x11) | (c >> 0x0f)) + d;
96   b = ((c & d) | (~c & a)) + LE_32((param+0x3c)) + b + 0x49B40821;
97   b = ((b << 0x16) | (b >> 0x0a)) + c;
98
99   a = ((b & d) | (~d & c)) + LE_32((param+0x04)) + a - 0x09E1DA9E;
100   a = ((a << 0x05) | (a >> 0x1b)) + b;
101   d = ((a & c) | (~c & b)) + LE_32((param+0x18)) + d - 0x3FBF4CC0;
102   d = ((d << 0x09) | (d >> 0x17)) + a;
103   c = ((d & b) | (~b & a)) + LE_32((param+0x2c)) + c + 0x265E5A51;
104   c = ((c << 0x0e) | (c >> 0x12)) + d;
105   b = ((c & a) | (~a & d)) + LE_32((param+0x00)) + b - 0x16493856;
106   b = ((b << 0x14) | (b >> 0x0c)) + c;
107   a = ((b & d) | (~d & c)) + LE_32((param+0x14)) + a - 0x29D0EFA3;
108   a = ((a << 0x05) | (a >> 0x1b)) + b;
109   d = ((a & c) | (~c & b)) + LE_32((param+0x28)) + d + 0x02441453;
110   d = ((d << 0x09) | (d >> 0x17)) + a;
111   c = ((d & b) | (~b & a)) + LE_32((param+0x3c)) + c - 0x275E197F;
112   c = ((c << 0x0e) | (c >> 0x12)) + d;
113   b = ((c & a) | (~a & d)) + LE_32((param+0x10)) + b - 0x182C0438;
114   b = ((b << 0x14) | (b >> 0x0c)) + c;
115   a = ((b & d) | (~d & c)) + LE_32((param+0x24)) + a + 0x21E1CDE6;
116   a = ((a << 0x05) | (a >> 0x1b)) + b;
117   d = ((a & c) | (~c & b)) + LE_32((param+0x38)) + d - 0x3CC8F82A;
118   d = ((d << 0x09) | (d >> 0x17)) + a;
119   c = ((d & b) | (~b & a)) + LE_32((param+0x0c)) + c - 0x0B2AF279;
120   c = ((c << 0x0e) | (c >> 0x12)) + d;
121   b = ((c & a) | (~a & d)) + LE_32((param+0x20)) + b + 0x455A14ED;
122   b = ((b << 0x14) | (b >> 0x0c)) + c;
123   a = ((b & d) | (~d & c)) + LE_32((param+0x34)) + a - 0x561C16FB;
124   a = ((a << 0x05) | (a >> 0x1b)) + b;
125   d = ((a & c) | (~c & b)) + LE_32((param+0x08)) + d - 0x03105C08;
126   d = ((d << 0x09) | (d >> 0x17)) + a;
127   c = ((d & b) | (~b & a)) + LE_32((param+0x1c)) + c + 0x676F02D9;
128   c = ((c << 0x0e) | (c >> 0x12)) + d;
129   b = ((c & a) | (~a & d)) + LE_32((param+0x30)) + b - 0x72D5B376;
130   b = ((b << 0x14) | (b >> 0x0c)) + c;
131
132   a = (b ^ c ^ d) + LE_32((param+0x14)) + a - 0x0005C6BE;
133   a = ((a << 0x04) | (a >> 0x1c)) + b;
134   d = (a ^ b ^ c) + LE_32((param+0x20)) + d - 0x788E097F;
135   d = ((d << 0x0b) | (d >> 0x15)) + a;
136   c = (d ^ a ^ b) + LE_32((param+0x2c)) + c + 0x6D9D6122;
137   c = ((c << 0x10) | (c >> 0x10)) + d;
138   b = (c ^ d ^ a) + LE_32((param+0x38)) + b - 0x021AC7F4;
139   b = ((b << 0x17) | (b >> 0x09)) + c;
140   a = (b ^ c ^ d) + LE_32((param+0x04)) + a - 0x5B4115BC;
141   a = ((a << 0x04) | (a >> 0x1c)) + b;
142   d = (a ^ b ^ c) + LE_32((param+0x10)) + d + 0x4BDECFA9;
143   d = ((d << 0x0b) | (d >> 0x15)) + a;
144   c = (d ^ a ^ b) + LE_32((param+0x1c)) + c - 0x0944B4A0;
145   c = ((c << 0x10) | (c >> 0x10)) + d;
146   b = (c ^ d ^ a) + LE_32((param+0x28)) + b - 0x41404390;
147   b = ((b << 0x17) | (b >> 0x09)) + c;
148   a = (b ^ c ^ d) + LE_32((param+0x34)) + a + 0x289B7EC6;
149   a = ((a << 0x04) | (a >> 0x1c)) + b;
150   d = (a ^ b ^ c) + LE_32((param+0x00)) + d - 0x155ED806;
151   d = ((d << 0x0b) | (d >> 0x15)) + a;
152   c = (d ^ a ^ b) + LE_32((param+0x0c)) + c - 0x2B10CF7B;
153   c = ((c << 0x10) | (c >> 0x10)) + d;
154   b = (c ^ d ^ a) + LE_32((param+0x18)) + b + 0x04881D05;
155   b = ((b << 0x17) | (b >> 0x09)) + c;
156   a = (b ^ c ^ d) + LE_32((param+0x24)) + a - 0x262B2FC7;
157   a = ((a << 0x04) | (a >> 0x1c)) + b;
158   d = (a ^ b ^ c) + LE_32((param+0x30)) + d - 0x1924661B;
159   d = ((d << 0x0b) | (d >> 0x15)) + a;
160   c = (d ^ a ^ b) + LE_32((param+0x3c)) + c + 0x1fa27cf8;
161   c = ((c << 0x10) | (c >> 0x10)) + d;
162   b = (c ^ d ^ a) + LE_32((param+0x08)) + b - 0x3B53A99B;
163   b = ((b << 0x17) | (b >> 0x09)) + c;
164
165   a = ((~d | b) ^ c)  + LE_32((param+0x00)) + a - 0x0BD6DDBC;
166   a = ((a << 0x06) | (a >> 0x1a)) + b;
167   d = ((~c | a) ^ b)  + LE_32((param+0x1c)) + d + 0x432AFF97;
168   d = ((d << 0x0a) | (d >> 0x16)) + a;
169   c = ((~b | d) ^ a)  + LE_32((param+0x38)) + c - 0x546BDC59;
170   c = ((c << 0x0f) | (c >> 0x11)) + d;
171   b = ((~a | c) ^ d)  + LE_32((param+0x14)) + b - 0x036C5FC7;
172   b = ((b << 0x15) | (b >> 0x0b)) + c;
173   a = ((~d | b) ^ c)  + LE_32((param+0x30)) + a + 0x655B59C3;
174   a = ((a << 0x06) | (a >> 0x1a)) + b;
175   d = ((~c | a) ^ b)  + LE_32((param+0x0C)) + d - 0x70F3336E;
176   d = ((d << 0x0a) | (d >> 0x16)) + a;
177   c = ((~b | d) ^ a)  + LE_32((param+0x28)) + c - 0x00100B83;
178   c = ((c << 0x0f) | (c >> 0x11)) + d;
179   b = ((~a | c) ^ d)  + LE_32((param+0x04)) + b - 0x7A7BA22F;
180   b = ((b << 0x15) | (b >> 0x0b)) + c;
181   a = ((~d | b) ^ c)  + LE_32((param+0x20)) + a + 0x6FA87E4F;
182   a = ((a << 0x06) | (a >> 0x1a)) + b;
183   d = ((~c | a) ^ b)  + LE_32((param+0x3c)) + d - 0x01D31920;
184   d = ((d << 0x0a) | (d >> 0x16)) + a;
185   c = ((~b | d) ^ a)  + LE_32((param+0x18)) + c - 0x5CFEBCEC;
186   c = ((c << 0x0f) | (c >> 0x11)) + d;
187   b = ((~a | c) ^ d)  + LE_32((param+0x34)) + b + 0x4E0811A1;
188   b = ((b << 0x15) | (b >> 0x0b)) + c;
189   a = ((~d | b) ^ c)  + LE_32((param+0x10)) + a - 0x08AC817E;
190   a = ((a << 0x06) | (a >> 0x1a)) + b;
191   d = ((~c | a) ^ b)  + LE_32((param+0x2c)) + d - 0x42C50DCB;
192   d = ((d << 0x0a) | (d >> 0x16)) + a;
193   c = ((~b | d) ^ a)  + LE_32((param+0x08)) + c + 0x2AD7D2BB;
194   c = ((c << 0x0f) | (c >> 0x11)) + d;
195   b = ((~a | c) ^ d)  + LE_32((param+0x24)) + b - 0x14792C6F;
196   b = ((b << 0x15) | (b >> 0x0b)) + c;
197
198   lprintf("hash output: %x %x %x %x\n", a, b, c, d);
199
200   a += LE_32(field);
201   b += LE_32(field+4);
202   c += LE_32(field+8);
203   d += LE_32(field+12);
204
205   LE_32C(field, a);
206   LE_32C(field+4, b);
207   LE_32C(field+8, c);
208   LE_32C(field+12, d);
209 }
210
211 static void call_hash (char *key, char *challenge, unsigned int len) {
212   uint8_t *ptr1, *ptr2;
213   uint32_t a, b, c, d, tmp;
214
215   ptr1=(uint8_t*)(key+16);
216   ptr2=(uint8_t*)(key+20);
217
218   a = LE_32(ptr1);
219   b = (a >> 3) & 0x3f;
220   a += len * 8;
221   LE_32C(ptr1, a);
222
223   if (a < (len << 3))
224   {
225     lprintf("not verified: (len << 3) > a true\n");
226     ptr2 += 4;
227   }
228
229   tmp = LE_32(ptr2) + (len >> 0x1d);
230   LE_32C(ptr2, tmp);
231   a = 64 - b;
232   c = 0;
233   if (a <= len)
234   {
235     memcpy(key+b+24, challenge, a);
236     hash(key, key+24);
237     c = a;
238     d = c + 0x3f;
239
240     while ( d < len ) {
241       lprintf("not verified:  while ( d < len )\n");
242       hash(key, challenge+d-0x3f);
243       d += 64;
244       c += 64;
245     }
246     b = 0;
247   }
248
249   memcpy(key+b+24, challenge+c, len-c);
250 }
251
252 static void calc_response (char *result, char *field) {
253   char buf1[128];
254   char buf2[128];
255   int i;
256
257   memset (buf1, 0, 64);
258   *buf1 = 128;
259
260   memcpy (buf2, field+16, 8);
261   i = ( LE_32((buf2)) >> 3 ) & 0x3f;
262
263   if (i < 56)
264   {
265     i = 56 - i;
266   } else
267   {
268     lprintf("not verified: ! (i < 56)\n");
269     i = 120 - i;
270   }
271
272   call_hash (field, buf1, i);
273   call_hash (field, buf2, 8);
274   memcpy (result, field, 16);
275 }
276
277 static void calc_response_string (char *result, char *challenge) {
278
279   char field[128] = {
280     0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
281     0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10,
282     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
283     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
284   };
285   char zres[20];
286   int  i;
287
288   /* calculate response */
289   call_hash(field, challenge, 64);
290   calc_response(zres,field);
291
292   /* convert zres to ascii string */
293   for (i=0; i<16; i++ ) {
294     char a, b;
295
296     a = (zres[i] >> 4) & 15;
297     b = zres[i] & 15;
298
299     result[i*2]   = ((a<10) ? (a+48) : (a+87)) & 255;
300     result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255;
301   }
302 }
303
304 static void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) {
305
306   int   ch_len, resp_len;
307   int   i;
308   char *ptr;
309   char  buf[128];
310
311   /* initialize return values */
312   memset(response, 0, 64);
313   memset(chksum, 0, 34);
314
315   /* initialize buffer */
316   memset(buf, 0, 128);
317   ptr=buf;
318   BE_32C(ptr, 0xa1e9149d);
319   ptr+=4;
320   BE_32C(ptr, 0x0e6b3b59);
321   ptr+=4;
322
323   /* some (length) checks */
324   if (challenge != NULL)
325   {
326     ch_len = strlen (challenge);
327
328     if (ch_len == 40) /* what a hack... */
329     {
330       challenge[32]=0;
331       ch_len=32;
332     }
333     if ( ch_len > 56 ) ch_len=56;
334
335     /* copy challenge to buf */
336     memcpy(ptr, challenge, ch_len);
337   }
338
339   /* xor challenge bytewise with xor_table */
340   for (i=0; i<XOR_TABLE_LEN; i++)
341     ptr[i] = ptr[i] ^ xor_table[i];
342
343   calc_response_string (response, buf);
344
345   /* add tail */
346   resp_len = strlen (response);
347   strcpy (&response[resp_len], "01d0a8e3");
348
349   /* calculate checksum */
350   for (i=0; i<resp_len/4; i++)
351     chksum[i] = response[i*4];
352 }
353
354 #define MLTI_BUF_MAX_SIZE 2048
355
356 /*
357  * takes a MLTI-Chunk and a rule number got from match_asm_rule,
358  * returns a pointer to selected data and number of bytes in that.
359  */
360 static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
361
362   int numrules, codec, size;
363   int i;
364
365   /* MLTI chunk should begin with MLTI */
366   if ((mlti_chunk[0] != 'M')
367       ||(mlti_chunk[1] != 'L')
368       ||(mlti_chunk[2] != 'T')
369       ||(mlti_chunk[3] != 'I'))
370   {
371     lprintf("MLTI tag not detected, copying data\n");
372     memcpy(*out, mlti_chunk, __MIN(mlti_size,MLTI_BUF_MAX_SIZE));
373     return mlti_size;
374   }
375
376   mlti_chunk+=4;
377
378   /* next 16 bits are the number of rules */
379   numrules=BE_16(mlti_chunk);
380   if (selection >= numrules) return 0;
381
382   /* now <numrules> indices of codecs follows */
383   /* we skip to selection                     */
384   mlti_chunk+=(selection+1)*2;
385
386   /* get our index */
387   codec=BE_16(mlti_chunk);
388
389   /* skip to number of codecs */
390   mlti_chunk+=(numrules-selection)*2;
391
392   /* get number of codecs */
393   numrules=BE_16(mlti_chunk);
394
395   if (codec >= numrules) {
396     lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
397     return 0;
398   }
399
400   mlti_chunk+=2;
401
402   /* now seek to selected codec */
403   for (i=0; i<codec; i++) {
404     size=BE_32(mlti_chunk);
405     mlti_chunk+=size+4;
406   }
407   size=BE_32(mlti_chunk);
408
409   memcpy(*out, mlti_chunk+4, __MIN(size,MLTI_BUF_MAX_SIZE));
410   return size;
411 }
412
413 /*
414  * looking at stream description.
415  */
416
417 static rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
418
419   sdpplin_t *desc = NULL;
420   rmff_header_t *header = NULL;
421   char *buf = NULL;
422   int len, i;
423   int max_bit_rate=0;
424   int avg_bit_rate=0;
425   int max_packet_size=0;
426   int avg_packet_size=0;
427   int duration=0;
428
429   if( !data ) return NULL;
430
431   desc=sdpplin_parse(data);
432   if( !desc ) return NULL;
433
434   buf= (char *)malloc(MLTI_BUF_MAX_SIZE);
435   if( !buf ) goto error;
436
437   header = calloc( 1, sizeof(rmff_header_t) );
438   if( !header ) goto error;
439
440   header->fileheader=rmff_new_fileheader(4+desc->stream_count);
441   header->cont=rmff_new_cont(
442       desc->title,
443       desc->author,
444       desc->copyright,
445       desc->abstract);
446
447   header->data=rmff_new_dataheader(0,0);
448   if( !header->data ) goto error;
449
450   header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
451   if( !header->streams ) goto error;
452
453   lprintf("number of streams: %u\n", desc->stream_count);
454
455   for (i=0; i<desc->stream_count; i++) {
456
457     int j=0;
458     int n;
459     char b[64];
460     int rulematches[16];
461
462     lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
463
464     n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
465     for (j=0; j<n; j++) {
466       lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
467       sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
468       strcat(*stream_rules, b);
469     }
470
471     if (!desc->stream[i]->mlti_data) {
472       len = 0;
473       free( buf );
474       buf = NULL;
475     } else
476       len=select_mlti_data(desc->stream[i]->mlti_data,
477         desc->stream[i]->mlti_data_size, rulematches[0], &buf);
478
479     header->streams[i]=rmff_new_mdpr(
480       desc->stream[i]->stream_id,
481         desc->stream[i]->max_bit_rate,
482         desc->stream[i]->avg_bit_rate,
483         desc->stream[i]->max_packet_size,
484         desc->stream[i]->avg_packet_size,
485         desc->stream[i]->start_time,
486         desc->stream[i]->preroll,
487         desc->stream[i]->duration,
488         desc->stream[i]->stream_name,
489         desc->stream[i]->mime_type,
490         len,
491         buf);
492     if( !header->streams[i] ) goto error;
493
494     duration=MAX(duration,desc->stream[i]->duration);
495     max_bit_rate+=desc->stream[i]->max_bit_rate;
496     avg_bit_rate+=desc->stream[i]->avg_bit_rate;
497     max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
498     if (avg_packet_size)
499       avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
500     else
501       avg_packet_size=desc->stream[i]->avg_packet_size;
502   }
503
504   if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
505       (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
506
507   header->prop=rmff_new_prop(
508       max_bit_rate,
509       avg_bit_rate,
510       max_packet_size,
511       avg_packet_size,
512       0,
513       duration,
514       0,
515       0,
516       0,
517       desc->stream_count,
518       desc->flags);
519   if( !header->prop ) goto error;
520
521   rmff_fix_header(header);
522
523   sdpplin_free( desc );
524   free( buf );
525   return header;
526
527 error:
528   sdpplin_free( desc );
529   rmff_free_header( header );
530   free( buf );
531   return NULL;
532 }
533
534 int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
535
536   int n=1;
537   uint8_t header[8];
538   int size;
539   int flags1;
540   int unknown1;
541   uint32_t ts;
542
543   n=rtsp_read_data(rtsp_session, header, 8);
544   if (n<8) return 0;
545   if (header[0] != 0x24)
546   {
547     lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
548     return 0;
549   }
550   size=(header[1]<<16)+(header[2]<<8)+(header[3]);
551   flags1=header[4];
552   if ((flags1!=0x40)&&(flags1!=0x42))
553   {
554     lprintf("got flags1: 0x%02x\n",flags1);
555     if (header[6]==0x06)
556     {
557       lprintf("got end of stream packet\n");
558       return 0;
559     }
560     header[0]=header[5];
561     header[1]=header[6];
562     header[2]=header[7];
563     n=rtsp_read_data(rtsp_session, header+3, 5);
564     if (n<5) return 0;
565     lprintf("ignoring bytes:\n");
566     n=rtsp_read_data(rtsp_session, header+4, 4);
567     if (n<4) return 0;
568     flags1=header[4];
569     size-=9;
570   }
571   unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
572   n=rtsp_read_data(rtsp_session, header, 6);
573   if (n<6) return 0;
574   ts=BE_32(header);
575
576 #if 0
577   lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
578           ts, size, flags1, unknown1, header[4], header[5]);
579 #endif
580
581   size+=2;
582   ph->object_version=0;
583   ph->length=size;
584   ph->stream_number=(flags1>>1)&1;
585   ph->timestamp=ts;
586   ph->reserved=0;
587   ph->flags=0;      /* TODO: determine keyframe flag and insert here? */
588   return size;
589 }
590
591 int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
592                        unsigned char **buffer) {
593
594   int n;
595   rmff_dump_pheader(ph, (char*)*buffer);
596   if (ph->length<12) return 0;
597   n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
598   return (n <= 0) ? 0 : n+12;
599 }
600
601 //! maximum size of the rtsp description, must be < INT_MAX
602 #define MAX_DESC_BUF (20 * 1024 * 1024)
603 rmff_header_t  *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
604
605   char *description=NULL;
606   char *session_id=NULL;
607   rmff_header_t *h=NULL;
608   char *challenge1 = NULL;
609   char challenge2[64];
610   char checksum[34];
611   char *subscribe=NULL;
612   char *buf = malloc(256);
613   if( !buf )
614     return NULL;
615   char *mrl=rtsp_get_mrl(rtsp_session);
616   unsigned int size;
617   int status;
618
619   /* get challenge */
620   challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
621   lprintf("Challenge1: %s\n", challenge1);
622
623   /* request stream description */
624   rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
625   sprintf(buf, "Bandwidth: %u", bandwidth);
626   rtsp_schedule_field(rtsp_session, buf);
627   rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
628   rtsp_schedule_field(rtsp_session, "RegionData: 0");
629   rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
630   rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
631   rtsp_schedule_field(rtsp_session, "Language: en-US");
632   rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
633
634   status=rtsp_request_describe(rtsp_session,NULL);
635   if ( status<200 || status>299 ) {
636     char *alert=rtsp_search_answers(rtsp_session,"Alert");
637     if (alert) {
638         lprintf("real: got message from server:\n%s\n", alert);
639     }
640     rtsp_send_ok( rtsp_session );
641     free( challenge1 );
642     free( alert );
643     free( buf );
644     return NULL;
645   }
646
647   /* receive description */
648   size=0;
649   if (!rtsp_search_answers(rtsp_session,"Content-length"))
650     lprintf("real: got no Content-length!\n");
651   else
652     size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
653
654   if (size > MAX_DESC_BUF) {
655     printf("real: Content-length for description too big (> %uMB)!\n",
656         MAX_DESC_BUF/(1024*1024) );
657     goto error;
658   }
659
660   if (!rtsp_search_answers(rtsp_session,"ETag"))
661     lprintf("real: got no ETag!\n");
662   else
663     session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
664
665   lprintf("Stream description size: %i\n", size);
666
667   description = malloc(size+1);
668   if( !description )
669     goto error;
670   if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
671     goto error;
672   description[size]=0;
673   //fprintf(stderr, "%s", description);
674
675   /* parse sdp (sdpplin) and create a header and a subscribe string */
676   subscribe = malloc(256);
677   if( !subscribe )
678     goto error;
679
680   strcpy(subscribe, "Subscribe: ");
681   h=real_parse_sdp(description, &subscribe, bandwidth);
682   if (!h)
683     goto error;
684
685   rmff_fix_header(h);
686
687 #if 0
688   fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
689       h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
690 #endif
691
692   /* setup our streams */
693   real_calc_response_and_checksum (challenge2, checksum, challenge1);
694   buf = realloc_or_free(buf, strlen(challenge2) + strlen(checksum) + 32);
695   if( !buf ) goto error;
696   sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
697   rtsp_schedule_field(rtsp_session, buf);
698   buf = realloc_or_free(buf, strlen(session_id) + 32);
699   if( !buf ) goto error;
700   sprintf(buf, "If-Match: %s", session_id);
701   rtsp_schedule_field(rtsp_session, buf);
702   rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
703   buf = realloc_or_free(buf, strlen(mrl) + 32);
704   if( !buf ) goto error;
705   sprintf(buf, "%s/streamid=0", mrl);
706   rtsp_request_setup(rtsp_session,buf);
707
708   if (h->prop->num_streams > 1) {
709     rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
710     buf = realloc_or_free(buf, strlen(session_id) + 32);
711     if( !buf ) goto error;
712     sprintf(buf, "If-Match: %s", session_id);
713     rtsp_schedule_field(rtsp_session, buf);
714     buf = realloc_or_free(buf, strlen(mrl) + 32);
715     if( !buf ) goto error;
716     sprintf(buf, "%s/streamid=1", mrl);
717     rtsp_request_setup(rtsp_session,buf);
718   }
719   /* set stream parameter (bandwidth) with our subscribe string */
720   rtsp_schedule_field(rtsp_session, subscribe);
721   rtsp_request_setparameter(rtsp_session,NULL);
722
723   /* and finally send a play request */
724   rtsp_schedule_field(rtsp_session, "Range: npt=0-");
725   rtsp_request_play(rtsp_session,NULL);
726
727   free( challenge1 );
728   free( session_id );
729   free( description );
730   free( subscribe );
731   free( buf );
732   return h;
733
734 error:
735   rmff_free_header( h );
736   free( challenge1 );
737   free( session_id );
738   free( description );
739   free( subscribe );
740   free( buf );
741   return NULL;
742 }