Coverage Report

Created: 2026-01-23 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gpac/src/ietf/rtsp_session.c
Line
Count
Source
1
/*
2
 *      GPAC - Multimedia Framework C SDK
3
 *
4
 *      Authors: Jean Le Feuvre
5
 *      Copyright (c) Telecom ParisTech 2000-2023
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
static GF_Err gf_rtsp_write_sock(GF_RTSPSession *sess, u8 *data, u32 len);
33
static GF_Err gf_rstp_flush_buffer(GF_RTSPSession *sess);
34
static GF_Err gf_rtsp_http_tunnel_setup(GF_RTSPSession *sess);
35
36
#ifdef GPAC_HAS_SSL
37
#include <openssl/ssl.h>
38
#include <openssl/err.h>
39
#include <openssl/x509.h>
40
#include <openssl/x509v3.h>
41
#include <openssl/rand.h>
42
43
void *gf_ssl_new(void *ssl_server_ctx, GF_Socket *client_sock, GF_Err *e);
44
void gf_ssl_del(void *ssl);
45
Bool gf_ssl_check_cert(SSL *ssl, const char *server_name);
46
47
#endif
48
49
50
/*default packet size to use when storing incomplete packets*/
51
0
#define RTSP_PCK_SIZE     1000
52
53
GF_Err RTSP_UnpackURL(char *sURL, char Server[1024], u16 *Port, char Service[1024], Bool *useTCP, char User[1024], char Pass[1024])
54
0
{
55
0
  char schema[10], *test, text[1024], *retest, *sep, *service_start;
56
0
  u32 i, len;
57
0
  Bool is_ipv6;
58
0
  if (!sURL) return GF_BAD_PARAM;
59
60
0
  Server[0] = 0;
61
0
  Service[0] = 0;
62
0
  User[0] = 0;
63
0
  Pass[0] = 0;
64
65
0
  *Port = 0;
66
0
  *useTCP = GF_FALSE;
67
68
0
  if (!strchr(sURL, ':')) return GF_BAD_PARAM;
69
70
0
  sep = strchr(sURL, '?');
71
0
  if (sep) sep[0] = 0;
72
  //extract the schema
73
0
  i = 0;
74
0
  while (i<=strlen(sURL)) {
75
0
    if (i==10) return GF_BAD_PARAM;
76
0
    if (sURL[i] == ':') goto found;
77
0
    schema[i] = sURL[i];
78
0
    i += 1;
79
0
  }
80
0
  if (sep) sep[0] = '?';
81
0
  return GF_BAD_PARAM;
82
83
0
found:
84
0
  schema[i] = 0;
85
0
  if (stricmp(schema, "rtsp") && stricmp(schema, "rtspu") && stricmp(schema, "rtsph")  && stricmp(schema, "rtsps") && stricmp(schema, "satip")) return GF_URL_ERROR;
86
  //check for user/pass - not allowed
87
  /*
88
    test = strstr(sURL, "@");
89
    if (test) return GF_NOT_SUPPORTED;
90
  */
91
0
  test = strstr(sURL, "://");
92
0
  if (!test) {
93
0
    if (sep) sep[0] = '?';
94
0
    return GF_URL_ERROR;
95
0
  }
96
0
  test += 3;
97
  //check for service
98
0
  retest = strstr(test, "/");
99
0
  if (!retest) {
100
0
    if (sep) sep[0] = '?';
101
0
    return GF_URL_ERROR;
102
0
  }
103
0
  if (!stricmp(schema, "rtsp") || !stricmp(schema, "satip") || !stricmp(schema, "rtsph") || !stricmp(schema, "rtsps"))
104
0
    *useTCP = GF_TRUE;
105
106
0
  service_start = retest;
107
  //check for port
108
0
  char *port = strrchr(test, ':');
109
0
  retest = (port<retest) ? port : NULL;
110
  /*IPV6 address*/
111
0
  if (retest && strchr(retest, ']')) retest = NULL;
112
113
0
  if (retest && strstr(retest, "/")) {
114
0
    retest += 1;
115
0
    i=0;
116
0
    while (i<strlen(retest) && i<1023) {
117
0
      if (retest[i] == '/') break;
118
0
      text[i] = retest[i];
119
0
      i += 1;
120
0
    }
121
0
    text[i] = 0;
122
0
    *Port = atoi(text);
123
0
  }
124
125
0
  char *sep_auth = strchr(test, '@');
126
0
  if (sep_auth>service_start) sep_auth=NULL;
127
0
  if (sep_auth) {
128
0
    sep_auth[0] = 0;
129
0
    char *psep = strchr(test, ':');
130
0
    if (psep) psep[0] = 0;
131
0
    strncpy(User, test, 1023);
132
0
    User[1023]=0;
133
0
    if (psep) {
134
0
      strncpy(Pass, psep+1, 1023);
135
0
      Pass[1023]=0;
136
0
      if (psep) psep[0] = ':';
137
0
    }
138
139
0
    sep_auth[0] = '@';
140
0
    test = sep_auth+1;
141
0
  }
142
143
  //get the server name
144
0
  is_ipv6 = GF_FALSE;
145
0
  len = (u32) strlen(test);
146
0
  i=0;
147
0
  while (i<len) {
148
0
    if (test[i]=='[') is_ipv6 = GF_TRUE;
149
0
    else if (test[i]==']') is_ipv6 = GF_FALSE;
150
0
    if ( (test[i] == '/') || (!is_ipv6 && (test[i] == ':')) ) break;
151
0
    if (i>=GF_ARRAY_LENGTH(text)) break;
152
0
    text[i] = test[i];
153
0
    i += 1;
154
0
  }
155
0
  text[MIN(i, GF_ARRAY_LENGTH(text)-1)] = 0;
156
0
  strncpy(Server, text, 1024);
157
0
  Server[1023]=0;
158
0
  if (sep) sep[0] = '?';
159
160
0
  if (service_start) {
161
0
    strncpy(Service, service_start+1, 1023);
162
0
    Service[1023]=0;
163
0
  } else {
164
0
    Service[0]=0;
165
0
  }
166
0
  return GF_OK;
167
0
}
168
169
170
//create a new GF_RTSPSession from URL - DO NOT USE WITH SDP
171
GF_EXPORT
172
GF_RTSPSession *gf_rtsp_session_new(char *sURL, u16 DefaultPort)
173
0
{
174
0
  GF_RTSPSession *sess;
175
0
  char server[1024], service[1024], user[1024], pass[1024];
176
0
  GF_Err e;
177
0
  u16 Port;
178
0
  Bool UseTCP;
179
180
0
  if (!sURL) return NULL;
181
182
0
  e = RTSP_UnpackURL(sURL, server, &Port, service, &UseTCP, user, pass);
183
0
  if (e) return NULL;
184
185
0
  GF_SAFEALLOC(sess, GF_RTSPSession);
186
0
  if (!sess) return NULL;
187
0
  sess->ConnectionType = UseTCP ? GF_SOCK_TYPE_TCP : GF_SOCK_TYPE_UDP;
188
189
0
#ifdef GPAC_HAS_SSL
190
0
  if (!strncmp(sURL, "rtsps://", 8)
191
0
    || (!strncmp(sURL, "rtsph://", 8) && ((Port==443) || (Port == 8443)))
192
0
  ) {
193
0
    sess->use_ssl = GF_TRUE;
194
0
    sess->ConnectionType = GF_SOCK_TYPE_TCP;
195
0
  }
196
0
#endif
197
198
0
  if (Port) sess->Port = Port;
199
0
#ifdef GPAC_HAS_SSL
200
0
  else if (sess->use_ssl) sess->Port = 322;
201
0
#endif
202
0
  else if (DefaultPort) sess->Port = DefaultPort;
203
0
  else sess->Port = 554;
204
205
  //HTTP tunnel
206
0
  if ((sess->Port == 80) || (sess->Port == 8080) || !strnicmp(sURL, "rtsph://", 8)){
207
0
    sess->ConnectionType = GF_SOCK_TYPE_TCP;
208
0
    sess->tunnel_mode = RTSP_HTTP_CLIENT;
209
0
  }
210
211
0
  gf_rtsp_set_buffer_size(sess, RTSP_PCK_SIZE);
212
213
0
  sess->Server = gf_strdup(server);
214
0
  sess->Service = gf_strdup(service);
215
0
  if (user[0])
216
0
    sess->User = gf_strdup(user);
217
0
  if (pass[0])
218
0
  sess->Pass = gf_strdup(pass);
219
0
  sess->TCPChannels = gf_list_new();
220
0
  gf_rtsp_session_reset(sess, GF_FALSE);
221
0
  return sess;
222
0
}
223
224
GF_EXPORT
225
void gf_rtsp_session_set_netcap_id(GF_RTSPSession *sess, const char *netcap_id)
226
0
{
227
0
  if (sess) sess->netcap_id = netcap_id;
228
0
}
229
230
GF_EXPORT
231
void gf_rtsp_reset_aggregation(GF_RTSPSession *sess)
232
0
{
233
0
  if (!sess) return;
234
235
0
  if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL) {
236
0
    strcpy(sess->RTSPLastRequest, "RESET");
237
    //skip all we haven't received
238
0
    sess->CSeq += sess->NbPending;
239
0
    sess->NbPending = 0;
240
0
  }
241
0
  sess->RTSP_State = GF_RTSP_STATE_INIT;
242
0
}
243
244
void RemoveTCPChannels(GF_RTSPSession *sess)
245
0
{
246
0
  while (gf_list_count(sess->TCPChannels)) {
247
0
    GF_TCPChan *ch = (GF_TCPChan*)gf_list_get(sess->TCPChannels, 0);
248
0
    gf_free(ch);
249
0
    gf_list_rem(sess->TCPChannels, 0);
250
0
  }
251
0
}
252
253
254
GF_EXPORT
255
u32 gf_rtsp_session_reset(GF_RTSPSession *sess, Bool ResetConnection)
256
0
{
257
0
  sess->last_session_id = NULL;
258
0
  sess->NeedConnection = 1;
259
260
0
  if (ResetConnection) {
261
0
    if (sess->connection) gf_sk_del(sess->connection);
262
0
    sess->connection = NULL;
263
0
    if (sess->http) {
264
0
      gf_sk_del(sess->http);
265
0
      sess->http = NULL;
266
0
      if (sess->tunnel_mode<RTSP_HTTP_DISABLE)
267
0
        sess->tunnel_mode = 0;
268
0
    }
269
0
    sess->tunnel_state = 0;
270
0
#ifdef GPAC_HAS_SSL
271
0
    if (sess->ssl) {
272
0
      gf_ssl_del(sess->ssl);
273
0
      sess->ssl = NULL;
274
0
    }
275
0
    if (sess->ssl_http) {
276
0
      gf_ssl_del(sess->ssl_http);
277
0
      sess->ssl_http = NULL;
278
0
    }
279
0
#endif
280
281
0
  }
282
283
0
  sess->RTSP_State = GF_RTSP_STATE_INIT;
284
0
  sess->InterID = (u8) -1;
285
0
  sess->pck_start = sess->payloadSize = 0;
286
0
  sess->CurrentPos = sess->CurrentSize = 0;
287
0
  strcpy(sess->RTSPLastRequest, "");
288
0
  RemoveTCPChannels(sess);
289
  //CSeq 1 is for regular rtsp -> rtsps switch, 0 is for rtsph->rtsph+tls
290
0
  if (sess->CSeq<=1) {
291
0
    sess->nb_retry++;
292
293
0
#ifdef GPAC_HAS_SSL
294
0
    if ((sess->nb_retry>2)
295
0
      && !sess->use_ssl
296
0
      && !gf_opts_get_bool("core", "no-tls-rcfg")
297
0
    ) {
298
0
      sess->use_ssl = GF_TRUE;
299
0
      GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSP] Connection closed by server %s, retrying with TLS\n", sess->Server));
300
0
    }
301
0
#endif
302
0
    return sess->nb_retry;
303
0
  }
304
0
  return 0;
305
0
}
306
307
308
#ifdef GPAC_HAS_SSL
309
Bool gf_rtsp_session_needs_ssl(GF_RTSPSession *sess)
310
0
{
311
0
  if (!sess) return GF_FALSE;
312
0
  if (sess->use_ssl && !sess->ssl_ctx) return GF_TRUE;
313
0
  return GF_FALSE;
314
0
}
315
#endif
316
317
GF_EXPORT
318
void gf_rtsp_session_del(GF_RTSPSession *sess)
319
0
{
320
0
  if (!sess) return;
321
322
0
  gf_rtsp_session_reset(sess, GF_FALSE);
323
324
0
  if (sess->connection) gf_sk_del(sess->connection);
325
0
  if (sess->http) gf_sk_del(sess->http);
326
0
  if (sess->Server) gf_free(sess->Server);
327
0
  if (sess->Service) gf_free(sess->Service);
328
0
  gf_list_del(sess->TCPChannels);
329
0
  if (sess->rtsp_pck_buf) gf_free(sess->rtsp_pck_buf);
330
0
  gf_free(sess->tcp_buffer);
331
0
  if (sess->HTTP_Cookie) gf_free(sess->HTTP_Cookie);
332
0
  if (sess->User) gf_free(sess->User);
333
0
  if (sess->Pass) gf_free(sess->Pass);
334
0
  if (sess->async_buf) gf_free(sess->async_buf);
335
336
0
#ifdef GPAC_HAS_SSL
337
0
  if (sess->ssl) gf_ssl_del(sess->ssl);
338
0
  if (sess->ssl_http) gf_ssl_del(sess->ssl_http);
339
0
#endif
340
341
0
  gf_free(sess);
342
0
}
343
344
#ifdef GPAC_HAS_SSL
345
GF_Err gf_rtsp_set_ssl_ctx(GF_RTSPSession *sess, void *ssl_CTX)
346
0
{
347
0
  if (!sess) return GF_BAD_PARAM;
348
0
  sess->ssl_ctx = ssl_CTX;
349
0
  return GF_OK;
350
0
}
351
#endif
352
353
354
GF_EXPORT
355
u32 gf_rtsp_get_session_state(GF_RTSPSession *sess)
356
0
{
357
0
  u32 state;
358
0
  if (!sess) return GF_RTSP_STATE_INVALIDATED;
359
360
0
  state = sess->RTSP_State;
361
0
  return state;
362
0
}
363
364
#if 0 //unused
365
char *gf_rtsp_get_last_request(GF_RTSPSession *sess)
366
{
367
  if (!sess) return NULL;
368
  return sess->RTSPLastRequest;
369
}
370
#endif
371
372
373
//check whether the url contains server and service name
374
//no thread protection as this is const throughout the session
375
GF_EXPORT
376
Bool gf_rtsp_is_my_session(GF_RTSPSession *sess, char *url)
377
0
{
378
0
  if (!sess) return GF_FALSE;
379
0
  if (!strstr(url, sess->Server)) return GF_FALSE;
380
  //same url or sub-url
381
0
  if (strstr(url, sess->Service)) return GF_TRUE;
382
0
  return GF_FALSE;
383
0
}
384
385
#if 0 //unused
386
const char *gf_rtsp_get_last_session_id(GF_RTSPSession *sess)
387
{
388
  if (!sess) return NULL;
389
  return sess->last_session_id;
390
}
391
#endif
392
393
GF_EXPORT
394
const char *gf_rtsp_get_server_name(GF_RTSPSession *sess)
395
0
{
396
0
  if (!sess) return NULL;
397
0
  return sess->Server;
398
0
}
399
400
GF_EXPORT
401
u16 gf_rtsp_get_session_port(GF_RTSPSession *sess)
402
0
{
403
0
  return (sess ? sess->Port : 0);
404
0
}
405
406
GF_EXPORT
407
Bool gf_rtsp_use_tls(GF_RTSPSession *sess)
408
0
{
409
#ifdef GPAC_HAS_TLS
410
  return (sess ? sess->use_tls : GF_FALSE);
411
#endif
412
0
  return GF_FALSE;
413
0
}
414
415
GF_Err gf_rtsp_check_connection(GF_RTSPSession *sess)
416
0
{
417
0
  GF_Err e;
418
0
  if (!sess) return GF_BAD_PARAM;
419
  //active, return
420
0
  if (!sess->NeedConnection) {
421
0
    if (sess->tunnel_state) return gf_rtsp_http_tunnel_setup(sess);
422
0
    return gf_rstp_flush_buffer(sess);
423
0
  }
424
425
  //socket is destroyed, recreate
426
0
  if (!sess->connection) {
427
0
    sess->connection = gf_sk_new_ex(sess->ConnectionType, sess->netcap_id);
428
0
    if (!sess->connection) return GF_OUT_OF_MEM;
429
430
    //work in non-blocking mode
431
0
    gf_sk_set_block_mode(sess->connection, GF_TRUE);
432
0
    sess->timeout_in = gf_opts_get_int("core", "tcp-timeout");
433
0
    if (!sess->timeout_in) sess->timeout_in = 5000;
434
0
    sess->timeout_in += gf_sys_clock();
435
0
    if (sess->SockBufferSize) gf_sk_set_buffer_size(sess->connection, GF_FALSE, sess->SockBufferSize);
436
0
  }
437
438
  //the session is down, reconnect
439
0
#ifdef GPAC_HAS_SSL
440
0
  if (!sess->ssl_connect_pending)
441
0
#endif
442
0
  {
443
0
    e = gf_sk_connect(sess->connection, sess->Server, sess->Port, NULL);
444
0
    if (e) {
445
0
      if (e==GF_IP_NETWORK_EMPTY) {
446
0
        if (sess->timeout_in < gf_sys_clock())
447
0
          e = GF_IP_CONNECTION_FAILURE;
448
0
      }
449
0
      return e;
450
0
    }
451
0
  }
452
453
0
#ifdef GPAC_HAS_SSL
454
0
  if (sess->use_ssl) {
455
0
    if (!sess->ssl_ctx)
456
0
      return GF_IP_CONNECTION_FAILURE;
457
458
0
    if (!sess->ssl) {
459
0
      sess->ssl = SSL_new(sess->ssl_ctx);
460
0
      SSL_set_fd(sess->ssl, gf_sk_get_handle(sess->connection));
461
0
      SSL_ctrl(sess->ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (void*) sess->Server);
462
0
      SSL_set_connect_state(sess->ssl);
463
0
      SSL_set_mode(sess->ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
464
0
      SSL_set_alpn_protos(sess->ssl, NULL, 0);
465
0
    }
466
467
0
    sess->ssl_connect_pending = 0;
468
0
    int ret = SSL_connect(sess->ssl);
469
0
    if (ret<=0) {
470
0
      ret = SSL_get_error(sess->ssl, ret);
471
0
      if (ret==SSL_ERROR_SSL) {
472
0
        char msg[1024];
473
0
        SSL_load_error_strings();
474
0
        ERR_error_string_n(ERR_get_error(), msg, 1023);
475
0
        msg[1023]=0;
476
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_HTTP, ("[SSL] Cannot connect, error %s\n", msg));
477
0
        return GF_IP_CONNECTION_FAILURE;
478
0
      } else if ((ret==SSL_ERROR_WANT_READ) || (ret==SSL_ERROR_WANT_WRITE)) {
479
0
        sess->ssl_connect_pending = 1;
480
0
        return GF_IP_NETWORK_EMPTY;
481
0
      } else {
482
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_HTTP, ("[SSL] Cannot connect, error %d\n", ret));
483
0
        return GF_REMOTE_SERVICE_ERROR;
484
0
      }
485
0
    } else {
486
0
      GF_LOG(GF_LOG_DEBUG, GF_LOG_HTTP, ("[SSL] connected\n"));
487
0
    }
488
489
0
    Bool success = gf_ssl_check_cert(sess->ssl, sess->Server);
490
0
    if (!success) {
491
0
      return GF_AUTHENTICATION_FAILURE;
492
0
    }
493
0
  }
494
0
#endif
495
496
0
  sess->NeedConnection = 0;
497
0
  if (!sess->http && (sess->tunnel_mode==RTSP_HTTP_CLIENT)) {
498
0
    e = gf_rtsp_http_tunnel_setup(sess);
499
0
    if (e) return e;
500
0
  }
501
0
  return gf_rstp_flush_buffer(sess);
502
0
}
503
504
505
GF_Err gf_rtsp_send_data(GF_RTSPSession *sess, u8 *buffer, u32 Size)
506
0
{
507
0
  GF_Err e;
508
0
  u32 Size64;
509
510
0
  e = gf_rtsp_check_connection(sess);
511
0
  if (e) return e;
512
513
  //RTSP requests on HTTP are base 64 encoded
514
0
  if (sess->tunnel_mode==RTSP_HTTP_CLIENT) {
515
0
    char *buf64 = gf_malloc(sizeof(char)*Size*2);
516
0
    if (!buf64) return GF_OUT_OF_MEM;
517
0
    Size64 = gf_base64_encode(buffer, Size, buf64, Size*2);
518
    //send on http connection
519
0
    e = gf_rtsp_write_sock(sess, buf64, Size64);
520
0
    gf_free(buf64);
521
0
    return e;
522
0
  } else {
523
0
    return gf_rtsp_write_sock(sess, buffer, Size);
524
0
  }
525
0
}
526
527
528
529
static GF_TCPChan *GetTCPChannel(GF_RTSPSession *sess, u8 rtpID, u8 rtcpID, Bool RemoveIt)
530
0
{
531
0
  GF_TCPChan *ptr;
532
0
  u32 i, count = gf_list_count(sess->TCPChannels);
533
0
  for (i=0; i<count; i++) {
534
0
    ptr = (GF_TCPChan *)gf_list_get(sess->TCPChannels, i);
535
0
    if (ptr->rtpID == rtpID) goto exit;
536
0
    if (ptr->rtcpID == rtcpID) goto exit;
537
0
  }
538
0
  return NULL;
539
0
exit:
540
0
  if (RemoveIt) gf_list_rem(sess->TCPChannels, i);
541
0
  return ptr;
542
0
}
543
544
545
GF_Err gf_rtsp_do_deinterleave(GF_RTSPSession *sess)
546
0
{
547
0
  GF_TCPChan *ch;
548
0
  Bool IsRTCP;
549
0
  u8 InterID;
550
0
  u16 paySize;
551
0
  u32 res, Size;
552
0
  char *buffer;
553
554
0
  if (!sess) return GF_SERVICE_ERROR;
555
556
0
  Size = sess->CurrentSize - sess->CurrentPos;
557
0
  buffer = sess->tcp_buffer + sess->CurrentPos;
558
559
  //we do not work with just a header -> force a refill
560
0
  if (!Size)
561
0
    return gf_rtsp_fill_buffer(sess);
562
0
  if (Size <= 4)
563
0
    return gf_rtsp_refill_buffer(sess);
564
565
  //break if we get RTSP response on the wire
566
0
  if (!strncmp(buffer, "RTSP", 4) || !strncmp(buffer, "HTTP", 4))
567
0
    return GF_EOS;
568
569
  //new packet
570
0
  if (!sess->pck_start && (buffer[0] == '$')) {
571
0
    InterID = buffer[1];
572
0
    paySize = ((buffer[2] << 8) & 0xFF00) | (buffer[3] & 0xFF);
573
    /*this may be NULL (data fetched after a teardown) - resync and return*/
574
0
    ch = GetTCPChannel(sess, InterID, InterID, GF_FALSE);
575
576
    /*then check whether this is a full packet or a split*/
577
0
    if (paySize <= Size-4) {
578
0
      if (ch) {
579
0
        IsRTCP = (ch->rtcpID == InterID) ? GF_TRUE : GF_FALSE;
580
0
        sess->RTSP_SignalData(sess, ch->ch_ptr, buffer+4, paySize, IsRTCP);
581
0
      }
582
0
      sess->CurrentPos += paySize+4;
583
0
      gf_fatal_assert(sess->CurrentPos <= sess->CurrentSize);
584
0
    } else {
585
      /*missed end of pck ?*/
586
0
      if (sess->payloadSize) {
587
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));
588
0
        ch = GetTCPChannel(sess, sess->InterID, sess->InterID, GF_FALSE);
589
0
        if (ch) {
590
0
          IsRTCP = (ch->rtcpID == sess->InterID) ? GF_TRUE : GF_FALSE;
591
0
          sess->RTSP_SignalData(sess, ch->ch_ptr, sess->rtsp_pck_buf, sess->payloadSize, IsRTCP);
592
0
        }
593
0
      }
594
0
      sess->InterID = InterID;
595
0
      sess->payloadSize = paySize;
596
0
      sess->pck_start = Size-4;
597
0
      if (sess->rtsp_pck_size < paySize) {
598
0
        sess->rtsp_pck_buf = (char *)gf_realloc(sess->rtsp_pck_buf, sizeof(char)*paySize);
599
0
        sess->rtsp_pck_size = paySize;
600
0
      }
601
0
      memcpy(sess->rtsp_pck_buf, buffer+4, Size-4);
602
0
      sess->CurrentPos += Size;
603
0
      gf_fatal_assert(sess->CurrentPos <= sess->CurrentSize);
604
0
    }
605
0
  }
606
  /*end of packet*/
607
0
  else if (sess->payloadSize - sess->pck_start <= Size) {
608
//    GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of packet (%d bytes) in stream %d\n", Size, sess->InterID));
609
610
0
    res = sess->payloadSize - sess->pck_start;
611
0
    if (res)
612
0
      memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, res);
613
    //flush - same as above, don't complain if channel not found
614
0
    ch = GetTCPChannel(sess, sess->InterID, sess->InterID, GF_FALSE);
615
0
    if (ch) {
616
0
      IsRTCP = (ch->rtcpID == sess->InterID) ? GF_TRUE : GF_FALSE;
617
0
      sess->RTSP_SignalData(sess, ch->ch_ptr, sess->rtsp_pck_buf, sess->payloadSize, IsRTCP);
618
0
    }
619
0
    sess->payloadSize = 0;
620
0
    sess->pck_start = 0;
621
0
    sess->InterID = (u8) -1;
622
0
    sess->CurrentPos += res;
623
0
    gf_fatal_assert(sess->CurrentPos <= sess->CurrentSize);
624
0
  }
625
  /*middle of packet*/
626
0
  else {
627
//    GF_LOG(GF_LOG_DEBUG, GF_LOG_RTP, ("[RTP over RTSP] Missed beginning of RTP packet in stream %d\n", sess->InterID));
628
0
    memcpy(sess->rtsp_pck_buf + sess->pck_start, buffer, Size);
629
0
    sess->pck_start += Size;
630
0
    sess->CurrentPos += Size;
631
0
    gf_fatal_assert(sess->CurrentPos <= sess->CurrentSize);
632
0
  }
633
0
  return GF_OK;
634
0
}
635
636
637
GF_EXPORT
638
GF_Err gf_rtsp_session_read(GF_RTSPSession *sess)
639
0
{
640
0
  GF_Err e;
641
0
  if (!sess) return GF_BAD_PARAM;
642
643
0
  e = gf_rtsp_fill_buffer(sess);
644
0
  if (!e) {
645
    //read as much as possible (will break if no data or if "RTSP" is found)
646
0
    while (1) {
647
0
      e = gf_rtsp_do_deinterleave(sess);
648
0
      if (e) return e;
649
0
    }
650
0
  }
651
0
  return e;
652
0
}
653
654
655
GF_EXPORT
656
u32 gf_rtsp_unregister_interleave(GF_RTSPSession *sess, u8 LowInterID)
657
0
{
658
0
  u32 res;
659
0
  GF_TCPChan *ptr;
660
0
  if (!sess) return 0;
661
662
0
  ptr = GetTCPChannel(sess, LowInterID, LowInterID, GF_TRUE);
663
0
  if (ptr) gf_free(ptr);
664
0
  res = gf_list_count(sess->TCPChannels);
665
0
  if (!res) sess->interleaved = GF_FALSE;
666
0
  return res;
667
0
}
668
669
GF_EXPORT
670
GF_Err gf_rtsp_register_interleave(GF_RTSPSession *sess, void *the_ch, u8 LowInterID, u8 HighInterID)
671
0
{
672
0
  GF_TCPChan *ptr;
673
674
0
  if (!sess) return GF_BAD_PARAM;
675
676
  //do NOT register twice
677
0
  ptr = GetTCPChannel(sess, LowInterID, HighInterID, GF_FALSE);
678
0
  if (!ptr) {
679
0
    ptr = (GF_TCPChan *)gf_malloc(sizeof(GF_TCPChan));
680
0
    ptr->ch_ptr = the_ch;
681
0
    ptr->rtpID = LowInterID;
682
0
    ptr->rtcpID = HighInterID;
683
0
    gf_list_add(sess->TCPChannels, ptr);
684
0
  }
685
0
  sess->interleaved=GF_TRUE;
686
0
  return GF_OK;
687
0
}
688
689
690
GF_EXPORT
691
GF_Err gf_rtsp_set_interleave_callback(GF_RTSPSession *sess, gf_rtsp_interleave_callback SignalData)
692
0
{
693
0
  if (!sess) return GF_BAD_PARAM;
694
695
  //only if existing
696
0
  if (SignalData) sess->RTSP_SignalData = SignalData;
697
698
0
  if (!sess->rtsp_pck_buf || (sess->rtsp_pck_size != RTSP_PCK_SIZE) ) {
699
0
    if (!sess->rtsp_pck_buf)
700
0
      sess->pck_start = 0;
701
0
    sess->rtsp_pck_size = RTSP_PCK_SIZE;
702
0
    sess->rtsp_pck_buf = (char *)gf_realloc(sess->rtsp_pck_buf, sizeof(char)*sess->rtsp_pck_size);
703
0
  }
704
0
  return GF_OK;
705
0
}
706
707
GF_EXPORT
708
GF_Err gf_rtsp_set_buffer_size(GF_RTSPSession *sess, u32 BufferSize)
709
0
{
710
0
  if (!sess) return GF_BAD_PARAM;
711
0
  if (sess->SockBufferSize >= BufferSize) return GF_OK;
712
0
  sess->SockBufferSize = BufferSize;
713
0
  sess->tcp_buffer = gf_realloc(sess->tcp_buffer, (BufferSize+1));
714
0
  return GF_OK;
715
0
}
716
717
static GF_Err rstp_do_write_sock(GF_RTSPSession *sess, GF_Socket *sock, const u8 *buffer, u32 size, u32 *written)
718
0
{
719
0
#ifdef GPAC_HAS_SSL
720
0
  SSL *ssl_sock = (sock==sess->http) ? sess->ssl_http : sess->ssl;
721
0
  if (ssl_sock) {
722
0
    u32 idx=0;
723
0
    s32 nb_tls_blocks = size/16000;
724
0
    if (written)
725
0
      *written = 0;
726
0
    while (nb_tls_blocks>=0) {
727
0
      u32 len, to_write = 16000;
728
0
      if (nb_tls_blocks==0)
729
0
        to_write = size - idx*16000;
730
731
0
      len = SSL_write(ssl_sock, buffer + idx*16000, to_write);
732
0
      nb_tls_blocks--;
733
0
      idx++;
734
735
0
      if (len != to_write) {
736
0
        int err = SSL_get_error(ssl_sock, len);
737
0
        if ((err==SSL_ERROR_WANT_READ) || (err==SSL_ERROR_WANT_WRITE)) {
738
0
          return GF_IP_NETWORK_EMPTY;
739
0
        }
740
0
        if (err==SSL_ERROR_SSL) {
741
0
          char msg[1024];
742
0
          SSL_load_error_strings();
743
0
          ERR_error_string_n(ERR_get_error(), msg, 1023);
744
0
          msg[1023]=0;
745
0
          GF_LOG(GF_LOG_ERROR, GF_LOG_HTTP, ("[SSL] Cannot send, error %s\n", msg));
746
0
        }
747
0
        return GF_IP_NETWORK_FAILURE;
748
0
      }
749
0
      if (written)
750
0
        *written += to_write;
751
0
    }
752
0
    return GF_OK;
753
0
  }
754
0
#endif
755
0
  return gf_sk_send_ex(sock, buffer, size, written);
756
0
}
757
758
759
static Bool HTTP_RandInit = GF_TRUE;
760
761
0
#define HTTP10_RSP_OK "HTTP/1.0 200 OK"
762
0
#define HTTP11_RSP_OK "HTTP/1.1 200 OK"
763
764
static GF_Err gf_rtsp_http_tunnel_setup(GF_RTSPSession *sess)
765
0
{
766
0
  GF_Err e;
767
0
  u32 size;
768
0
  s32 pos;
769
0
  const char *ua;
770
0
  char buffer[GF_RTSP_DEFAULT_BUFFER];
771
772
0
  if (!sess) return GF_BAD_PARAM;
773
774
0
  if (!sess->tunnel_state) {
775
    //generate http cookie
776
0
    if (HTTP_RandInit) {
777
0
      gf_rand_init(GF_FALSE);
778
0
      HTTP_RandInit = GF_FALSE;
779
0
    }
780
0
    if (!sess->HTTP_Cookie) {
781
0
      char szBuf[30];
782
0
      u32 r = gf_rand();
783
0
      snprintf(szBuf, 29, "GPAC_%x_"LLX, r, gf_sys_clock_high_res() );
784
0
      szBuf[29]=0;
785
0
      sess->HTTP_Cookie = gf_strdup(szBuf);
786
0
      if (!sess->HTTP_Cookie) return GF_OUT_OF_MEM;
787
0
    }
788
789
0
    ua = gf_opts_get_key("core", "user-agent");
790
0
    if (!ua) ua = "GPAC " GPAC_VERSION;
791
792
    //  1. send "GET /sample.mov HTTP/1.0\r\n ..."
793
0
    memset(buffer, 0, GF_RTSP_DEFAULT_BUFFER);
794
0
    pos = 0;
795
0
    pos += sprintf(buffer + pos, "GET /%s HTTP/1.0\r\n", sess->Service);
796
0
    pos += sprintf(buffer + pos, "User-Agent: %s\r\n", ua);
797
0
    pos += sprintf(buffer + pos, "x-sessioncookie: %s\r\n", sess->HTTP_Cookie);
798
0
    pos += sprintf(buffer + pos, "Accept: application/x-rtsp-tunnelled\r\n" );
799
0
    pos += sprintf(buffer + pos, "Pragma: no-cache\r\n" );
800
0
    /*pos += */sprintf(buffer + pos, "Cache-Control: no-cache\r\n\r\n" );
801
802
0
    sess->tunnel_state = 1;
803
0
    GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSPTunnel] Sending %s", buffer));
804
805
    //  send it - we assume this will fit the socket buffer
806
0
    e = rstp_do_write_sock(sess, sess->connection, buffer, (u32) strlen(buffer), NULL);
807
0
    if (e) return e;
808
0
  }
809
810
0
  if (sess->tunnel_state == 1) {
811
    //  2. wait for "HTTP/1.0 200 OK"
812
0
    e = gf_rstp_do_read_sock(sess, sess->connection, buffer, GF_RTSP_DEFAULT_BUFFER, &size);
813
0
    if (e) {
814
0
      if ((e==GF_IP_NETWORK_EMPTY) && (sess->timeout_in < gf_sys_clock()))
815
0
        e = GF_IP_CONNECTION_FAILURE;
816
0
      return e;
817
0
    }
818
0
    gf_assert(size);
819
0
    sess->tunnel_state = 2;
820
0
    GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSPTunnel] Got reply %s", buffer));
821
822
    //get HTTP/1.0 200 OK
823
0
    if (strncmp(buffer, HTTP10_RSP_OK, strlen(HTTP10_RSP_OK)) && strncmp(buffer, HTTP11_RSP_OK, strlen(HTTP11_RSP_OK))) {
824
0
      sess->tunnel_state = 0;
825
0
      return GF_REMOTE_SERVICE_ERROR;
826
0
    }
827
828
    //  3. send "POST /sample.mov HTTP/1.0\r\n ..."
829
0
    sess->http = gf_sk_new_ex(GF_SOCK_TYPE_TCP, sess->netcap_id);
830
0
    if (!sess->http) {
831
0
      sess->tunnel_state = 0;
832
0
      return GF_IP_NETWORK_FAILURE;
833
0
    }
834
0
    gf_sk_set_block_mode(sess->http, GF_TRUE);
835
0
  }
836
837
0
#ifdef GPAC_HAS_SSL
838
0
  if (!sess->ssl_connect_pending)
839
0
#endif
840
0
  {
841
0
    e = gf_sk_connect(sess->http, sess->Server, sess->Port, NULL);
842
0
    if (e) {
843
0
      if ((e==GF_IP_NETWORK_EMPTY) && (sess->timeout_in < gf_sys_clock()))
844
0
        e = GF_IP_CONNECTION_FAILURE;
845
0
      return e;
846
0
    }
847
0
  }
848
849
850
0
#ifdef GPAC_HAS_SSL
851
0
  if (sess->use_ssl) {
852
0
    if (!sess->ssl_http) {
853
0
      sess->ssl_http = SSL_new(sess->ssl_ctx);
854
0
      SSL_set_fd(sess->ssl_http, gf_sk_get_handle(sess->http));
855
0
      SSL_ctrl(sess->ssl_http, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, (void*) sess->Server);
856
0
      SSL_set_connect_state(sess->ssl_http);
857
0
      SSL_set_mode(sess->ssl_http, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
858
0
      SSL_set_alpn_protos(sess->ssl_http, NULL, 0);
859
0
    }
860
861
0
    sess->ssl_connect_pending = 0;
862
0
    int ret = SSL_connect(sess->ssl_http);
863
0
    if (ret<=0) {
864
0
      ret = SSL_get_error(sess->ssl_http, ret);
865
0
      if (ret==SSL_ERROR_SSL) {
866
0
        char msg[1024];
867
0
        SSL_load_error_strings();
868
0
        ERR_error_string_n(ERR_get_error(), msg, 1023);
869
0
        msg[1023]=0;
870
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_HTTP, ("[SSL] Cannot connect, error %s\n", msg));
871
0
        return GF_IP_CONNECTION_FAILURE;
872
0
      } else if ((ret==SSL_ERROR_WANT_READ) || (ret==SSL_ERROR_WANT_WRITE)) {
873
0
        sess->ssl_connect_pending = 1;
874
0
        return GF_IP_NETWORK_EMPTY;
875
0
      } else {
876
0
        GF_LOG(GF_LOG_ERROR, GF_LOG_HTTP, ("[SSL] Cannot connect, error %d\n", ret));
877
0
        return GF_REMOTE_SERVICE_ERROR;
878
0
      }
879
0
    } else {
880
0
      GF_LOG(GF_LOG_DEBUG, GF_LOG_HTTP, ("[SSL] connected\n"));
881
0
    }
882
0
  }
883
0
#endif
884
885
0
  GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSPTunnel] POST channel connected"));
886
887
888
0
  ua = gf_opts_get_key("core", "user-agent");
889
0
  if (!ua) ua = "GPAC " GPAC_VERSION;
890
0
  memset(buffer, 0, GF_RTSP_DEFAULT_BUFFER);
891
0
  pos = 0;
892
0
  pos += sprintf(buffer + pos, "POST /%s HTTP/1.0\r\n", sess->Service);
893
0
  pos += sprintf(buffer + pos, "User-Agent: %s\r\n", ua);
894
0
  pos += sprintf(buffer + pos, "x-sessioncookie: %s\r\n", sess->HTTP_Cookie);
895
0
  pos += sprintf(buffer + pos, "Accept: application/x-rtsp-tunnelled\r\n");
896
0
  pos += sprintf(buffer + pos, "Pragma: no-cache\r\n");
897
0
  pos += sprintf(buffer + pos, "Cache-Control: no-cache\r\n");
898
0
  pos += sprintf(buffer + pos, "Content-Length: 32767\r\n");
899
0
  /*pos += */sprintf(buffer + pos, "Expires: Sun. 9 Jan 1972 00:00:00 GMT\r\n\r\n");
900
901
0
  sess->tunnel_state = 0;
902
0
  GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSPTunnel] Sending request %s", buffer));
903
  //  send it, no need to wait for answer
904
0
  return rstp_do_write_sock(sess, sess->http, buffer, (u32) strlen(buffer), NULL);
905
0
}
906
907
/*server-side RTSP sockets*/
908
909
static u32 SessionID_RandInit = 0;
910
911
912
GF_EXPORT
913
GF_RTSPSession *gf_rtsp_session_new_server(GF_Socket *rtsp_listener, Bool allow_http_tunnel, void *ssl_ctx)
914
0
{
915
0
  GF_RTSPSession *sess;
916
0
  GF_Socket *new_conn;
917
0
  GF_Err e;
918
0
  u32 fam;
919
0
  u16 port;
920
0
#ifdef GPAC_HAS_SSL
921
0
  SSL *ssl = NULL;
922
0
#endif
923
924
0
  if (!rtsp_listener) return NULL;
925
926
927
0
  e = gf_sk_accept(rtsp_listener, &new_conn);
928
0
  if (!new_conn || e) return NULL;
929
930
0
#ifdef GPAC_HAS_SSL
931
0
  if (ssl_ctx) {
932
0
    ssl = gf_ssl_new(ssl_ctx, new_conn, &e);
933
0
    if (e) {
934
0
      GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("[SSL] Failed to create TLS session: %s\n", gf_error_to_string(e) ));
935
0
      gf_sk_del(new_conn);
936
0
      return NULL;
937
0
    }
938
0
    SSL_set_mode(ssl, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER|SSL_MODE_ENABLE_PARTIAL_WRITE);
939
0
  }
940
0
#endif
941
942
0
  e = gf_sk_get_local_info(new_conn, &port, &fam);
943
0
  if (e) {
944
0
    gf_sk_del(new_conn);
945
0
    return NULL;
946
0
  }
947
0
  e = gf_sk_set_block_mode(new_conn, GF_TRUE);
948
0
  if (e) {
949
0
    gf_sk_del(new_conn);
950
0
    return NULL;
951
0
  }
952
0
  e = gf_sk_server_mode(new_conn, GF_TRUE);
953
0
  if (e) {
954
0
    gf_sk_del(new_conn);
955
0
    return NULL;
956
0
  }
957
958
  //OK create a new session
959
0
  GF_SAFEALLOC(sess, GF_RTSPSession);
960
0
  if (!sess) return NULL;
961
962
0
  sess->connection = new_conn;
963
0
  sess->Port = port;
964
0
  sess->ConnectionType = fam;
965
0
#ifdef GPAC_HAS_SSL
966
0
  sess->ssl_ctx = ssl_ctx;
967
0
  sess->ssl = ssl;
968
0
#endif
969
0
  const char *name = gf_opts_get_key("core", "user-agent");
970
0
  if (name) {
971
0
    sess->Server = gf_strdup(name);
972
0
  } else {
973
0
    sess->Server = gf_strdup("GPAC-");
974
0
    gf_dynstrcat(&sess->Server, gf_gpac_version(), NULL);
975
0
  }
976
0
  gf_rtsp_set_buffer_size(sess, 4096);
977
0
  sess->TCPChannels = gf_list_new();
978
0
  if (!allow_http_tunnel)
979
0
    sess->tunnel_mode = RTSP_HTTP_DISABLE;
980
981
0
  return sess;
982
0
}
983
984
985
#if 0 //unused
986
GF_Err gf_rtsp_load_service_name(GF_RTSPSession *sess, char *URL)
987
{
988
  char server[1024], service[1024], user[1024], pass[1024];
989
  GF_Err e;
990
  u16 Port;
991
  Bool UseTCP;
992
  u32 type;
993
994
  if (!sess || !URL) return GF_BAD_PARAM;
995
  e = RTSP_UnpackURL(URL, server, &Port, service, &UseTCP, user, pass);
996
  if (e) return e;
997
998
  type = UseTCP ? GF_SOCK_TYPE_TCP : GF_SOCK_TYPE_UDP;
999
  //check the network type matches, otherwise deny client
1000
  if (sess->ConnectionType != type) return GF_URL_ERROR;
1001
  if (sess->Port != Port) return GF_URL_ERROR;
1002
1003
  //ok
1004
  sess->Server = gf_strdup(server);
1005
  sess->Service = gf_strdup(service);
1006
  return GF_OK;
1007
}
1008
#endif
1009
1010
GF_EXPORT
1011
char *gf_rtsp_generate_session_id(GF_RTSPSession *sess)
1012
0
{
1013
0
  u32 one;
1014
0
  u64 res;
1015
0
  char buffer[30];
1016
1017
0
  if (!sess) return NULL;
1018
1019
0
  if (!SessionID_RandInit) {
1020
0
    SessionID_RandInit = 1;
1021
0
    gf_rand_init(GF_FALSE);
1022
0
  }
1023
0
  one = gf_rand();
1024
0
  res = one;
1025
0
  res <<= 32;
1026
0
  res+= (PTR_TO_U_CAST sess) + sess->CurrentPos + sess->CurrentSize;
1027
0
  sprintf(buffer, LLU, res);
1028
0
  return gf_strdup(buffer);
1029
0
}
1030
1031
1032
GF_EXPORT
1033
GF_Err gf_rtsp_get_session_ip(GF_RTSPSession *sess, char buffer[GF_MAX_IP_NAME_LEN])
1034
0
{
1035
0
  if (!sess || !sess->connection) return GF_BAD_PARAM;
1036
0
  if (gf_sk_get_local_ip(sess->connection, buffer) != GF_OK)
1037
0
    strcpy(buffer, "127.0.0.1");
1038
0
  return GF_OK;
1039
0
}
1040
1041
1042
#if 0 //unused
1043
u8 gf_rtsp_get_next_interleave_id(GF_RTSPSession *sess)
1044
{
1045
  u32 i;
1046
  u8 id;
1047
  GF_TCPChan *ch;
1048
  id = 0;
1049
  i=0;
1050
  while ((ch = (GF_TCPChan *)gf_list_enum(sess->TCPChannels, &i))) {
1051
    if (ch->rtpID >= id) id = ch->rtpID + 1;
1052
    if (ch->rtcpID >= id) id = ch->rtcpID + 1;
1053
  }
1054
  return id;
1055
}
1056
#endif
1057
1058
GF_EXPORT
1059
GF_Err gf_rtsp_get_remote_address(GF_RTSPSession *sess, char *buf)
1060
0
{
1061
0
  if (!sess || !sess->connection) return GF_BAD_PARAM;
1062
0
  return gf_sk_get_remote_address(sess->connection, buf);
1063
0
}
1064
1065
static GF_Err gf_rtsp_write_sock(GF_RTSPSession *sess, u8 *data, u32 len)
1066
0
{
1067
0
  u32 remain, written=0;
1068
0
  if (!sess->async_buf_size) {
1069
0
    GF_Err e = rstp_do_write_sock(sess, (sess->http && (sess->tunnel_mode==RTSP_HTTP_CLIENT)) ? sess->http : sess->connection, data, len, &written);
1070
0
    if (e && (e!= GF_IP_NETWORK_EMPTY))
1071
0
      return e;
1072
0
    if (written==len) return GF_OK;
1073
0
  }
1074
1075
0
  remain = len - written;
1076
0
  if (sess->async_buf_size + remain > sess->async_buf_alloc) {
1077
0
    sess->async_buf_alloc = sess->async_buf_size+remain;
1078
0
    sess->async_buf = gf_realloc(sess->async_buf, sess->async_buf_alloc);
1079
0
    if (!sess->async_buf) return GF_OUT_OF_MEM;
1080
0
  }
1081
0
  memcpy(sess->async_buf + sess->async_buf_size, data+written, remain);
1082
0
  sess->async_buf_size += remain;
1083
0
  return GF_OK;
1084
0
}
1085
1086
GF_EXPORT
1087
GF_Err gf_rtsp_session_write_interleaved(GF_RTSPSession *sess, u32 idx, u8 *pck, u32 pck_size)
1088
0
{
1089
0
  GF_Err e;
1090
0
  char streamID[4];
1091
0
  if (!sess || !sess->connection) return GF_BAD_PARAM;
1092
1093
0
  streamID[0] = '$';
1094
0
  streamID[1] = (u8) idx;
1095
0
  streamID[2] = (pck_size>>8) & 0xFF;
1096
0
  streamID[3] = pck_size & 0xFF;
1097
1098
0
  e = gf_rtsp_write_sock(sess, streamID, 4);
1099
0
  e |= gf_rtsp_write_sock(sess, pck, pck_size);
1100
0
  return e;
1101
0
}
1102
1103
1104
static GF_Err gf_rstp_flush_buffer(GF_RTSPSession *sess)
1105
0
{
1106
0
  while (sess->async_buf_size) {
1107
0
    u32 written = 0;
1108
0
    GF_Err e = rstp_do_write_sock(sess, (sess->tunnel_mode==RTSP_HTTP_CLIENT) ? sess->http : sess->connection, sess->async_buf, sess->async_buf_size, &written);
1109
0
    if (e) {
1110
0
      if (e!= GF_IP_NETWORK_EMPTY)
1111
0
        sess->async_buf_size = 0;
1112
0
      return e;
1113
0
    }
1114
0
    if (written==sess->async_buf_size) {
1115
0
      sess->async_buf_size = 0;
1116
0
      return GF_OK;
1117
0
    }
1118
0
    memmove(sess->async_buf, sess->async_buf + written, sess->async_buf_size - written);
1119
0
    sess->async_buf_size -= written;
1120
0
  }
1121
0
  return GF_OK;
1122
0
}
1123
1124
const char *gf_rtsp_get_session_cookie(GF_RTSPSession *sess)
1125
0
{
1126
0
  return sess ? sess->HTTP_Cookie : NULL;
1127
0
}
1128
1129
GF_Err gf_rtsp_merge_tunnel(GF_RTSPSession *sess, GF_RTSPSession *post_sess)
1130
0
{
1131
0
  if (!sess || !post_sess) return GF_BAD_PARAM;
1132
0
  if (!sess->HTTP_Cookie || !post_sess->HTTP_Cookie) return GF_BAD_PARAM;
1133
0
  if (strcmp(sess->HTTP_Cookie, post_sess->HTTP_Cookie)) return GF_BAD_PARAM;
1134
0
  if (!post_sess->connection) return GF_BAD_PARAM;
1135
1136
  //move any pending data
1137
0
  if (post_sess->CurrentPos<post_sess->CurrentSize) {
1138
0
    u8 *buf = post_sess->tcp_buffer + post_sess->CurrentPos;
1139
0
    u32 remain = post_sess->CurrentSize - post_sess->CurrentPos;
1140
0
    if (sess->CurrentSize + remain > sess->SockBufferSize) {
1141
0
      sess->SockBufferSize = sess->CurrentSize + remain;
1142
0
      sess->tcp_buffer = gf_realloc(sess->tcp_buffer, sess->SockBufferSize);
1143
0
      if (!sess->tcp_buffer) return GF_OUT_OF_MEM;
1144
0
    }
1145
0
    memcpy(sess->tcp_buffer+sess->CurrentPos, buf, remain);
1146
0
    sess->CurrentSize += remain;
1147
0
  }
1148
0
  sess->tunnel_mode = RTSP_HTTP_SERVER;
1149
0
  sess->http = post_sess->connection;
1150
0
  post_sess->connection = NULL;
1151
1152
0
#ifdef GPAC_HAS_SSL
1153
0
  sess->ssl_http = post_sess->ssl;
1154
0
  post_sess->ssl = NULL;
1155
0
#endif
1156
1157
0
  return GF_OK;
1158
0
}
1159
1160
const char *gf_rtsp_get_user(GF_RTSPSession *sess)
1161
0
{
1162
0
  return sess ? sess->User : NULL;
1163
0
}
1164
const char *gf_rtsp_get_password(GF_RTSPSession *sess)
1165
0
{
1166
0
  return sess ? sess->Pass : NULL;
1167
0
}
1168
1169
1170
#endif /*GPAC_DISABLE_STREAMING*/