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