]> git.sesse.net Git - vlc/blob - modules/access/rtsp/real.c
Merge branch 1.0-bugfix
[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
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 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
32 #include "rtsp.h"
33 #include "real.h"
34 #include "real_sdpplin.h"
35
36 #define XOR_TABLE_LEN 37
37 static const unsigned char xor_table[] = {
38     0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
39     0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
40     0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
41     0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
42     0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
43
44 #define BE_32(x) GetDWBE(x)
45 #define LE_32(x) GetDWLE(x)
46 #define BE_16(x) GetWBE(x)
47 #define LE_16(x) GetWLE(x)
48 #define BE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWBE(&in);} while(0)
49 #define LE_32C(x,y) do {uint32_t in=y; *(uint32_t *)(x)=GetDWLE(&in);} while(0)
50 #define MAX(x,y) ((x>y) ? x : y)
51
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 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
355 /*
356  * takes a MLTI-Chunk and a rule number got from match_asm_rule,
357  * returns a pointer to selected data and number of bytes in that.
358  */
359 static int select_mlti_data(const char *mlti_chunk, int mlti_size, int selection, char **out) {
360
361   int numrules, codec, size;
362   int i;
363
364   /* MLTI chunk should begin with MLTI */
365   if ((mlti_chunk[0] != 'M')
366       ||(mlti_chunk[1] != 'L')
367       ||(mlti_chunk[2] != 'T')
368       ||(mlti_chunk[3] != 'I'))
369   {
370     lprintf("MLTI tag not detected, copying data\n");
371     memcpy(*out, mlti_chunk, mlti_size);
372     return mlti_size;
373   }
374
375   mlti_chunk+=4;
376
377   /* next 16 bits are the number of rules */
378   numrules=BE_16(mlti_chunk);
379   if (selection >= numrules) return 0;
380
381   /* now <numrules> indices of codecs follows */
382   /* we skip to selection                     */
383   mlti_chunk+=(selection+1)*2;
384
385   /* get our index */
386   codec=BE_16(mlti_chunk);
387
388   /* skip to number of codecs */
389   mlti_chunk+=(numrules-selection)*2;
390
391   /* get number of codecs */
392   numrules=BE_16(mlti_chunk);
393
394   if (codec >= numrules) {
395     lprintf("codec index >= number of codecs. %i %i\n", codec, numrules);
396     return 0;
397   }
398
399   mlti_chunk+=2;
400
401   /* now seek to selected codec */
402   for (i=0; i<codec; i++) {
403     size=BE_32(mlti_chunk);
404     mlti_chunk+=size+4;
405   }
406   size=BE_32(mlti_chunk);
407
408   memcpy(*out, mlti_chunk+4, size);
409   return size;
410 }
411
412 /*
413  * looking at stream description.
414  */
415
416 rmff_header_t *real_parse_sdp(char *data, char **stream_rules, uint32_t bandwidth) {
417
418   sdpplin_t *desc = NULL;
419   rmff_header_t *header = NULL;
420   char *buf = NULL;
421   int len, i;
422   int max_bit_rate=0;
423   int avg_bit_rate=0;
424   int max_packet_size=0;
425   int avg_packet_size=0;
426   int duration=0;
427
428   if( !data ) return NULL;
429
430   desc=sdpplin_parse(data);
431   if( !desc ) return NULL;
432
433   buf= (char *)malloc(2048);
434   if( !buf ) goto error;
435
436   header = calloc( 1, sizeof(rmff_header_t) );
437   if( !header ) goto error;
438
439   header->fileheader=rmff_new_fileheader(4+desc->stream_count);
440   header->cont=rmff_new_cont(
441       desc->title,
442       desc->author,
443       desc->copyright,
444       desc->abstract);
445
446   header->data=rmff_new_dataheader(0,0);
447   if( !header->data ) goto error;
448
449   header->streams = calloc( desc->stream_count+1, sizeof(rmff_mdpr_t*) );
450   if( !header->streams ) goto error;
451
452   lprintf("number of streams: %u\n", desc->stream_count);
453
454   for (i=0; i<desc->stream_count; i++) {
455
456     int j=0;
457     int n;
458     char b[64];
459     int rulematches[16];
460
461     lprintf("calling asmrp_match with:\n%s\n%u\n", desc->stream[i]->asm_rule_book, bandwidth);
462
463     n=asmrp_match(desc->stream[i]->asm_rule_book, bandwidth, rulematches, sizeof(rulematches)/sizeof(rulematches[0]));
464     for (j=0; j<n; j++) {
465       lprintf("asmrp rule match: %u for stream %u\n", rulematches[j], desc->stream[i]->stream_id);
466       sprintf(b,"stream=%u;rule=%u,", desc->stream[i]->stream_id, rulematches[j]);
467       strcat(*stream_rules, b);
468     }
469
470     if (!desc->stream[i]->mlti_data) {
471       len = 0;
472       free( buf );
473       buf = NULL;
474     } else
475       len=select_mlti_data(desc->stream[i]->mlti_data,
476         desc->stream[i]->mlti_data_size, rulematches[0], &buf);
477
478     header->streams[i]=rmff_new_mdpr(
479       desc->stream[i]->stream_id,
480         desc->stream[i]->max_bit_rate,
481         desc->stream[i]->avg_bit_rate,
482         desc->stream[i]->max_packet_size,
483         desc->stream[i]->avg_packet_size,
484         desc->stream[i]->start_time,
485         desc->stream[i]->preroll,
486         desc->stream[i]->duration,
487         desc->stream[i]->stream_name,
488         desc->stream[i]->mime_type,
489         len,
490         buf);
491     if( !header->streams[i] ) goto error;
492
493     duration=MAX(duration,desc->stream[i]->duration);
494     max_bit_rate+=desc->stream[i]->max_bit_rate;
495     avg_bit_rate+=desc->stream[i]->avg_bit_rate;
496     max_packet_size=MAX(max_packet_size, desc->stream[i]->max_packet_size);
497     if (avg_packet_size)
498       avg_packet_size=(avg_packet_size + desc->stream[i]->avg_packet_size) / 2;
499     else
500       avg_packet_size=desc->stream[i]->avg_packet_size;
501   }
502
503   if (*stream_rules && strlen(*stream_rules) && (*stream_rules)[strlen(*stream_rules)-1] == ',')
504       (*stream_rules)[strlen(*stream_rules)-1]=0; /* delete last ',' in stream_rules */
505
506   header->prop=rmff_new_prop(
507       max_bit_rate,
508       avg_bit_rate,
509       max_packet_size,
510       avg_packet_size,
511       0,
512       duration,
513       0,
514       0,
515       0,
516       desc->stream_count,
517       desc->flags);
518   if( !header->prop ) goto error;
519
520   rmff_fix_header(header);
521
522   sdpplin_free( desc );
523   free( buf );
524   return header;
525
526 error:
527   sdpplin_free( desc );
528   rmff_free_header( header );
529   free( buf );
530   return NULL;
531 }
532
533 int real_get_rdt_chunk_header(rtsp_client_t *rtsp_session, rmff_pheader_t *ph) {
534
535   int n=1;
536   uint8_t header[8];
537   int size;
538   int flags1;
539   int unknown1;
540   uint32_t ts;
541
542   n=rtsp_read_data(rtsp_session, header, 8);
543   if (n<8) return 0;
544   if (header[0] != 0x24)
545   {
546     lprintf("rdt chunk not recognized: got 0x%02x\n", header[0]);
547     return 0;
548   }
549   size=(header[1]<<16)+(header[2]<<8)+(header[3]);
550   flags1=header[4];
551   if ((flags1!=0x40)&&(flags1!=0x42))
552   {
553     lprintf("got flags1: 0x%02x\n",flags1);
554     if (header[6]==0x06)
555     {
556       lprintf("got end of stream packet\n");
557       return 0;
558     }
559     header[0]=header[5];
560     header[1]=header[6];
561     header[2]=header[7];
562     n=rtsp_read_data(rtsp_session, header+3, 5);
563     if (n<5) return 0;
564     lprintf("ignoring bytes:\n");
565     n=rtsp_read_data(rtsp_session, header+4, 4);
566     if (n<4) return 0;
567     flags1=header[4];
568     size-=9;
569   }
570   unknown1=(header[5]<<16)+(header[6]<<8)+(header[7]);
571   n=rtsp_read_data(rtsp_session, header, 6);
572   if (n<6) return 0;
573   ts=BE_32(header);
574
575 #if 0
576   lprintf("ts: %u size: %u, flags: 0x%02x, unknown values: %u 0x%02x 0x%02x\n",
577           ts, size, flags1, unknown1, header[4], header[5]);
578 #endif
579
580   size+=2;
581   ph->object_version=0;
582   ph->length=size;
583   ph->stream_number=(flags1>>1)&1;
584   ph->timestamp=ts;
585   ph->reserved=0;
586   ph->flags=0;      /* TODO: determine keyframe flag and insert here? */
587   return size;
588 }
589
590 int real_get_rdt_chunk(rtsp_client_t *rtsp_session, rmff_pheader_t *ph,
591                        unsigned char **buffer) {
592
593   int n;
594   rmff_dump_pheader(ph, (char*)*buffer);
595   n=rtsp_read_data(rtsp_session, (uint8_t*)(*buffer + 12), ph->length - 12);
596   return (n <= 0) ? 0 : n+12;
597 }
598
599 //! maximum size of the rtsp description, must be < INT_MAX
600 #define MAX_DESC_BUF (20 * 1024 * 1024)
601 rmff_header_t  *real_setup_and_get_header(rtsp_client_t *rtsp_session, int bandwidth) {
602
603   char *description=NULL;
604   char *session_id=NULL;
605   rmff_header_t *h=NULL;
606   char *challenge1 = NULL;
607   char challenge2[64];
608   char checksum[34];
609   char *subscribe=NULL;
610   char *buf = malloc(256);
611   if( !buf )
612     return NULL;
613   char *mrl=rtsp_get_mrl(rtsp_session);
614   unsigned int size;
615   int status;
616
617   /* get challenge */
618   challenge1=strdup(rtsp_search_answers(rtsp_session,"RealChallenge1"));
619   lprintf("Challenge1: %s\n", challenge1);
620
621   /* request stream description */
622   rtsp_schedule_field(rtsp_session, "Accept: application/sdp");
623   sprintf(buf, "Bandwidth: %u", bandwidth);
624   rtsp_schedule_field(rtsp_session, buf);
625   rtsp_schedule_field(rtsp_session, "GUID: 00000000-0000-0000-0000-000000000000");
626   rtsp_schedule_field(rtsp_session, "RegionData: 0");
627   rtsp_schedule_field(rtsp_session, "ClientID: Linux_2.4_6.0.9.1235_play32_RN01_EN_586");
628   rtsp_schedule_field(rtsp_session, "SupportsMaximumASMBandwidth: 1");
629   rtsp_schedule_field(rtsp_session, "Language: en-US");
630   rtsp_schedule_field(rtsp_session, "Require: com.real.retain-entity-for-setup");
631
632   status=rtsp_request_describe(rtsp_session,NULL);
633   if ( status<200 || status>299 ) {
634     char *alert=rtsp_search_answers(rtsp_session,"Alert");
635     if (alert) {
636         lprintf("real: got message from server:\n%s\n", alert);
637     }
638     rtsp_send_ok( rtsp_session );
639     free( challenge1 );
640     free( alert );
641     free( buf );
642     return NULL;
643   }
644
645   /* receive description */
646   size=0;
647   if (!rtsp_search_answers(rtsp_session,"Content-length"))
648     lprintf("real: got no Content-length!\n");
649   else
650     size=atoi(rtsp_search_answers(rtsp_session,"Content-length"));
651
652   if (size > MAX_DESC_BUF) {
653     printf("real: Content-length for description too big (> %uMB)!\n",
654         MAX_DESC_BUF/(1024*1024) );
655     goto error;
656   }
657
658   if (!rtsp_search_answers(rtsp_session,"ETag"))
659     lprintf("real: got no ETag!\n");
660   else
661     session_id=strdup(rtsp_search_answers(rtsp_session,"ETag"));
662
663   lprintf("Stream description size: %i\n", size);
664
665   description = malloc(size+1);
666   if( !description )
667     goto error;
668   if( rtsp_read_data(rtsp_session, (uint8_t*)description, size) <= 0)
669     goto error;
670   description[size]=0;
671   //fprintf(stderr, "%s", description);
672
673   /* parse sdp (sdpplin) and create a header and a subscribe string */
674   subscribe = malloc(256);
675   if( !subscribe )
676     goto error;
677
678   strcpy(subscribe, "Subscribe: ");
679   h=real_parse_sdp(description, &subscribe, bandwidth);
680   if (!h)
681     goto error;
682
683   rmff_fix_header(h);
684
685 #if 0
686   fprintf("Title: %s\nCopyright: %s\nAuthor: %s\nStreams: %i\n",
687       h->cont->title, h->cont->copyright, h->cont->author, h->prop->num_streams);
688 #endif
689
690   /* setup our streams */
691   real_calc_response_and_checksum (challenge2, checksum, challenge1);
692   buf = realloc(buf, strlen(challenge2) + strlen(checksum) + 32);
693   sprintf(buf, "RealChallenge2: %s, sd=%s", challenge2, checksum);
694   rtsp_schedule_field(rtsp_session, buf);
695   buf = realloc(buf, strlen(session_id) + 32);
696   sprintf(buf, "If-Match: %s", session_id);
697   rtsp_schedule_field(rtsp_session, buf);
698   rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
699   buf = realloc(buf, strlen(mrl) + 32);
700   sprintf(buf, "%s/streamid=0", mrl);
701   rtsp_request_setup(rtsp_session,buf);
702
703   if (h->prop->num_streams > 1) {
704     rtsp_schedule_field(rtsp_session, "Transport: x-pn-tng/tcp;mode=play,rtp/avp/tcp;unicast;mode=play");
705     buf = realloc(buf, strlen(session_id) + 32);
706     sprintf(buf, "If-Match: %s", session_id);
707     rtsp_schedule_field(rtsp_session, buf);
708     buf = realloc(buf, strlen(mrl) + 32);
709     sprintf(buf, "%s/streamid=1", mrl);
710     rtsp_request_setup(rtsp_session,buf);
711   }
712   /* set stream parameter (bandwidth) with our subscribe string */
713   rtsp_schedule_field(rtsp_session, subscribe);
714   rtsp_request_setparameter(rtsp_session,NULL);
715
716   /* and finally send a play request */
717   rtsp_schedule_field(rtsp_session, "Range: npt=0-");
718   rtsp_request_play(rtsp_session,NULL);
719
720   free( challenge1 );
721   free( session_id );
722   free( description );
723   free( subscribe );
724   free( buf );
725   return h;
726
727 error:
728   rmff_free_header( h );
729   free( challenge1 );
730   free( session_id );
731   free( description );
732   free( subscribe );
733   free( buf );
734   return NULL;
735 }