Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / IETF RTP/RTSP/SDP sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include <gpac/internal/ietf_dev.h>
27 : #include <gpac/base_coding.h>
28 :
29 :
30 : #ifndef GPAC_DISABLE_STREAMING
31 :
32 : /*default packet size to use when storing incomplete packets*/
33 : #define RTSP_PCK_SIZE 1000
34 :
35 5 : GF_Err RTSP_UnpackURL(char *sURL, char *Server, u16 *Port, char *Service, Bool *useTCP)
36 : {
37 : char schema[10], *test, text[1024], *retest;
38 : u32 i, len;
39 : Bool is_ipv6;
40 5 : if (!sURL) return GF_BAD_PARAM;
41 :
42 : strcpy(Server, "");
43 : strcpy(Service, "");
44 5 : *Port = 0;
45 5 : *useTCP = GF_FALSE;
46 :
47 5 : if (!strchr(sURL, ':')) return GF_BAD_PARAM;
48 :
49 : //extract the schema
50 : i = 0;
51 25 : while (i<=strlen(sURL)) {
52 25 : if (sURL[i] == ':') goto found;
53 20 : schema[i] = sURL[i];
54 20 : i += 1;
55 : }
56 : return GF_BAD_PARAM;
57 :
58 5 : found:
59 5 : schema[i] = 0;
60 5 : if (stricmp(schema, "rtsp") && stricmp(schema, "rtspu") && stricmp(schema, "satip")) return GF_URL_ERROR;
61 : //check for user/pass - not allowed
62 : /*
63 : test = strstr(sURL, "@");
64 : if (test) return GF_NOT_SUPPORTED;
65 : */
66 5 : test = strstr(sURL, "://");
67 5 : if (!test) return GF_URL_ERROR;
68 5 : test += 3;
69 : //check for service
70 5 : retest = strstr(test, "/");
71 5 : if (!retest) return GF_URL_ERROR;
72 :
73 5 : if (!stricmp(schema, "rtsp") || !stricmp(schema, "satip"))
74 5 : *useTCP = GF_TRUE;
75 :
76 : //check for port
77 5 : retest = strrchr(test, ':');
78 : /*IPV6 address*/
79 5 : if (retest && strchr(retest, ']')) retest = NULL;
80 :
81 5 : if (retest && strstr(retest, "/")) {
82 5 : retest += 1;
83 : i=0;
84 30 : while (i<strlen(retest)) {
85 25 : if (retest[i] == '/') break;
86 20 : text[i] = retest[i];
87 20 : i += 1;
88 : }
89 5 : text[i] = 0;
90 5 : *Port = atoi(text);
91 : }
92 : //get the server name
93 : is_ipv6 = GF_FALSE;
94 5 : len = (u32) strlen(test);
95 : i=0;
96 55 : while (i<len) {
97 50 : if (test[i]=='[') is_ipv6 = GF_TRUE;
98 50 : else if (test[i]==']') is_ipv6 = GF_FALSE;
99 50 : if ( (test[i] == '/') || (!is_ipv6 && (test[i] == ':')) ) break;
100 45 : text[i] = test[i];
101 45 : i += 1;
102 : }
103 5 : text[i] = 0;
104 : strcpy(Server, text);
105 :
106 25 : while (test[i] != '/') i += 1;
107 5 : strcpy(Service, test+i+1);
108 :
109 5 : return GF_OK;
110 : }
111 :
112 :
113 : //create a new GF_RTSPSession from URL - DO NOT USE WITH SDP
114 : GF_EXPORT
115 5 : GF_RTSPSession *gf_rtsp_session_new(char *sURL, u16 DefaultPort)
116 : {
117 : GF_RTSPSession *sess;
118 : char server[1024], service[1024];
119 : GF_Err e;
120 : u16 Port;
121 : Bool UseTCP;
122 :
123 5 : if (!sURL) return NULL;
124 :
125 5 : e = RTSP_UnpackURL(sURL, server, &Port, service, &UseTCP);
126 5 : if (e) return NULL;
127 :
128 5 : GF_SAFEALLOC(sess, GF_RTSPSession);
129 5 : if (!sess) return NULL;
130 5 : sess->ConnectionType = UseTCP ? GF_SOCK_TYPE_TCP : GF_SOCK_TYPE_UDP;
131 5 : if (Port) sess->Port = Port;
132 0 : else if (DefaultPort) sess->Port = DefaultPort;
133 0 : else sess->Port = 554;
134 :
135 : //HTTP tunnel
136 5 : if (sess->Port == 80) {
137 0 : sess->ConnectionType = GF_SOCK_TYPE_TCP;
138 0 : sess->HasTunnel = GF_TRUE;
139 : }
140 :
141 5 : gf_rtsp_set_buffer_size(sess, RTSP_PCK_SIZE);
142 :
143 5 : sess->Server = gf_strdup(server);
144 5 : sess->Service = gf_strdup(service);
145 5 : sess->TCPChannels = gf_list_new();
146 5 : gf_rtsp_session_reset(sess, GF_FALSE);
147 5 : return sess;
148 : }
149 :
150 :
151 : GF_EXPORT
152 1 : void gf_rtsp_reset_aggregation(GF_RTSPSession *sess)
153 : {
154 1 : if (!sess) return;
155 :
156 0 : if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL) {
157 0 : strcpy(sess->RTSPLastRequest, "RESET");
158 : //skip all we haven't received
159 0 : sess->CSeq += sess->NbPending;
160 0 : sess->NbPending = 0;
161 : }
162 0 : sess->RTSP_State = GF_RTSP_STATE_INIT;
163 : }
164 :
165 64 : void RemoveTCPChannels(GF_RTSPSession *sess)
166 : {
167 129 : while (gf_list_count(sess->TCPChannels)) {
168 1 : GF_TCPChan *ch = (GF_TCPChan*)gf_list_get(sess->TCPChannels, 0);
169 1 : gf_free(ch);
170 1 : gf_list_rem(sess->TCPChannels, 0);
171 : }
172 64 : }
173 :
174 :
175 : GF_EXPORT
176 64 : void gf_rtsp_session_reset(GF_RTSPSession *sess, Bool ResetConnection)
177 : {
178 64 : sess->last_session_id = NULL;
179 64 : sess->NeedConnection = 1;
180 :
181 64 : if (ResetConnection) {
182 5 : if (sess->connection) gf_sk_del(sess->connection);
183 5 : sess->connection = NULL;
184 5 : if (sess->http) {
185 0 : gf_sk_del(sess->http);
186 0 : sess->http = NULL;
187 : }
188 : }
189 :
190 64 : sess->RTSP_State = GF_RTSP_STATE_INIT;
191 : // sess->CSeq = sess->NbPending = 0;
192 64 : sess->InterID = (u8) -1;
193 64 : sess->pck_start = sess->payloadSize = 0;
194 64 : sess->CurrentPos = sess->CurrentSize = 0;
195 64 : strcpy(sess->RTSPLastRequest, "");
196 64 : RemoveTCPChannels(sess);
197 64 : }
198 :
199 : GF_EXPORT
200 56 : void gf_rtsp_session_del(GF_RTSPSession *sess)
201 : {
202 56 : if (!sess) return;
203 :
204 30 : gf_rtsp_session_reset(sess, GF_FALSE);
205 :
206 30 : if (sess->connection) gf_sk_del(sess->connection);
207 30 : if (sess->http) gf_sk_del(sess->http);
208 30 : if (sess->Server) gf_free(sess->Server);
209 30 : if (sess->Service) gf_free(sess->Service);
210 30 : gf_list_del(sess->TCPChannels);
211 30 : if (sess->rtsp_pck_buf) gf_free(sess->rtsp_pck_buf);
212 30 : gf_free(sess->tcp_buffer);
213 :
214 30 : gf_free(sess);
215 : }
216 :
217 : GF_EXPORT
218 28 : u32 gf_rtsp_get_session_state(GF_RTSPSession *sess)
219 : {
220 : u32 state;
221 28 : if (!sess) return GF_RTSP_STATE_INVALIDATED;
222 :
223 28 : state = sess->RTSP_State;
224 28 : return state;
225 : }
226 :
227 : #if 0 //unused
228 : char *gf_rtsp_get_last_request(GF_RTSPSession *sess)
229 : {
230 : if (!sess) return NULL;
231 : return sess->RTSPLastRequest;
232 : }
233 : #endif
234 :
235 :
236 : //check whether the url contains server and service name
237 : //no thread protection as this is const throughout the session
238 : GF_EXPORT
239 6 : Bool gf_rtsp_is_my_session(GF_RTSPSession *sess, char *url)
240 : {
241 6 : if (!sess) return GF_FALSE;
242 6 : if (!strstr(url, sess->Server)) return GF_FALSE;
243 : //same url or sub-url
244 6 : if (strstr(url, sess->Service)) return GF_TRUE;
245 0 : return GF_FALSE;
246 : }
247 :
248 : #if 0 //unused
249 : const char *gf_rtsp_get_last_session_id(GF_RTSPSession *sess)
250 : {
251 : if (!sess) return NULL;
252 : return sess->last_session_id;
253 : }
254 : #endif
255 :
256 : GF_EXPORT
257 6 : char *gf_rtsp_get_server_name(GF_RTSPSession *sess)
258 : {
259 6 : if (!sess) return NULL;
260 6 : return sess->Server;
261 : }
262 :
263 : GF_EXPORT
264 3 : u16 gf_rtsp_get_session_port(GF_RTSPSession *sess)
265 : {
266 3 : return (sess ? sess->Port : 0);
267 : }
268 :
269 2063 : GF_Err gf_rtsp_check_connection(GF_RTSPSession *sess)
270 : {
271 : GF_Err e;
272 : //active, return
273 2063 : if (!sess->NeedConnection) return GF_OK;
274 :
275 : //socket is destroyed, recreate
276 25 : if (!sess->connection) {
277 25 : sess->connection = gf_sk_new(sess->ConnectionType);
278 25 : if (!sess->connection) return GF_OUT_OF_MEM;
279 : }
280 : //the session is down, reconnect
281 25 : e = gf_sk_connect(sess->connection, sess->Server, sess->Port, NULL);
282 25 : if (e) return e;
283 :
284 25 : if (sess->SockBufferSize) gf_sk_set_buffer_size(sess->connection, GF_FALSE, sess->SockBufferSize);
285 :
286 : #ifdef GPAC_ENABLE_COVERAGE
287 25 : if (gf_sys_is_cov_mode())
288 25 : gf_rtsp_http_tunnel_start(NULL, NULL);
289 : #endif
290 :
291 25 : if (!sess->http && sess->HasTunnel) {
292 0 : const char *ua = gf_opts_get_key("core", "user-agent");
293 0 : if (!ua) ua = "GPAC " GPAC_VERSION;
294 0 : e = gf_rtsp_http_tunnel_start(sess, (char *)ua);
295 0 : if (e) return e;
296 : }
297 25 : sess->NeedConnection = 0;
298 25 : return GF_OK;
299 : }
300 :
301 :
302 56 : GF_Err gf_rtsp_send_data(GF_RTSPSession *sess, u8 *buffer, u32 Size)
303 : {
304 : GF_Err e;
305 : u32 Size64;
306 :
307 56 : e = gf_rtsp_check_connection(sess);
308 56 : if (e) return e;
309 :
310 : //RTSP requests on HTTP are base 64 encoded
311 56 : if (sess->HasTunnel) {
312 : char buf64[3000];
313 0 : Size64 = gf_base64_encode(buffer, Size, buf64, 3000);
314 0 : buf64[Size64] = 0;
315 : //send on http connection
316 0 : return gf_sk_send_wait(sess->http, buf64, Size64, 30);
317 : } else {
318 56 : return gf_sk_send(sess->connection, buffer, Size);
319 : }
320 : }
321 :
322 :
323 :
324 15 : static GF_TCPChan *GetTCPChannel(GF_RTSPSession *sess, u8 rtpID, u8 rtcpID, Bool RemoveIt)
325 : {
326 : GF_TCPChan *ptr;
327 15 : u32 i, count = gf_list_count(sess->TCPChannels);
328 15 : for (i=0; i<count; i++) {
329 14 : ptr = (GF_TCPChan *)gf_list_get(sess->TCPChannels, i);
330 14 : if (ptr->rtpID == rtpID) goto exit;
331 1 : if (ptr->rtcpID == rtcpID) goto exit;
332 : }
333 : return NULL;
334 14 : exit:
335 14 : if (RemoveIt) gf_list_rem(sess->TCPChannels, i);
336 : return ptr;
337 : }
338 :
339 :
340 31 : GF_Err gf_rtsp_set_deinterleave(GF_RTSPSession *sess)
341 : {
342 : GF_TCPChan *ch;
343 : Bool IsRTCP;
344 : u8 InterID;
345 : u16 paySize;
346 : u32 res, Size;
347 : char *buffer;
348 :
349 31 : if (!sess) return GF_SERVICE_ERROR;
350 :
351 31 : Size = sess->CurrentSize - sess->CurrentPos;
352 31 : buffer = sess->tcp_buffer + sess->CurrentPos;
353 :
354 31 : if (!Size) return GF_IP_NETWORK_EMPTY;
355 :
356 : //we do not work with just a header -> force a refill
357 17 : if (Size <= 4) return gf_rtsp_refill_buffer(sess);
358 :
359 : //break if we get RTSP response on the wire
360 16 : if (!strncmp(buffer, "RTSP", 4))
361 : return GF_IP_NETWORK_EMPTY;
362 :
363 : //new packet
364 14 : if (!sess->pck_start && (buffer[0] == '$')) {
365 14 : InterID = buffer[1];
366 14 : paySize = ((buffer[2] << 8) & 0xFF00) | (buffer[3] & 0xFF);
367 : /*this may be NULL (data fetched after a teardown) - resync and return*/
368 14 : ch = GetTCPChannel(sess, InterID, InterID, GF_FALSE);
369 :
370 : /*then check wether this is a full packet or a split*/
371 14 : if (paySize <= Size-4) {
372 14 : if (ch) {
373 14 : IsRTCP = (ch->rtcpID == InterID) ? GF_TRUE : GF_FALSE;
374 14 : sess->RTSP_SignalData(sess, ch->ch_ptr, buffer+4, paySize, IsRTCP);
375 : }
376 14 : sess->CurrentPos += paySize+4;
377 : assert(sess->CurrentPos <= sess->CurrentSize);
378 : } else {
379 : /*missed end of pck ?*/
380 0 : if (sess->payloadSize) {
381 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed end of packet (%d bytes) in stream %d\n", sess->payloadSize - sess->pck_start, sess->InterID));
382 0 : ch = GetTCPChannel(sess, sess->InterID, sess->InterID, GF_FALSE);
383 0 : if (ch) {
384 0 : IsRTCP = (ch->rtcpID == sess->InterID) ? GF_TRUE : GF_FALSE;
385 0 : sess->RTSP_SignalData(sess, ch->ch_ptr, sess->rtsp_pck_buf, sess->payloadSize, IsRTCP);
386 : }
387 : }
388 0 : sess->InterID = InterID;
389 0 : sess->payloadSize = paySize;
390 0 : sess->pck_start = Size-4;
391 0 : if (sess->rtsp_pck_size < paySize) {
392 0 : sess->rtsp_pck_buf = (char *)gf_realloc(sess->rtsp_pck_buf, sizeof(char)*paySize);
393 0 : sess->rtsp_pck_size = paySize;
394 : }
395 0 : memcpy(sess->rtsp_pck_buf, buffer+4, Size-4);
396 0 : sess->CurrentPos += Size;
397 : assert(sess->CurrentPos <= sess->CurrentSize);
398 : }
399 : }
400 : /*end of packet*/
401 0 : else if (sess->payloadSize - sess->pck_start <= Size) {
402 : // GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of packet (%d bytes) in stream %d\n", Size, sess->InterID));
403 :
404 : res = sess->payloadSize - sess->pck_start;
405 0 : memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, res);
406 : //flush - same as above, don't complain if channel not found
407 0 : ch = GetTCPChannel(sess, sess->InterID, sess->InterID, GF_FALSE);
408 0 : if (ch) {
409 0 : IsRTCP = (ch->rtcpID == sess->InterID) ? GF_TRUE : GF_FALSE;
410 0 : sess->RTSP_SignalData(sess, ch->ch_ptr, sess->rtsp_pck_buf, sess->payloadSize, IsRTCP);
411 : }
412 0 : sess->payloadSize = 0;
413 0 : sess->pck_start = 0;
414 0 : sess->InterID = (u8) -1;
415 0 : sess->CurrentPos += res;
416 : assert(sess->CurrentPos <= sess->CurrentSize);
417 : }
418 : /*middle of packet*/
419 : else {
420 : // GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of RTP packet in stream %d\n", sess->InterID));
421 0 : memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, Size);
422 0 : sess->pck_start += Size;
423 0 : sess->CurrentPos += Size;
424 : assert(sess->CurrentPos <= sess->CurrentSize);
425 : }
426 : return GF_OK;
427 : }
428 :
429 :
430 : GF_EXPORT
431 437 : GF_Err gf_rtsp_session_read(GF_RTSPSession *sess)
432 : {
433 : GF_Err e;
434 437 : if (!sess) return GF_BAD_PARAM;
435 :
436 437 : e = gf_rtsp_fill_buffer(sess);
437 437 : if (!e) {
438 : //only read if not RTSP
439 : while (1) {
440 31 : e = gf_rtsp_set_deinterleave(sess);
441 31 : if (e) break;
442 : }
443 : }
444 : return e;
445 : }
446 :
447 :
448 : GF_EXPORT
449 1 : u32 gf_rtsp_unregister_interleave(GF_RTSPSession *sess, u8 LowInterID)
450 : {
451 : u32 res;
452 : GF_TCPChan *ptr;
453 1 : if (!sess) return 0;
454 :
455 0 : ptr = GetTCPChannel(sess, LowInterID, LowInterID, GF_TRUE);
456 0 : if (ptr) gf_free(ptr);
457 0 : res = gf_list_count(sess->TCPChannels);
458 0 : if (!res) sess->interleaved = GF_FALSE;
459 : return res;
460 : }
461 :
462 : GF_EXPORT
463 1 : GF_Err gf_rtsp_register_interleave(GF_RTSPSession *sess, void *the_ch, u8 LowInterID, u8 HighInterID)
464 : {
465 : GF_TCPChan *ptr;
466 :
467 1 : if (!sess) return GF_BAD_PARAM;
468 :
469 : //do NOT register twice
470 1 : ptr = GetTCPChannel(sess, LowInterID, HighInterID, GF_FALSE);
471 1 : if (!ptr) {
472 1 : ptr = (GF_TCPChan *)gf_malloc(sizeof(GF_TCPChan));
473 1 : ptr->ch_ptr = the_ch;
474 1 : ptr->rtpID = LowInterID;
475 1 : ptr->rtcpID = HighInterID;
476 1 : gf_list_add(sess->TCPChannels, ptr);
477 : }
478 1 : sess->interleaved=GF_TRUE;
479 1 : return GF_OK;
480 : }
481 :
482 :
483 : GF_EXPORT
484 1 : GF_Err gf_rtsp_set_interleave_callback(GF_RTSPSession *sess, gf_rtsp_interleave_callback SignalData)
485 : {
486 1 : if (!sess) return GF_BAD_PARAM;
487 :
488 : //only if existing
489 1 : if (SignalData) sess->RTSP_SignalData = SignalData;
490 :
491 1 : if (!sess->rtsp_pck_buf || (sess->rtsp_pck_size != RTSP_PCK_SIZE) ) {
492 1 : if (!sess->rtsp_pck_buf)
493 1 : sess->pck_start = 0;
494 1 : sess->rtsp_pck_size = RTSP_PCK_SIZE;
495 1 : sess->rtsp_pck_buf = (char *)gf_realloc(sess->rtsp_pck_buf, sizeof(char)*sess->rtsp_pck_size);
496 : }
497 : return GF_OK;
498 : }
499 :
500 : GF_EXPORT
501 61 : GF_Err gf_rtsp_set_buffer_size(GF_RTSPSession *sess, u32 BufferSize)
502 : {
503 61 : if (!sess) return GF_BAD_PARAM;
504 61 : if (sess->SockBufferSize >= BufferSize) return GF_OK;
505 60 : sess->SockBufferSize = BufferSize;
506 60 : sess->tcp_buffer = gf_realloc(sess->tcp_buffer, BufferSize);
507 60 : return GF_OK;
508 : }
509 :
510 :
511 : static Bool HTTP_RandInit = GF_TRUE;
512 :
513 : #define HTTP_WAIT_SEC 30
514 :
515 : #define HTTP_RSP_OK "HTTP/1.0 200 OK"
516 :
517 :
518 : //http tunnelling start.
519 : GF_EXPORT
520 25 : GF_Err gf_rtsp_http_tunnel_start(GF_RTSPSession *sess, char *UserAgent)
521 : {
522 : GF_Err e;
523 : u32 size;
524 : s32 pos;
525 : u32 i, num, temp;
526 : char buffer[GF_RTSP_DEFAULT_BUFFER];
527 :
528 25 : if (!sess || !UserAgent) return GF_BAD_PARAM;
529 :
530 : //generate http cookie
531 0 : if (HTTP_RandInit) {
532 0 : gf_rand_init(GF_FALSE);
533 0 : HTTP_RandInit = GF_FALSE;
534 : }
535 0 : if (!sess->CookieRadLen) {
536 0 : strcpy(sess->HTTP_Cookie, "GPACROH");
537 0 : sess->CookieRadLen = 8;
538 : }
539 0 : num = gf_rand();
540 0 : for (i=0; i < 8; i++) {
541 0 : temp = (num >> (i * 4)) & 0x0f;
542 0 : sess->HTTP_Cookie[sess->CookieRadLen + i] = (u8) temp + sess->HTTP_Cookie[0];
543 : }
544 0 : sess->HTTP_Cookie[sess->CookieRadLen + i] = 0;
545 :
546 : // 1. send "GET /sample.mov HTTP/1.0\r\n ..."
547 : memset(buffer, 0, GF_RTSP_DEFAULT_BUFFER);
548 : pos = 0;
549 0 : pos += sprintf(buffer + pos, "GET /%s HTTP/1.0\r\n", sess->Service);
550 0 : pos += sprintf(buffer + pos, "User-Agent: %s\r\n", UserAgent);
551 0 : pos += sprintf(buffer + pos, "x-sessioncookie: %s\r\n", sess->HTTP_Cookie);
552 0 : pos += sprintf(buffer + pos, "Accept: application/x-rtsp-tunnelled\r\n" );
553 0 : pos += sprintf(buffer + pos, "Pragma: no-cache\r\n" );
554 0 : /*pos += */sprintf(buffer + pos, "Cache-Control: no-cache\r\n\r\n" );
555 :
556 : // send it!
557 0 : e = gf_sk_send_wait(sess->connection, buffer, (u32) strlen(buffer), HTTP_WAIT_SEC);
558 0 : if (e) return e;
559 :
560 : // 2. wait for "HTTP/1.0 200 OK"
561 0 : e = gf_sk_receive_wait(sess->connection, buffer, GF_RTSP_DEFAULT_BUFFER, &size, HTTP_WAIT_SEC);
562 0 : if (e) return e;
563 :
564 : //get HTTP/1.0 200 OK
565 0 : if (strncmp(buffer, HTTP_RSP_OK, strlen(HTTP_RSP_OK)))
566 : return GF_REMOTE_SERVICE_ERROR;
567 :
568 : // 3. send "POST /sample.mov HTTP/1.0\r\n ..."
569 0 : sess->http = gf_sk_new(GF_SOCK_TYPE_TCP);
570 0 : if (!sess->http ) return GF_IP_NETWORK_FAILURE;
571 :
572 0 : if (gf_sk_connect(sess->http, sess->Server, sess->Port, NULL)) return GF_IP_CONNECTION_FAILURE;
573 :
574 : memset(buffer, 0, GF_RTSP_DEFAULT_BUFFER);
575 : pos = 0;
576 0 : pos += sprintf(buffer + pos, "POST /%s HTTP/1.0\r\n", sess->Service);
577 0 : pos += sprintf(buffer + pos, "User-Agent: %s\r\n", UserAgent);
578 0 : pos += sprintf(buffer + pos, "x-sessioncookie: %s\r\n", sess->HTTP_Cookie);
579 0 : pos += sprintf(buffer + pos, "Accept: application/x-rtsp-tunnelled\r\n");
580 0 : pos += sprintf(buffer + pos, "Pragma: no-cache\r\n");
581 0 : pos += sprintf(buffer + pos, "Cache-Control: no-cache\r\n");
582 0 : pos += sprintf(buffer + pos, "Content-Length: 32767\r\n");
583 0 : /*pos += */sprintf(buffer + pos, "Expires: Sun. 9 Jan 1972 00:00:00 GMT\r\n\r\n");
584 :
585 : // send it!
586 0 : e = gf_sk_send_wait(sess->http, buffer, (u32) strlen(buffer), HTTP_WAIT_SEC);
587 :
588 0 : return e;
589 : }
590 :
591 :
592 : /*server-side RTSP sockets*/
593 :
594 : static u32 SessionID_RandInit = 0;
595 :
596 :
597 : GF_EXPORT
598 2824 : GF_RTSPSession *gf_rtsp_session_new_server(GF_Socket *rtsp_listener)
599 : {
600 : GF_RTSPSession *sess;
601 : GF_Socket *new_conn;
602 : GF_Err e;
603 : u32 fam;
604 : u16 port;
605 : char name[GF_MAX_IP_NAME_LEN];
606 :
607 2824 : if (!rtsp_listener) return NULL;
608 :
609 :
610 2824 : e = gf_sk_accept(rtsp_listener, &new_conn);
611 2824 : if (!new_conn || e) return NULL;
612 :
613 25 : e = gf_sk_get_local_info(new_conn, &port, &fam);
614 25 : if (e) {
615 0 : gf_sk_del(new_conn);
616 0 : return NULL;
617 : }
618 25 : e = gf_sk_set_block_mode(new_conn, GF_TRUE);
619 25 : if (e) {
620 0 : gf_sk_del(new_conn);
621 0 : return NULL;
622 : }
623 25 : e = gf_sk_server_mode(new_conn, GF_TRUE);
624 25 : if (e) {
625 0 : gf_sk_del(new_conn);
626 0 : return NULL;
627 : }
628 :
629 : //OK create a new session
630 25 : GF_SAFEALLOC(sess, GF_RTSPSession);
631 25 : if (!sess) return NULL;
632 :
633 25 : sess->connection = new_conn;
634 25 : sess->Port = port;
635 25 : sess->ConnectionType = fam;
636 25 : gf_sk_get_host_name(name);
637 25 : sess->Server = gf_strdup(name);
638 25 : gf_rtsp_set_buffer_size(sess, 4096);
639 25 : sess->TCPChannels = gf_list_new();
640 25 : return sess;
641 : }
642 :
643 :
644 : #if 0 //unused
645 : GF_Err gf_rtsp_load_service_name(GF_RTSPSession *sess, char *URL)
646 : {
647 : char server[1024], service[1024];
648 : GF_Err e;
649 : u16 Port;
650 : Bool UseTCP;
651 : u32 type;
652 :
653 : if (!sess || !URL) return GF_BAD_PARAM;
654 : e = RTSP_UnpackURL(URL, server, &Port, service, &UseTCP);
655 : if (e) return e;
656 :
657 : type = UseTCP ? GF_SOCK_TYPE_TCP : GF_SOCK_TYPE_UDP;
658 : //check the network type matches, otherwise deny client
659 : if (sess->ConnectionType != type) return GF_URL_ERROR;
660 : if (sess->Port != Port) return GF_URL_ERROR;
661 :
662 : //ok
663 : sess->Server = gf_strdup(server);
664 : sess->Service = gf_strdup(service);
665 : return GF_OK;
666 : }
667 : #endif
668 :
669 : GF_EXPORT
670 5 : char *gf_rtsp_generate_session_id(GF_RTSPSession *sess)
671 : {
672 : u32 one;
673 : u64 res;
674 : char buffer[30];
675 :
676 5 : if (!sess) return NULL;
677 :
678 5 : if (!SessionID_RandInit) {
679 5 : SessionID_RandInit = 1;
680 5 : gf_rand_init(GF_FALSE);
681 : }
682 5 : one = gf_rand();
683 5 : res = one;
684 5 : res <<= 32;
685 5 : res+= (PTR_TO_U_CAST sess) + sess->CurrentPos + sess->CurrentSize;
686 : sprintf(buffer, LLU, res);
687 5 : return gf_strdup(buffer);
688 : }
689 :
690 :
691 : GF_EXPORT
692 5 : GF_Err gf_rtsp_get_session_ip(GF_RTSPSession *sess, char buffer[GF_MAX_IP_NAME_LEN])
693 : {
694 5 : if (!sess || !sess->connection) return GF_BAD_PARAM;
695 5 : gf_sk_get_local_ip(sess->connection, buffer);
696 5 : return GF_OK;
697 : }
698 :
699 :
700 : #if 0 //unused
701 : u8 gf_rtsp_get_next_interleave_id(GF_RTSPSession *sess)
702 : {
703 : u32 i;
704 : u8 id;
705 : GF_TCPChan *ch;
706 : id = 0;
707 : i=0;
708 : while ((ch = (GF_TCPChan *)gf_list_enum(sess->TCPChannels, &i))) {
709 : if (ch->rtpID >= id) id = ch->rtpID + 1;
710 : if (ch->rtcpID >= id) id = ch->rtcpID + 1;
711 : }
712 : return id;
713 : }
714 : #endif
715 :
716 : GF_EXPORT
717 25 : GF_Err gf_rtsp_get_remote_address(GF_RTSPSession *sess, char *buf)
718 : {
719 25 : if (!sess || !sess->connection) return GF_BAD_PARAM;
720 25 : return gf_sk_get_remote_address(sess->connection, buf);
721 : }
722 :
723 : GF_EXPORT
724 14 : GF_Err gf_rtsp_session_write_interleaved(GF_RTSPSession *sess, u32 idx, u8 *pck, u32 pck_size)
725 : {
726 : GF_Err e;
727 : char streamID[4];
728 14 : if (!sess || !sess->connection) return GF_BAD_PARAM;
729 :
730 14 : streamID[0] = '$';
731 14 : streamID[1] = (u8) idx;
732 14 : streamID[2] = (pck_size>>8) & 0xFF;
733 14 : streamID[3] = pck_size & 0xFF;
734 :
735 14 : e = gf_sk_send_wait(sess->connection, streamID, 4, 20);
736 14 : e |= gf_sk_send_wait(sess->connection, pck, pck_size, 20);
737 14 : return e;
738 : }
739 :
740 : #endif /*GPAC_DISABLE_STREAMING*/
|