LCOV - code coverage report
Current view: top level - ietf - rtsp_session.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 224 315 71.1 %
Date: 2021-04-29 23:48:07 Functions: 25 25 100.0 %

          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*/

Generated by: LCOV version 1.13