Loading docs/libcurl/curl_easy_setopt.3 +2 −6 Original line number Diff line number Diff line Loading @@ -411,7 +411,7 @@ interleaved header as well as the included data for each call. The first byte is always an ASCII dollar sign. The dollar sign is followed by a one byte channel identifier and then a 2 byte integer length in network byte order. See \fIRFC 2326 Section 10.12\fP for more information on how RTP interleaving behaves. behaves. If unset or set to NULL, curl will use the default write function. Interleaved RTP poses some challeneges for the client application. Since the stream data is sharing the RTSP control connection, it is critical to service Loading @@ -424,11 +424,7 @@ process any pending RTP data before marking the request as finished. (Added in 7.20.0) .IP CURLOPT_INTERLEAVEDATA This is the stream that will be passed to \fICURLOPT_INTERLEAVEFUNCTION\fP when interleaved RTP data is received. Since the application is required to provide a custom function for RTP data, there is no requirement that the stream pointer be a valid FILE pointer. An application may wish to pass a cookie containing information about many streams to assist in demultiplexing the different RTP channels. (Added in 7.20.0) interleaved RTP data is received. (Added in 7.20.0) .SH ERROR OPTIONS .IP CURLOPT_ERRORBUFFER Pass a char * to a buffer that the libcurl may store human readable error Loading lib/rtsp.c +40 −56 Original line number Diff line number Diff line Loading @@ -127,6 +127,10 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, long CSeq_sent; long CSeq_recv; /* Bypass HTTP empty-reply checks on receive */ if(data->set.rtspreq == RTSPREQ_RECEIVE) premature = TRUE; httpStatus = Curl_http_done(conn, status, premature); /* Check the sequence numbers */ Loading @@ -139,7 +143,7 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, } else if (data->set.rtspreq == RTSPREQ_RECEIVE && (conn->proto.rtspc.rtp_channel == -1)) { infof(data, "Got a non RTP Receive with a CSeq of %ld\n", CSeq_recv); infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv); /* TODO CPC: Server -> Client logic here */ } Loading Loading @@ -512,8 +516,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, struct connectdata *conn, ssize_t *nread, bool *readmore, bool *done) { bool *readmore) { struct SingleRequest *k = &data->req; struct rtsp_conn *rtspc = &(conn->proto.rtspc); Loading @@ -538,10 +541,6 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, rtp_dataleft = *nread; } if(rtp_dataleft == 0 || rtp[0] != '$') { return CURLE_OK; } while((rtp_dataleft > 0) && (rtp[0] == '$')) { if(rtp_dataleft > 4) { Loading @@ -564,22 +563,18 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, else { /* We have the full RTP interleaved packet * Write out the header but strip the leading '$' */ infof(data, "CPCDEBUG: RTP write channel %d rtp_length %d\n", rtspc->rtp_channel, rtp_length); DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", rtspc->rtp_channel, rtp_length)); result = rtp_client_write(conn, &rtp[1], rtp_length + 3); if(result) { failf(data, "Got an error writing an RTP packet"); *done = TRUE; *readmore = FALSE; Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return result; } /* Update progress */ k->bytecount += rtp_length + 4; Curl_pgrsSetDownloadCounter(data, k->bytecount); if(k->bytecountp) *k->bytecountp = k->bytecount; /* Move forward in the buffer */ rtp_dataleft -= rtp_length + 4; rtp += rtp_length + 4; Loading @@ -587,11 +582,8 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, if(data->set.rtspreq == RTSPREQ_RECEIVE) { /* If we are in a passive receive, give control back * to the app as often as we can. * * Otherwise, keep chugging along until we get RTSP data */ k->keepon &= ~KEEP_RECV; *done = TRUE; } } } Loading @@ -602,11 +594,9 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, } } if(*done || *readmore) { if(rtp_dataleft != 0 && rtp[0] == '$') { infof(data, "RTP Rewinding %zu %s %s\n", rtp_dataleft, *done ? "DONE " : "", *readmore ? "READMORE" : ""); DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft, *readmore ? "(READMORE)" : "")); /* Store the incomplete RTP packet for a "rewind" */ scratch = malloc(rtp_dataleft); Loading @@ -616,37 +606,31 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, 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; return CURLE_OK; } } else { /* RTP followed by RTSP */ if(rtp_dataleft == 0) { /* Need more */ *readmore = TRUE; } else { /* Fix up k->str to point just after the last RTP packet */ k->str += *nread - rtp_dataleft; /* rtp may point into the leftover buffer, but at this point * it is somewhere in the merged data from k->str. */ /* 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 */ 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; /* TODO CPC: Could implement parsing logic for Server->Client requests here */ return CURLE_OK; } Loading lib/rtsp.h +8 −2 Original line number Diff line number Diff line Loading @@ -27,11 +27,17 @@ extern const struct Curl_handler Curl_handler_rtsp; /* * Parse and write out any available RTP data. * * nread: amount of data left after k->str. will be modified if RTP * data is parsed and k->str is moved up * readmore: whether or not the RTP parser needs more data right away */ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, struct connectdata *conn, ssize_t *nread, bool *readmore, bool *done); bool *readmore); /* protocol-specific functions set up to be called by the main engine */ Loading lib/transfer.c +64 −8 Original line number Diff line number Diff line Loading @@ -368,7 +368,11 @@ static CURLcode readwrite_data(struct SessionHandle *data, { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ size_t excess = 0; /* excess bytes read */ bool is_empty_data = FALSE; #ifndef CURL_DISABLE_RTSP bool readmore = FALSE; /* used by RTP to signal for more data */ #endif *done = FALSE; Loading Loading @@ -437,15 +441,13 @@ static CURLcode readwrite_data(struct SessionHandle *data, k->str = k->buf; #ifndef CURL_DISABLE_RTSP /* Check for RTP at the beginning of the data */ if(conn->protocol & PROT_RTSP) { bool readmore = FALSE; result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore, done); result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; if(*done) return CURLE_OK; } #endif Loading @@ -458,6 +460,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading); if(result) return result; #ifndef CURL_DISABLE_RTSP /* Check for RTP after the headers if there is no Content */ if(k->maxdownload <= 0 && nread > 0 && (conn->protocol & PROT_RTSP)) { result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } #endif if(stop_reading) /* We've stopped dealing with input, get out of the do-while loop */ break; Loading Loading @@ -594,13 +608,19 @@ static CURLcode readwrite_data(struct SessionHandle *data, } #endif /* CURL_DISABLE_HTTP */ /* Account for body content stored in the header buffer */ if(k->badheader && !k->ignorebody) { DEBUGF(infof(data, "Increasing bytecount by %" FORMAT_OFF_T" from hbuflen\n", k->hbuflen)); k->bytecount += k->hbuflen; } if((-1 != k->maxdownload) && (k->bytecount + nread >= k->maxdownload)) { excess = (size_t)(k->bytecount + nread - k->maxdownload); if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) { /* The 'excess' amount below can't be more than BUFSIZE which always will fit in a size_t */ size_t excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { infof(data, "Rewinding stream by : %d" Loading @@ -612,6 +632,15 @@ static CURLcode readwrite_data(struct SessionHandle *data, read_rewind(conn, excess); } } else { infof(data, "Excess found in a non pipelined read:" " excess=%zu" ", size=%" FORMAT_OFF_T ", maxdownload=%" FORMAT_OFF_T ", bytecount=%" FORMAT_OFF_T "\n", excess, k->size, k->maxdownload, k->bytecount); } nread = (ssize_t) (k->maxdownload - k->bytecount); if(nread < 0 ) /* this should be unusual */ Loading @@ -630,9 +659,17 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(k->badheader && !k->ignorebody) { /* we parsed a piece of data wrongly assuming it was a header and now we output it as body instead */ /* Don't let excess data pollute body writes */ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, k->hbuflen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, k->maxdownload); if(result) return result; } Loading Loading @@ -694,6 +731,25 @@ static CURLcode readwrite_data(struct SessionHandle *data, } /* if(! header and data to read ) */ #ifndef CURL_DISABLE_RTSP if(excess > 0 && !conn->bits.stream_was_rewound && (conn->protocol & PROT_RTSP)) { /* Check for RTP after the content if there is unrewound excess */ /* Parse the excess data */ k->str += nread; nread = excess; result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) k->keepon |= KEEP_RECV; /* we're not done reading */ break; } #endif if(is_empty_data) { /* if we received nothing, the server closed the connection and we are done */ Loading Loading
docs/libcurl/curl_easy_setopt.3 +2 −6 Original line number Diff line number Diff line Loading @@ -411,7 +411,7 @@ interleaved header as well as the included data for each call. The first byte is always an ASCII dollar sign. The dollar sign is followed by a one byte channel identifier and then a 2 byte integer length in network byte order. See \fIRFC 2326 Section 10.12\fP for more information on how RTP interleaving behaves. behaves. If unset or set to NULL, curl will use the default write function. Interleaved RTP poses some challeneges for the client application. Since the stream data is sharing the RTSP control connection, it is critical to service Loading @@ -424,11 +424,7 @@ process any pending RTP data before marking the request as finished. (Added in 7.20.0) .IP CURLOPT_INTERLEAVEDATA This is the stream that will be passed to \fICURLOPT_INTERLEAVEFUNCTION\fP when interleaved RTP data is received. Since the application is required to provide a custom function for RTP data, there is no requirement that the stream pointer be a valid FILE pointer. An application may wish to pass a cookie containing information about many streams to assist in demultiplexing the different RTP channels. (Added in 7.20.0) interleaved RTP data is received. (Added in 7.20.0) .SH ERROR OPTIONS .IP CURLOPT_ERRORBUFFER Pass a char * to a buffer that the libcurl may store human readable error Loading
lib/rtsp.c +40 −56 Original line number Diff line number Diff line Loading @@ -127,6 +127,10 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, long CSeq_sent; long CSeq_recv; /* Bypass HTTP empty-reply checks on receive */ if(data->set.rtspreq == RTSPREQ_RECEIVE) premature = TRUE; httpStatus = Curl_http_done(conn, status, premature); /* Check the sequence numbers */ Loading @@ -139,7 +143,7 @@ CURLcode Curl_rtsp_done(struct connectdata *conn, } else if (data->set.rtspreq == RTSPREQ_RECEIVE && (conn->proto.rtspc.rtp_channel == -1)) { infof(data, "Got a non RTP Receive with a CSeq of %ld\n", CSeq_recv); infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv); /* TODO CPC: Server -> Client logic here */ } Loading Loading @@ -512,8 +516,7 @@ CURLcode Curl_rtsp(struct connectdata *conn, bool *done) CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, struct connectdata *conn, ssize_t *nread, bool *readmore, bool *done) { bool *readmore) { struct SingleRequest *k = &data->req; struct rtsp_conn *rtspc = &(conn->proto.rtspc); Loading @@ -538,10 +541,6 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, rtp_dataleft = *nread; } if(rtp_dataleft == 0 || rtp[0] != '$') { return CURLE_OK; } while((rtp_dataleft > 0) && (rtp[0] == '$')) { if(rtp_dataleft > 4) { Loading @@ -564,22 +563,18 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, else { /* We have the full RTP interleaved packet * Write out the header but strip the leading '$' */ infof(data, "CPCDEBUG: RTP write channel %d rtp_length %d\n", rtspc->rtp_channel, rtp_length); DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n", rtspc->rtp_channel, rtp_length)); result = rtp_client_write(conn, &rtp[1], rtp_length + 3); if(result) { failf(data, "Got an error writing an RTP packet"); *done = TRUE; *readmore = FALSE; Curl_safefree(rtspc->rtp_buf); rtspc->rtp_buf = NULL; rtspc->rtp_bufsize = 0; return result; } /* Update progress */ k->bytecount += rtp_length + 4; Curl_pgrsSetDownloadCounter(data, k->bytecount); if(k->bytecountp) *k->bytecountp = k->bytecount; /* Move forward in the buffer */ rtp_dataleft -= rtp_length + 4; rtp += rtp_length + 4; Loading @@ -587,11 +582,8 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, if(data->set.rtspreq == RTSPREQ_RECEIVE) { /* If we are in a passive receive, give control back * to the app as often as we can. * * Otherwise, keep chugging along until we get RTSP data */ k->keepon &= ~KEEP_RECV; *done = TRUE; } } } Loading @@ -602,11 +594,9 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, } } if(*done || *readmore) { if(rtp_dataleft != 0 && rtp[0] == '$') { infof(data, "RTP Rewinding %zu %s %s\n", rtp_dataleft, *done ? "DONE " : "", *readmore ? "READMORE" : ""); DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft, *readmore ? "(READMORE)" : "")); /* Store the incomplete RTP packet for a "rewind" */ scratch = malloc(rtp_dataleft); Loading @@ -616,37 +606,31 @@ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, 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; return CURLE_OK; } } else { /* RTP followed by RTSP */ if(rtp_dataleft == 0) { /* Need more */ *readmore = TRUE; } else { /* Fix up k->str to point just after the last RTP packet */ k->str += *nread - rtp_dataleft; /* rtp may point into the leftover buffer, but at this point * it is somewhere in the merged data from k->str. */ /* 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 */ 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; /* TODO CPC: Could implement parsing logic for Server->Client requests here */ return CURLE_OK; } Loading
lib/rtsp.h +8 −2 Original line number Diff line number Diff line Loading @@ -27,11 +27,17 @@ extern const struct Curl_handler Curl_handler_rtsp; /* * Parse and write out any available RTP data. * * nread: amount of data left after k->str. will be modified if RTP * data is parsed and k->str is moved up * readmore: whether or not the RTP parser needs more data right away */ CURLcode Curl_rtsp_rtp_readwrite(struct SessionHandle *data, struct connectdata *conn, ssize_t *nread, bool *readmore, bool *done); bool *readmore); /* protocol-specific functions set up to be called by the main engine */ Loading
lib/transfer.c +64 −8 Original line number Diff line number Diff line Loading @@ -368,7 +368,11 @@ static CURLcode readwrite_data(struct SessionHandle *data, { CURLcode result = CURLE_OK; ssize_t nread; /* number of bytes read */ size_t excess = 0; /* excess bytes read */ bool is_empty_data = FALSE; #ifndef CURL_DISABLE_RTSP bool readmore = FALSE; /* used by RTP to signal for more data */ #endif *done = FALSE; Loading Loading @@ -437,15 +441,13 @@ static CURLcode readwrite_data(struct SessionHandle *data, k->str = k->buf; #ifndef CURL_DISABLE_RTSP /* Check for RTP at the beginning of the data */ if(conn->protocol & PROT_RTSP) { bool readmore = FALSE; result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore, done); result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; if(*done) return CURLE_OK; } #endif Loading @@ -458,6 +460,18 @@ static CURLcode readwrite_data(struct SessionHandle *data, result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading); if(result) return result; #ifndef CURL_DISABLE_RTSP /* Check for RTP after the headers if there is no Content */ if(k->maxdownload <= 0 && nread > 0 && (conn->protocol & PROT_RTSP)) { result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) break; } #endif if(stop_reading) /* We've stopped dealing with input, get out of the do-while loop */ break; Loading Loading @@ -594,13 +608,19 @@ static CURLcode readwrite_data(struct SessionHandle *data, } #endif /* CURL_DISABLE_HTTP */ /* Account for body content stored in the header buffer */ if(k->badheader && !k->ignorebody) { DEBUGF(infof(data, "Increasing bytecount by %" FORMAT_OFF_T" from hbuflen\n", k->hbuflen)); k->bytecount += k->hbuflen; } if((-1 != k->maxdownload) && (k->bytecount + nread >= k->maxdownload)) { excess = (size_t)(k->bytecount + nread - k->maxdownload); if(conn->data->multi && Curl_multi_canPipeline(conn->data->multi)) { /* The 'excess' amount below can't be more than BUFSIZE which always will fit in a size_t */ size_t excess = (size_t)(k->bytecount + nread - k->maxdownload); if(excess > 0 && !k->ignorebody) { infof(data, "Rewinding stream by : %d" Loading @@ -612,6 +632,15 @@ static CURLcode readwrite_data(struct SessionHandle *data, read_rewind(conn, excess); } } else { infof(data, "Excess found in a non pipelined read:" " excess=%zu" ", size=%" FORMAT_OFF_T ", maxdownload=%" FORMAT_OFF_T ", bytecount=%" FORMAT_OFF_T "\n", excess, k->size, k->maxdownload, k->bytecount); } nread = (ssize_t) (k->maxdownload - k->bytecount); if(nread < 0 ) /* this should be unusual */ Loading @@ -630,9 +659,17 @@ static CURLcode readwrite_data(struct SessionHandle *data, if(k->badheader && !k->ignorebody) { /* we parsed a piece of data wrongly assuming it was a header and now we output it as body instead */ /* Don't let excess data pollute body writes */ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload) result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, k->hbuflen); else result = Curl_client_write(conn, CLIENTWRITE_BODY, data->state.headerbuff, k->maxdownload); if(result) return result; } Loading Loading @@ -694,6 +731,25 @@ static CURLcode readwrite_data(struct SessionHandle *data, } /* if(! header and data to read ) */ #ifndef CURL_DISABLE_RTSP if(excess > 0 && !conn->bits.stream_was_rewound && (conn->protocol & PROT_RTSP)) { /* Check for RTP after the content if there is unrewound excess */ /* Parse the excess data */ k->str += nread; nread = excess; result = Curl_rtsp_rtp_readwrite(data, conn, &nread, &readmore); if(result) return result; if(readmore) k->keepon |= KEEP_RECV; /* we're not done reading */ break; } #endif if(is_empty_data) { /* if we received nothing, the server closed the connection and we are done */ Loading