summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/rtsp.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2023-05-30 13:38:38 (GMT)
committerBrad King <brad.king@kitware.com>2023-05-30 13:39:43 (GMT)
commita6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d (patch)
tree23bfdb5c7a2254a82571a4acb78b5a25c1641898 /Utilities/cmcurl/lib/rtsp.c
parent7f1abf62e12a261a2fc91a2d527b5c4a30e25d41 (diff)
parent80cb6a512119ea6f8f8cf480c78e1e32d494e6ca (diff)
downloadCMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.zip
CMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.tar.gz
CMake-a6c9b53273eb3ef8b4d9a0a2a0fc6a4822211b9d.tar.bz2
Merge branch 'upstream-curl' into update-curl
* upstream-curl: curl 2023-05-30 (7ab9d437)
Diffstat (limited to 'Utilities/cmcurl/lib/rtsp.c')
-rw-r--r--Utilities/cmcurl/lib/rtsp.c242
1 files changed, 158 insertions, 84 deletions
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
index aef3560..ccd7264 100644
--- a/Utilities/cmcurl/lib/rtsp.c
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -45,8 +45,6 @@
#include "curl_memory.h"
#include "memdebug.h"
-#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1])))
-
#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
((int)((unsigned char)((p)[3]))))
@@ -91,6 +89,8 @@ static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
static
CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len);
+static
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport);
/*
@@ -119,6 +119,7 @@ const struct Curl_handler Curl_handler_rtsp = {
PROTOPT_NONE /* flags */
};
+#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
@@ -130,6 +131,7 @@ static CURLcode rtsp_setup_connection(struct Curl_easy *data,
if(!rtsp)
return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&conn->proto.rtspc.buf, MAX_RTP_BUFFERSIZE);
return CURLE_OK;
}
@@ -176,7 +178,7 @@ static CURLcode rtsp_disconnect(struct Curl_easy *data,
{
(void) dead;
(void) data;
- Curl_safefree(conn->proto.rtspc.rtp_buf);
+ Curl_dyn_free(&conn->proto.rtspc.buf);
return CURLE_OK;
}
@@ -204,7 +206,7 @@ static CURLcode rtsp_done(struct Curl_easy *data,
return CURLE_RTSP_CSEQ_ERROR;
}
if(data->set.rtspreq == RTSPREQ_RECEIVE &&
- (data->conn->proto.rtspc.rtp_channel == -1)) {
+ (data->conn->proto.rtspc.rtp_channel == -1)) {
infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
}
}
@@ -374,7 +376,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
if(Curl_checkheaders(data, STRCONST("User-Agent")) &&
data->state.aptr.uagent) {
Curl_safefree(data->state.aptr.uagent);
- data->state.aptr.uagent = NULL;
}
else if(!Curl_checkheaders(data, STRCONST("User-Agent")) &&
data->set.str[STRING_USERAGENT]) {
@@ -394,8 +395,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
Curl_safefree(data->state.aptr.ref);
if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer")))
data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
- else
- data->state.aptr.ref = NULL;
p_referrer = data->state.aptr.ref;
@@ -476,7 +475,6 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
* with basic and digest, it will be freed anyway by the next request
*/
Curl_safefree(data->state.aptr.userpwd);
- data->state.aptr.userpwd = NULL;
if(result)
return result;
@@ -495,7 +493,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) {
- if(data->set.upload) {
+ if(data->state.upload) {
putsize = data->state.infilesize;
data->state.httpreq = HTTPREQ_PUT;
@@ -514,7 +512,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
result =
Curl_dyn_addf(&req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
- (data->set.upload ? putsize : postsize));
+ (data->state.upload ? putsize : postsize));
if(result)
return result;
}
@@ -594,26 +592,20 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
bool *readmore) {
struct SingleRequest *k = &data->req;
struct rtsp_conn *rtspc = &(conn->proto.rtspc);
+ unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
char *rtp; /* moving pointer to rtp data */
ssize_t rtp_dataleft; /* how much data left to parse in this round */
- char *scratch;
CURLcode result;
+ bool interleaved = false;
+ size_t skip_size = 0;
- if(rtspc->rtp_buf) {
- /* There was some leftover data the last time. Merge buffers */
- char *newptr = Curl_saferealloc(rtspc->rtp_buf,
- rtspc->rtp_bufsize + *nread);
- if(!newptr) {
- rtspc->rtp_buf = NULL;
- rtspc->rtp_bufsize = 0;
+ if(Curl_dyn_len(&rtspc->buf)) {
+ /* There was some leftover data the last time. Append new buffers */
+ if(Curl_dyn_addn(&rtspc->buf, k->str, *nread))
return CURLE_OUT_OF_MEMORY;
- }
- rtspc->rtp_buf = newptr;
- memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread);
- rtspc->rtp_bufsize += *nread;
- rtp = rtspc->rtp_buf;
- rtp_dataleft = rtspc->rtp_bufsize;
+ rtp = Curl_dyn_ptr(&rtspc->buf);
+ rtp_dataleft = Curl_dyn_len(&rtspc->buf);
}
else {
/* Just parse the request buffer directly */
@@ -621,71 +613,107 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
rtp_dataleft = *nread;
}
- while((rtp_dataleft > 0) &&
- (rtp[0] == '$')) {
- if(rtp_dataleft > 4) {
- int rtp_length;
+ while(rtp_dataleft > 0) {
+ if(rtp[0] == '$') {
+ if(rtp_dataleft > 4) {
+ unsigned char rtp_channel;
+ int rtp_length;
+ int idx;
+ int off;
+
+ /* Parse the header */
+ /* The channel identifier immediately follows and is 1 byte */
+ rtp_channel = (unsigned char)rtp[1];
+ idx = rtp_channel / 8;
+ off = rtp_channel % 8;
+ if(!(rtp_channel_mask[idx] & (1 << off))) {
+ /* invalid channel number, maybe not an RTP packet */
+ rtp++;
+ rtp_dataleft--;
+ skip_size++;
+ continue;
+ }
+ if(skip_size > 0) {
+ DEBUGF(infof(data, "Skip the malformed interleaved data %lu "
+ "bytes", skip_size));
+ }
+ skip_size = 0;
+ rtspc->rtp_channel = rtp_channel;
- /* Parse the header */
- /* The channel identifier immediately follows and is 1 byte */
- rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp);
+ /* The length is two bytes */
+ rtp_length = RTP_PKT_LENGTH(rtp);
- /* The length is two bytes */
- rtp_length = RTP_PKT_LENGTH(rtp);
+ if(rtp_dataleft < rtp_length + 4) {
+ /* Need more - incomplete payload */
+ *readmore = TRUE;
+ break;
+ }
+ interleaved = true;
+ /* We have the full RTP interleaved packet
+ * Write out the header including the leading '$' */
+ DEBUGF(infof(data, "RTP write channel %d rtp_length %d",
+ rtspc->rtp_channel, rtp_length));
+ result = rtp_client_write(data, &rtp[0], rtp_length + 4);
+ if(result) {
+ *readmore = FALSE;
+ return result;
+ }
+
+ /* Move forward in the buffer */
+ rtp_dataleft -= rtp_length + 4;
+ rtp += rtp_length + 4;
- if(rtp_dataleft < rtp_length + 4) {
- /* Need more - incomplete payload */
+ if(data->set.rtspreq == RTSPREQ_RECEIVE) {
+ /* If we are in a passive receive, give control back
+ * to the app as often as we can.
+ */
+ k->keepon &= ~KEEP_RECV;
+ }
+ }
+ else {
+ /* Need more - incomplete header */
*readmore = TRUE;
break;
}
- /* We have the full RTP interleaved packet
- * Write out the header including the leading '$' */
- DEBUGF(infof(data, "RTP write channel %d rtp_length %d",
- rtspc->rtp_channel, rtp_length));
- result = rtp_client_write(data, &rtp[0], rtp_length + 4);
- if(result) {
- failf(data, "Got an error writing an RTP packet");
- *readmore = FALSE;
- Curl_safefree(rtspc->rtp_buf);
- rtspc->rtp_buf = NULL;
- rtspc->rtp_bufsize = 0;
- return result;
- }
-
- /* Move forward in the buffer */
- rtp_dataleft -= rtp_length + 4;
- rtp += rtp_length + 4;
-
- if(data->set.rtspreq == RTSPREQ_RECEIVE) {
- /* If we are in a passive receive, give control back
- * to the app as often as we can.
- */
- k->keepon &= ~KEEP_RECV;
- }
}
else {
- /* Need more - incomplete header */
- *readmore = TRUE;
- break;
+ /* If the following data begins with 'RTSP/', which might be an RTSP
+ message, we should stop skipping the data. */
+ /* If `k-> headerline> 0 && !interleaved` is true, we are maybe in the
+ middle of an RTSP message. It is difficult to determine this, so we
+ stop skipping. */
+ size_t prefix_len = (rtp_dataleft < 5) ? rtp_dataleft : 5;
+ if((k->headerline > 0 && !interleaved) ||
+ strncmp(rtp, "RTSP/", prefix_len) == 0) {
+ if(skip_size > 0) {
+ DEBUGF(infof(data, "Skip the malformed interleaved data %lu "
+ "bytes", skip_size));
+ }
+ break; /* maybe is an RTSP message */
+ }
+ /* Skip incorrect data util the next RTP packet or RTSP message */
+ do {
+ rtp++;
+ rtp_dataleft--;
+ skip_size++;
+ } while(rtp_dataleft > 0 && rtp[0] != '$' && rtp[0] != 'R');
}
}
if(rtp_dataleft && rtp[0] == '$') {
DEBUGF(infof(data, "RTP Rewinding %zd %s", rtp_dataleft,
- *readmore ? "(READMORE)" : ""));
+ *readmore ? "(READMORE)" : ""));
/* Store the incomplete RTP packet for a "rewind" */
- scratch = malloc(rtp_dataleft);
- if(!scratch) {
- Curl_safefree(rtspc->rtp_buf);
- rtspc->rtp_buf = NULL;
- rtspc->rtp_bufsize = 0;
- return CURLE_OUT_OF_MEMORY;
+ if(!Curl_dyn_len(&rtspc->buf)) {
+ /* nothing was stored, add this data */
+ if(Curl_dyn_addn(&rtspc->buf, rtp, rtp_dataleft))
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ /* keep the remainder */
+ Curl_dyn_tail(&rtspc->buf, rtp_dataleft);
}
- memcpy(scratch, rtp, rtp_dataleft);
- Curl_safefree(rtspc->rtp_buf);
- rtspc->rtp_buf = scratch;
- rtspc->rtp_bufsize = rtp_dataleft;
/* As far as the transfer is concerned, this data is consumed */
*nread = 0;
@@ -694,20 +722,10 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
/* Fix up k->str to point just after the last RTP packet */
k->str += *nread - rtp_dataleft;
- /* either all of the data has been read or...
- * rtp now points at the next byte to parse
- */
- if(rtp_dataleft > 0)
- DEBUGASSERT(k->str[0] == rtp[0]);
-
- DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */
-
*nread = rtp_dataleft;
/* If we get here, we have finished with the leftover/merge buffer */
- Curl_safefree(rtspc->rtp_buf);
- rtspc->rtp_buf = NULL;
- rtspc->rtp_bufsize = 0;
+ Curl_dyn_free(&rtspc->buf);
return CURLE_OK;
}
@@ -822,7 +840,63 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
(data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
}
}
+ else if(checkprefix("Transport:", header)) {
+ CURLcode result;
+ result = rtsp_parse_transport(data, header + 10);
+ if(result)
+ return result;
+ }
return CURLE_OK;
}
+static
+CURLcode rtsp_parse_transport(struct Curl_easy *data, char *transport)
+{
+ /* If we receive multiple Transport response-headers, the linterleaved
+ channels of each response header is recorded and used together for
+ subsequent data validity checks.*/
+ /* e.g.: ' RTP/AVP/TCP;unicast;interleaved=5-6' */
+ char *start;
+ char *end;
+ start = transport;
+ while(start && *start) {
+ while(*start && ISBLANK(*start) )
+ start++;
+ end = strchr(start, ';');
+ if(checkprefix("interleaved=", start)) {
+ long chan1, chan2, chan;
+ char *endp;
+ char *p = start + 12;
+ chan1 = strtol(p, &endp, 10);
+ if(p != endp && chan1 >= 0 && chan1 <= 255) {
+ unsigned char *rtp_channel_mask = data->state.rtp_channel_mask;
+ chan2 = chan1;
+ if(*endp == '-') {
+ p = endp + 1;
+ chan2 = strtol(p, &endp, 10);
+ if(p == endp || chan2 < 0 || chan2 > 255) {
+ infof(data, "Unable to read the interleaved parameter from "
+ "Transport header: [%s]", transport);
+ chan2 = chan1;
+ }
+ }
+ for(chan = chan1; chan <= chan2; chan++) {
+ long idx = chan / 8;
+ long off = chan % 8;
+ rtp_channel_mask[idx] |= (unsigned char)(1 << off);
+ }
+ }
+ else {
+ infof(data, "Unable to read the interleaved parameter from "
+ "Transport header: [%s]", transport);
+ }
+ break;
+ }
+ /* skip to next parameter */
+ start = (!end) ? end : (end + 1);
+ }
+ return CURLE_OK;
+}
+
+
#endif /* CURL_DISABLE_RTSP or using Hyper */