LCOV - code coverage report
Current view: top level - ietf - rtsp_command.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 229 285 80.4 %
Date: 2021-04-29 23:48:07 Functions: 8 8 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             : 
      27             : #include <gpac/internal/ietf_dev.h>
      28             : 
      29             : #ifndef GPAC_DISABLE_STREAMING
      30             : 
      31             : #include <gpac/token.h>
      32             : 
      33             : GF_EXPORT
      34          55 : GF_RTSPCommand *gf_rtsp_command_new()
      35             : {
      36             :         GF_RTSPCommand *tmp;
      37          55 :         GF_SAFEALLOC(tmp, GF_RTSPCommand);
      38          55 :         if (!tmp) return NULL;
      39          55 :         tmp->Xtensions = gf_list_new();
      40          55 :         tmp->Transports = gf_list_new();
      41          55 :         return tmp;
      42             : }
      43             : 
      44             : 
      45             : #define COM_FREE_CLEAN(hdr)             if (com->hdr) gf_free(com->hdr);  \
      46             :                                                                 com->hdr = NULL;
      47             : 
      48             : GF_EXPORT
      49         473 : void gf_rtsp_command_reset(GF_RTSPCommand *com)
      50             : {
      51         473 :         if (!com) return;
      52             : 
      53             :         //free all headers
      54         473 :         COM_FREE_CLEAN(Accept);
      55         473 :         COM_FREE_CLEAN(Accept_Encoding);
      56         473 :         COM_FREE_CLEAN(Accept_Language);
      57         473 :         COM_FREE_CLEAN(Authorization);
      58         473 :         COM_FREE_CLEAN(Cache_Control);
      59         473 :         COM_FREE_CLEAN(Conference);
      60         473 :         COM_FREE_CLEAN(Connection);
      61         473 :         COM_FREE_CLEAN(From);
      62         473 :         COM_FREE_CLEAN(Proxy_Authorization);
      63         473 :         COM_FREE_CLEAN(Proxy_Require);
      64         473 :         COM_FREE_CLEAN(Referer);
      65         473 :         COM_FREE_CLEAN(Session);
      66         473 :         COM_FREE_CLEAN(User_Agent);
      67         473 :         COM_FREE_CLEAN(body);
      68         473 :         COM_FREE_CLEAN(service_name);
      69         473 :         COM_FREE_CLEAN(ControlString);
      70         473 :         COM_FREE_CLEAN(method);
      71             : 
      72             :         //this is for server only, set to OK by default
      73         473 :         com->StatusCode = NC_RTSP_OK;
      74             : 
      75             : 
      76         473 :         com->user_data = NULL;
      77             : 
      78         473 :         com->Bandwidth = com->Blocksize = com->Content_Length = com->CSeq = 0;
      79         473 :         com->Scale = com->Speed = 0.0;
      80         473 :         if (com->Range) gf_free(com->Range);
      81         473 :         com->Range = NULL;
      82             : 
      83         958 :         while (gf_list_count(com->Transports)) {
      84          12 :                 GF_RTSPTransport *trans = (GF_RTSPTransport *) gf_list_get(com->Transports, 0);
      85          12 :                 gf_list_rem(com->Transports, 0);
      86          12 :                 gf_rtsp_transport_del(trans);
      87             :         }
      88         473 :         while (gf_list_count(com->Xtensions)) {
      89           0 :                 GF_X_Attribute *att = (GF_X_Attribute*)gf_list_get(com->Xtensions, 0);
      90           0 :                 gf_list_rem(com->Xtensions, 0);
      91           0 :                 gf_free(att->Name);
      92           0 :                 gf_free(att->Value);
      93           0 :                 gf_free(att);
      94             :         }
      95             : }
      96             : 
      97             : GF_EXPORT
      98          77 : void gf_rtsp_command_del(GF_RTSPCommand *com)
      99             : {
     100          77 :         if (!com) return;
     101          55 :         gf_rtsp_command_reset(com);
     102          55 :         gf_list_del(com->Xtensions);
     103          55 :         gf_list_del(com->Transports);
     104          55 :         gf_free(com);
     105             : }
     106             : 
     107             : 
     108          28 : GF_Err RTSP_WriteCommand(GF_RTSPSession *sess, GF_RTSPCommand *com, unsigned char *req_buffer,
     109             :                          unsigned char **out_buffer, u32 *out_size)
     110             : {
     111             :         u32 i, cur_pos, size, count;
     112             :         char *buffer;
     113             : 
     114          28 :         *out_buffer = NULL;
     115             :         
     116             :         size = RTSP_WRITE_STEPALLOC;
     117          28 :         buffer = (char *) gf_malloc(size);
     118             :         cur_pos = 0;
     119             : 
     120             :         //request
     121          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, req_buffer);
     122             : 
     123             :         //then all headers
     124          48 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept", com->Accept);
     125          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept-Encoding", com->Accept_Encoding);
     126         140 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Accept-Language", com->Accept_Language);
     127          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Authorization", com->Authorization);
     128          28 :         if (com->Bandwidth) {
     129           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Bandwidth: ");
     130           0 :                 RTSP_WRITE_INT(buffer, size, cur_pos, com->Bandwidth, 0);
     131           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     132             :         }
     133          28 :         if (com->Blocksize) {
     134           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Blocksize: ");
     135           0 :                 RTSP_WRITE_INT(buffer, size, cur_pos, com->Blocksize, 0);
     136           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     137             :         }
     138          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Cache-Control", com->Cache_Control);
     139          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Conference", com->Conference);
     140          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Connection", com->Connection);
     141             :         //if we have a body write the content length
     142          28 :         if (com->body) {
     143           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Content-Length: ");
     144           0 :                 RTSP_WRITE_INT(buffer, size, cur_pos, (u32) strlen(com->body), 0);
     145           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     146             :         }
     147             :         //write the CSeq - use the SESSION CSeq
     148          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "CSeq: ");
     149          84 :         RTSP_WRITE_INT(buffer, size, cur_pos, sess->CSeq, 0);
     150          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     151             : 
     152          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "From", com->From);
     153          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Proxy-Authorization", com->Proxy_Authorization);
     154          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Proxy-Require", com->Proxy_Require);
     155             : 
     156             :         //Range, only NPT
     157          28 :         if (com->Range && !com->Range->UseSMPTE) {
     158          24 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Range: npt=");
     159          36 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, com->Range->start);
     160          24 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     161          12 :                 if (com->Range->end > com->Range->start) {
     162           0 :                         RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, com->Range->end);
     163             :                 }
     164          24 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     165             :         }
     166             : 
     167          28 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Referer", com->Referer);
     168          28 :         if (com->Scale != 0.0) {
     169           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Scale: ");
     170           0 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, com->Scale);
     171           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     172             :         }
     173         100 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "Session", com->Session);
     174          28 :         if (com->Speed != 0.0) {
     175           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Speed: ");
     176           0 :                 RTSP_WRITE_FLOAT_WITHOUT_CHECK(buffer, size, cur_pos, com->Speed);
     177           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     178             :         }
     179             : 
     180             :         //transport info
     181          28 :         count = gf_list_count(com->Transports);
     182          28 :         if (count) {
     183          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "Transport: ");
     184          12 :                 for (i=0; i<count; i++) {
     185             :                         GF_RTSPTransport *trans;
     186             :                         //line separator for headers
     187           6 :                         if (i) RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n ,");
     188           6 :                         trans = (GF_RTSPTransport *) gf_list_get(com->Transports, i);
     189             : 
     190             :                         //then write the structure
     191          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->Profile);
     192          12 :                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, (trans->IsUnicast ? ";unicast" : ";multicast"));
     193           6 :                         if (trans->destination) {
     194           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";destination=");
     195           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->destination);
     196             :                         }
     197           6 :                         if (trans->source) {
     198           0 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";source=");
     199           0 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, trans->source);
     200             :                         }
     201           6 :                         if (trans->IsRecord) {
     202           0 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";mode=RECORD");
     203           0 :                                 if (trans->Append) RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";append");
     204             :                         }
     205           6 :                         if (trans->IsInterleaved) {
     206           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";interleaved=");
     207           3 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->rtpID, 0);
     208           1 :                                 if (trans->rtcpID != trans->rtpID) {
     209           2 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     210           3 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->rtcpID, 0);
     211             :                                 }
     212             :                         }
     213           6 :                         if (trans->port_first) {
     214           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, (trans->IsUnicast ? ";server_port=" : ";port="));
     215           3 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->port_first, 0);
     216           2 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     217           3 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->port_last, 0);
     218             :                         }
     219           6 :                         if (/*trans->IsUnicast && */trans->client_port_first) {
     220          10 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";client_port=");
     221          15 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->client_port_first, 0);
     222          10 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "-");
     223          15 :                                 RTSP_WRITE_INT(buffer, size, cur_pos, trans->client_port_last, 0);
     224             :                         }
     225             :                         //multicast specific
     226           6 :                         if (!trans->IsUnicast) {
     227           1 :                                 if (trans->MulticastLayers) {
     228           0 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";layers=");
     229           0 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->MulticastLayers, 0);
     230             :                                 }
     231           1 :                                 if (trans->TTL) {
     232           2 :                                         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";ttl=");
     233           3 :                                         RTSP_WRITE_INT(buffer, size, cur_pos, trans->TTL, 0);
     234             :                                 }
     235             :                         }
     236           6 :                         if (trans->SSRC) {
     237           0 :                                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, ";ssrc=");
     238           0 :                                 RTSP_WRITE_HEX(buffer, size, cur_pos, trans->SSRC, 0);
     239             :                         }
     240             :                 }
     241             :                 //done with transport
     242          12 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     243             :         }
     244         140 :         RTSP_WRITE_HEADER(buffer, size, cur_pos, "User-Agent", com->User_Agent);
     245             : 
     246             :         //eXtensions
     247          28 :         count = gf_list_count(com->Xtensions);
     248          28 :         for (i=0; i<count; i++) {
     249           0 :                 GF_X_Attribute *att = (GF_X_Attribute *) gf_list_get(com->Xtensions, i);
     250           0 :                 RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "x-");
     251           0 :                 RTSP_WRITE_HEADER(buffer, size, cur_pos, att->Name, att->Value);
     252             :         }
     253             : 
     254             :         //the end of header
     255          56 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     256             :         //then body
     257          28 :         RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, com->body);
     258             :         //the end of message ? to check, should not be needed...
     259             : //      RTSP_WRITE_ALLOC_STR(buffer, size, cur_pos, "\r\n");
     260             : 
     261          28 :         *out_buffer = (unsigned char *)buffer;
     262          28 :         *out_size = (u32) strlen(buffer);
     263          28 :         return GF_OK;
     264             : }
     265             : 
     266             : 
     267             : //format a DESCRIBE, SETUP, PLAY or PAUSE on a session
     268             : //YOUR COMMAND MUST BE FORMATTED ACCORDINGLY
     269             : //sCtrl contains a control string if needed, formatting the REQUEST as server_url/service_name/sCtrl
     270             : GF_EXPORT
     271          28 : GF_Err gf_rtsp_send_command(GF_RTSPSession *sess, GF_RTSPCommand *com)
     272             : {
     273             :         GF_Err e;
     274             :         char *sCtrl;
     275             :         const char *rad;
     276             :         u32 size;
     277             :         char buffer[1024], *result, *body;
     278             : 
     279          28 :         if (!com || !com->method) return GF_BAD_PARAM;
     280             : 
     281          28 :         sCtrl = com->ControlString;
     282             : 
     283             :         //NB: OPTIONS is not sent this way
     284          28 :         if (strcmp(com->method, GF_RTSP_DESCRIBE)
     285          23 :                 && strcmp(com->method, GF_RTSP_ANNOUNCE)
     286          23 :                 && strcmp(com->method, GF_RTSP_GET_PARAMETER)
     287          23 :                 && strcmp(com->method, GF_RTSP_SET_PARAMETER)
     288          23 :                 && strcmp(com->method, GF_RTSP_SETUP)
     289          17 :                 && strcmp(com->method, GF_RTSP_PLAY)
     290          11 :                 && strcmp(com->method, GF_RTSP_PAUSE)
     291           5 :                 && strcmp(com->method, GF_RTSP_RECORD)
     292           5 :                 && strcmp(com->method, GF_RTSP_REDIRECT)
     293           5 :                 && strcmp(com->method, GF_RTSP_TEARDOWN)
     294           0 :                 && strcmp(com->method, GF_RTSP_OPTIONS)
     295             : 
     296             :            ) return GF_BAD_PARAM;
     297             : 
     298             :         //check the state machine
     299          28 :         if (strcmp(com->method, GF_RTSP_PLAY)
     300          22 :                 && strcmp(com->method, GF_RTSP_PAUSE)
     301          16 :                 && strcmp(com->method, GF_RTSP_RECORD)
     302          16 :                 && sess->RTSP_State != GF_RTSP_STATE_INIT)
     303             :                 return GF_SERVICE_ERROR;
     304             : 
     305             :         //aggregation is ONLY for the same request - unclear in RFC2326 ...
     306             :         //it is often mentioned "queued requests" at the server, like 3 PLAYS
     307             :         //and a PAUSE ....
     308             : 
     309             :         /*
     310             :         else if (sess->RTSP_State == GF_RTSP_STATE_WAIT_FOR_CONTROL
     311             :                 && strcmp(com->method, sess->RTSPLastRequest))
     312             :                 && strcmp(com->method, GF_RTSP_OPTIONS))
     313             : 
     314             :                 return GF_BAD_PARAM;
     315             :         */
     316             : 
     317             :         //OPTIONS must have a parameter string
     318          28 :         if (!strcmp(com->method, GF_RTSP_OPTIONS) && !sCtrl) return GF_BAD_PARAM;
     319             : 
     320             : 
     321             :         //update sequence number
     322          28 :         sess->CSeq += 1;
     323          28 :         sess->NbPending += 1;
     324             : 
     325          28 :         if (!strcmp(com->method, GF_RTSP_OPTIONS)) {
     326             :                 sprintf(buffer, "OPTIONS %s %s\r\n", sCtrl, GF_RTSP_VERSION);
     327             :         } else {
     328          28 :                 rad = (sess->ConnectionType == GF_SOCK_TYPE_TCP) ? "rtsp" : "rtspu";
     329          28 :                 if (sCtrl) {
     330             :                         //if both server and service names are included in the control, just
     331             :                         //use the control
     332          12 :                         if (strstr(sCtrl, sess->Server) && strstr(sCtrl, sess->Service)) {
     333             :                                 sprintf(buffer, "%s %s %s\r\n", com->method, sCtrl, GF_RTSP_VERSION);
     334             :                         }
     335             :                         //if service is specified in ctrl, do not rewrite it
     336          12 :                         else if (strstr(sCtrl, sess->Service)) {
     337           0 :                                 sprintf(buffer, "%s %s://%s:%d/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sCtrl, GF_RTSP_VERSION);
     338             :                         }
     339          12 :                         else if (!strnicmp(sCtrl, "rtsp", 4)) {
     340             :                                 sprintf(buffer, "%s %s %s\r\n", com->method, sCtrl, GF_RTSP_VERSION);
     341             :                         }
     342             :                         //otherwise rewrite full URL
     343             :                         else {
     344             :                                 sprintf(buffer, "%s %s://%s/%s/%s %s\r\n", com->method, rad, sess->Server, sess->Service, sCtrl, GF_RTSP_VERSION);
     345             : //                              sprintf(buffer, "%s %s://%s:%d/%s/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, sCtrl, GF_RTSP_VERSION);
     346             :                         }
     347             :                 } else {
     348          16 :                         sprintf(buffer, "%s %s://%s:%d/%s %s\r\n", com->method, rad, sess->Server, sess->Port, sess->Service, GF_RTSP_VERSION);
     349             :                 }
     350             :         }
     351             : 
     352             :         //Body on ANNOUNCE, GET_PARAMETER, SET_PARAMETER ONLY
     353             :         body = NULL;
     354          28 :         if (strcmp(com->method, GF_RTSP_ANNOUNCE)
     355          28 :                 && strcmp(com->method, GF_RTSP_GET_PARAMETER)
     356          28 :                 && strcmp(com->method, GF_RTSP_SET_PARAMETER)
     357             :            ) {
     358             :                 //this is an error, but don't say anything
     359          28 :                 if (com->body) {
     360             :                         body = com->body;
     361           0 :                         com->body = NULL;
     362             :                 }
     363             :         }
     364             : 
     365          28 :         result = NULL;
     366          28 :         e = RTSP_WriteCommand(sess, com, (unsigned char *)buffer, (unsigned char **) &result, &size);
     367             :         //restore body if needed
     368          28 :         if (body) com->body = body;
     369          28 :         if (e) goto exit;
     370             : 
     371             : 
     372          28 :         GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSP] Sending Command:\n%s\n", result));
     373             : 
     374             :         //send buffer
     375          28 :         e = gf_rtsp_send_data(sess, result, size);
     376          28 :         if (e) goto exit;
     377             : 
     378             : 
     379             :         //update our state
     380          28 :         if (!strcmp(com->method, GF_RTSP_RECORD)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL;
     381          28 :         else if (!strcmp(com->method, GF_RTSP_PLAY)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL;
     382          22 :         else if (!strcmp(com->method, GF_RTSP_PAUSE)) sess->RTSP_State = GF_RTSP_STATE_WAIT_FOR_CONTROL;
     383          16 :         else sess->RTSP_State = GF_RTSP_STATE_WAITING;
     384             :         //teardown invalidates the session most of the time, so we force the user to wait for the reply
     385             :         //as the reply may indicate a connection-closed
     386          28 :         strcpy(sess->RTSPLastRequest, com->method);
     387             : 
     388          28 : exit:
     389          28 :         if (result) gf_free(result);
     390             :         return e;
     391             : }
     392             : 
     393             : 
     394         125 : void gf_rtsp_set_command_value(GF_RTSPCommand *com, char *Header, char *Value)
     395             : {
     396             :         char LineBuffer[400];
     397             :         s32 LinePos;
     398             :         GF_RTSPTransport *trans;
     399             :         GF_X_Attribute *x_Att;
     400             : 
     401         125 :         if (!stricmp(Header, "Accept")) com->Accept = gf_strdup(Value);
     402         120 :         else if (!stricmp(Header, "Accept-Encoding")) com->Accept_Encoding = gf_strdup(Value);
     403         120 :         else if (!stricmp(Header, "Accept-Language")) com->Accept_Language = gf_strdup(Value);
     404          92 :         else if (!stricmp(Header, "Authorization")) com->Authorization = gf_strdup(Value);
     405          92 :         else if (!stricmp(Header, "Bandwidth")) sscanf(Value, "%u", &com->Bandwidth);
     406          92 :         else if (!stricmp(Header, "Blocksize")) sscanf(Value, "%u", &com->Blocksize);
     407          92 :         else if (!stricmp(Header, "Cache-Control")) com->Cache_Control = gf_strdup(Value);
     408          92 :         else if (!stricmp(Header, "Conference")) com->Conference = gf_strdup(Value);
     409          92 :         else if (!stricmp(Header, "Connection")) com->Connection = gf_strdup(Value);
     410          92 :         else if (!stricmp(Header, "Content-Length")) sscanf(Value, "%u", &com->Content_Length);
     411          92 :         else if (!stricmp(Header, "CSeq")) sscanf(Value, "%u", &com->CSeq);
     412          64 :         else if (!stricmp(Header, "From")) com->From = gf_strdup(Value);
     413          64 :         else if (!stricmp(Header, "Proxy_Authorization")) com->Proxy_Authorization = gf_strdup(Value);
     414          64 :         else if (!stricmp(Header, "Proxy_Require")) com->Proxy_Require = gf_strdup(Value);
     415          64 :         else if (!stricmp(Header, "Range")) com->Range = gf_rtsp_range_parse(Value);
     416          52 :         else if (!stricmp(Header, "Referer")) com->Referer = gf_strdup(Value);
     417          52 :         else if (!stricmp(Header, "Scale")) sscanf(Value, "%lf", &com->Scale);
     418          52 :         else if (!stricmp(Header, "Session"))
     419          18 :                 com->Session = gf_strdup(Value);
     420          34 :         else if (!stricmp(Header, "Speed")) sscanf(Value, "%lf", &com->Speed);
     421          34 :         else if (!stricmp(Header, "User_Agent")) com->User_Agent = gf_strdup(Value);
     422             :         //Transports
     423          34 :         else if (!stricmp(Header, "Transport")) {
     424             :                 LinePos = 0;
     425             :                 while (1) {
     426          12 :                         LinePos = gf_token_get(Value, LinePos, "\r\n", LineBuffer, 400);
     427          18 :                         if (LinePos <= 0) return;
     428           6 :                         trans = gf_rtsp_transport_parse(Value);
     429           6 :                         if (trans) gf_list_add(com->Transports, trans);
     430             :                 }
     431             :         }
     432             :         //eXtensions attributes
     433          28 :         else if (!strnicmp(Header, "x-", 2)) {
     434           0 :                 x_Att = (GF_X_Attribute*)gf_malloc(sizeof(GF_X_Attribute));
     435           0 :                 x_Att->Name = gf_strdup(Header+2);
     436           0 :                 x_Att->Value = NULL;
     437           0 :                 if (Value && strlen(Value)) x_Att->Value = gf_strdup(Value);
     438           0 :                 gf_list_add(com->Xtensions, x_Att);
     439             :         }
     440             :         //the rest is ignored
     441             : }
     442             : 
     443          28 : GF_Err RTSP_ParseCommandHeader(GF_RTSPSession *sess, GF_RTSPCommand *com, u32 BodyStart)
     444             : {
     445             :         char LineBuffer[1024];
     446             :         char ValBuf[1024];
     447             :         char *buffer;
     448             :         s32 Pos, ret;
     449             :         u32 Size;
     450             : 
     451          28 :         Size = sess->CurrentSize - sess->CurrentPos;
     452          28 :         buffer = sess->tcp_buffer + sess->CurrentPos;
     453             : 
     454             :         //by default the command is wrong ;)
     455          28 :         com->StatusCode = NC_RTSP_Bad_Request;
     456             : 
     457             :         //parse first line
     458          28 :         ret = gf_token_get_line(buffer, 0, Size, LineBuffer, 1024);
     459          28 :         if (ret < 0) return GF_REMOTE_SERVICE_ERROR;
     460             : 
     461             :         //method
     462          28 :         Pos = gf_token_get(LineBuffer, 0, " \t\r\n", ValBuf, 1024);
     463          28 :         if (Pos <= 0) return GF_OK;
     464          28 :         com->method = gf_strdup((const char *) ValBuf);
     465             : 
     466             :         //URL
     467          28 :         Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 1024);
     468          28 :         if (Pos <= 0) return GF_OK;
     469          28 :         com->service_name = gf_strdup(ValBuf);
     470             : 
     471             :         //RTSP version
     472          28 :         Pos = gf_token_get(LineBuffer, Pos, " \t\r\n", ValBuf, 1024);
     473          28 :         if (Pos <= 0) return GF_OK;
     474          28 :         if (strcmp(ValBuf, GF_RTSP_VERSION)) {
     475           0 :                 com->StatusCode = NC_RTSP_RTSP_Version_Not_Supported;
     476           0 :                 return GF_OK;
     477             :         }
     478             : 
     479          28 :         com->StatusCode = NC_RTSP_OK;
     480             : 
     481          28 :         return gf_rtsp_parse_header(buffer + ret, Size - ret, BodyStart, com, NULL);
     482             : }
     483             : 
     484             : char *RTSP_DEFINED_METHODS[] =
     485             : {
     486             :         GF_RTSP_DESCRIBE,
     487             :         GF_RTSP_SETUP,
     488             :         GF_RTSP_PLAY,
     489             :         GF_RTSP_PAUSE,
     490             :         GF_RTSP_RECORD,
     491             :         GF_RTSP_TEARDOWN,
     492             :         GF_RTSP_GET_PARAMETER,
     493             :         GF_RTSP_SET_PARAMETER,
     494             :         GF_RTSP_OPTIONS,
     495             :         GF_RTSP_ANNOUNCE,
     496             :         GF_RTSP_REDIRECT,
     497             :         NULL
     498             : };
     499             : 
     500             : GF_EXPORT
     501         418 : GF_Err gf_rtsp_get_command(GF_RTSPSession *sess, GF_RTSPCommand *com)
     502             : {
     503             :         GF_Err e;
     504             :         u32 BodyStart, size;
     505         418 :         if (!sess || !com) return GF_BAD_PARAM;
     506             : 
     507             :         //reset the command
     508         418 :         gf_rtsp_command_reset(com);
     509             :         //if no connection, we have sent a "Connection: Close"
     510         418 :         if (!sess->connection) return GF_IP_CONNECTION_CLOSED;
     511             : 
     512             :         //lock
     513             :         //fill TCP buffer
     514         418 :         e = gf_rtsp_fill_buffer(sess);
     515         418 :         if (e) goto exit;
     516          28 :         if (sess->TCPChannels)
     517             :         //this is upcoming, interleaved data
     518          28 :         if (sess->interleaved) {
     519             :                 u32 i=0;
     520             :                 Bool sync = GF_FALSE;
     521           0 :                 while (RTSP_DEFINED_METHODS[i]) {
     522           0 :                         if (!strncmp(sess->tcp_buffer+sess->CurrentPos, RTSP_DEFINED_METHODS[i], strlen(RTSP_DEFINED_METHODS[i]) ) ) {
     523             :                                 sync = GF_TRUE;
     524             :                                 break;
     525             :                         }
     526             :                 }
     527           0 :                 if (!sync) {
     528             :                         e = GF_IP_NETWORK_EMPTY;
     529             :                         goto exit;
     530             :                 }
     531             :         }
     532          28 :         e = gf_rtsp_read_reply(sess);
     533          28 :         if (e) goto exit;
     534             : 
     535          28 :         GF_LOG(GF_LOG_INFO, GF_LOG_RTP, ("[RTSP] Got Command:\n%s\n", sess->tcp_buffer+sess->CurrentPos));
     536             : 
     537          28 :         gf_rtsp_get_body_info(sess, &BodyStart, &size);
     538          28 :         e = RTSP_ParseCommandHeader(sess, com, BodyStart);
     539             :         //before returning an error we MUST reset the TCP buffer
     540             : 
     541             :         //copy the body if any
     542          28 :         if (!e && com->Content_Length) {
     543           0 :                 com->body = (char *) gf_malloc(sizeof(char) * (com->Content_Length));
     544           0 :                 memcpy(com->body, sess->tcp_buffer+sess->CurrentPos + BodyStart, com->Content_Length);
     545             :         }
     546             :         //reset TCP buffer
     547          28 :         sess->CurrentPos += BodyStart + com->Content_Length;
     548             : 
     549          28 :         if (!com->CSeq)
     550           0 :                 com->StatusCode = NC_RTSP_Bad_Request;
     551             : 
     552          56 :         if (e || (com->StatusCode != NC_RTSP_OK)) goto exit;
     553             : 
     554             :         //NB: there is no "session state" in our lib when acting at the server side, as it depends
     555             :         //on the server implementation. We cannot block responses / announcement to be sent
     556             :         //dynamically, nor reset the session ourselves as we don't know the details of the session
     557             :         //(eg TEARDOWN may keep resources up or not, ...)
     558             : 
     559             :         //we also have the same pb for CSeq, as nothing forbids a server to buffer commands (and it
     560             :         //happens during aggregation of PLAY/PAUSE with overlapping ranges)
     561             : 
     562             :         //however store the last CSeq in case for client checking
     563          28 :         if (!sess->CSeq) {
     564          25 :                 sess->CSeq = com->CSeq;
     565             :         }
     566             :         //check we're in the right range
     567             :         else {
     568           3 :                 if (sess->CSeq >= com->CSeq)
     569           0 :                         com->StatusCode = NC_RTSP_Header_Field_Not_Valid;
     570             :                 else
     571           3 :                         sess->CSeq = com->CSeq;
     572             :         }
     573             : 
     574             :         //
     575             :         //if a connection closed is signal, check this is the good session
     576             :         // and reset it (the client is no longer connected)
     577          28 :         if (sess->last_session_id && com->Session && !strcmp(com->Session, sess->last_session_id)
     578           0 :                 && com->Connection && !stricmp(com->Connection, "Close")) {
     579             : 
     580           0 :                 gf_rtsp_session_reset(sess, GF_FALSE);
     581             :                 //destroy the socket
     582           0 :                 if (sess->connection) gf_sk_del(sess->connection);
     583           0 :                 sess->connection = NULL;
     584             : 
     585             :                 //destroy the http tunnel if any
     586           0 :                 if (sess->HasTunnel && sess->http) {
     587           0 :                         gf_sk_del(sess->http);
     588           0 :                         sess->http = NULL;
     589             :                 }
     590             :         }
     591             : 
     592         418 : exit:
     593             :         return e;
     594             : }
     595             : 
     596             : #endif /*GPAC_DISABLE_STREAMING*/

Generated by: LCOV version 1.13