rtsp: move easy handle/connection protoocol structs into meta data

Remove the connectdata proto and data->req.p member for rtsp and manage
the structs as meta data at easy handle/connection.

Closes #17254
This commit is contained in:
Stefan Eissing 2025-05-06 10:44:27 +02:00 committed by Daniel Stenberg
parent f7c544d867
commit 2e49965126
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
4 changed files with 94 additions and 75 deletions

View file

@ -105,7 +105,6 @@ struct SingleRequest {
struct FILEPROTO *file;
struct IMAP *imap;
struct ldapreqinfo *ldap;
struct RTSP *rtsp;
struct SMTP *smtp;
struct SSHPROTO *ssh;
struct TELNET *telnet;

View file

@ -46,6 +46,36 @@
#include "curl_memory.h"
#include "memdebug.h"
/* meta key for storing protocol meta at easy handle */
#define CURL_META_RTSP_EASY "meta:proto:rtsp:easy"
/* meta key for storing protocol meta at connection */
#define CURL_META_RTSP_CONN "meta:proto:rtsp:conn"
typedef enum {
RTP_PARSE_SKIP,
RTP_PARSE_CHANNEL,
RTP_PARSE_LEN,
RTP_PARSE_DATA
} rtp_parse_st;
/* RTSP Connection data
* Currently, only used for tracking incomplete RTP data reads */
struct rtsp_conn {
struct dynbuf buf;
int rtp_channel;
size_t rtp_len;
rtp_parse_st state;
BIT(in_header);
};
/* RTSP transfer data */
struct RTSP {
long CSeq_sent; /* CSeq of this request */
long CSeq_recv; /* CSeq received */
};
#define RTP_PKT_LENGTH(p) ((((unsigned int)((unsigned char)((p)[2]))) << 8) | \
((unsigned int)((unsigned char)((p)[3]))))
@ -53,8 +83,6 @@
static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature);
static CURLcode rtsp_connect(struct Curl_easy *data, bool *done);
static CURLcode rtsp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static int rtsp_getsock_do(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
@ -113,7 +141,7 @@ const struct Curl_handler Curl_handler_rtsp = {
rtsp_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
rtsp_disconnect, /* disconnect */
ZERO_NULL, /* disconnect */
rtsp_rtp_write_resp, /* write_resp */
ZERO_NULL, /* write_resp_hd */
rtsp_conncheck, /* connection_check */
@ -127,20 +155,39 @@ const struct Curl_handler Curl_handler_rtsp = {
#define MAX_RTP_BUFFERSIZE 1000000 /* arbitrary */
static void rtsp_easy_dtor(void *key, size_t klen, void *entry)
{
struct RTSP *rtsp = entry;
(void)key;
(void)klen;
free(rtsp);
}
static void rtsp_conn_dtor(void *key, size_t klen, void *entry)
{
struct rtsp_conn *rtspc = entry;
(void)key;
(void)klen;
Curl_dyn_free(&rtspc->buf);
free(rtspc);
}
static CURLcode rtsp_setup_connection(struct Curl_easy *data,
struct connectdata *conn)
{
struct rtsp_conn *rtspc = &conn->proto.rtspc;
struct rtsp_conn *rtspc;
struct RTSP *rtsp;
(void)conn;
if(!rtspc->initialised) {
Curl_dyn_init(&rtspc->buf, MAX_RTP_BUFFERSIZE);
rtspc->initialised = TRUE;
}
rtspc = calloc(1, sizeof(*rtspc));
if(!rtspc)
return CURLE_OUT_OF_MEMORY;
Curl_dyn_init(&rtspc->buf, MAX_RTP_BUFFERSIZE);
if(Curl_conn_meta_set(conn, CURL_META_RTSP_CONN, rtspc, rtsp_conn_dtor))
return CURLE_OUT_OF_MEMORY;
data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
if(!rtsp)
rtsp = calloc(1, sizeof(struct RTSP));
if(!rtsp ||
Curl_meta_set(data, CURL_META_RTSP_EASY, rtsp, rtsp_easy_dtor))
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
@ -169,8 +216,13 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
{
struct rtsp_conn *rtspc =
Curl_conn_meta_get(data->conn, CURL_META_RTSP_CONN);
CURLcode httpStatus;
if(!rtspc)
return CURLE_FAILED_INIT;
httpStatus = Curl_http_connect(data, done);
/* Initialize the CSeq if not already done */
@ -179,31 +231,22 @@ static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
if(data->state.rtsp_next_server_CSeq == 0)
data->state.rtsp_next_server_CSeq = 1;
data->conn->proto.rtspc.rtp_channel = -1;
rtspc->rtp_channel = -1;
return httpStatus;
}
static CURLcode rtsp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead)
{
struct rtsp_conn *rtspc = &conn->proto.rtspc;
(void) dead;
(void) data;
if(rtspc->initialised) {
Curl_dyn_free(&conn->proto.rtspc.buf);
rtspc->initialised = FALSE;
}
return CURLE_OK;
}
static CURLcode rtsp_done(struct Curl_easy *data,
CURLcode status, bool premature)
{
struct RTSP *rtsp = data->req.p.rtsp;
struct rtsp_conn *rtspc =
Curl_conn_meta_get(data->conn, CURL_META_RTSP_CONN);
struct RTSP *rtsp = Curl_meta_get(data, CURL_META_RTSP_EASY);
CURLcode httpStatus;
if(!rtspc || !rtsp)
return CURLE_FAILED_INIT;
/* Bypass HTTP empty-reply checks on receive */
if(data->set.rtspreq == RTSPREQ_RECEIVE)
premature = TRUE;
@ -220,8 +263,7 @@ static CURLcode rtsp_done(struct Curl_easy *data,
CSeq_sent, CSeq_recv);
return CURLE_RTSP_CSEQ_ERROR;
}
if(data->set.rtspreq == RTSPREQ_RECEIVE &&
(data->conn->proto.rtspc.rtp_channel == -1)) {
if(data->set.rtspreq == RTSPREQ_RECEIVE && (rtspc->rtp_channel == -1)) {
infof(data, "Got an RTP Receive with a CSeq of %ld", CSeq_recv);
}
if(data->set.rtspreq == RTSPREQ_RECEIVE &&
@ -239,7 +281,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
CURLcode result = CURLE_OK;
Curl_RtspReq rtspreq = data->set.rtspreq;
struct RTSP *rtsp = data->req.p.rtsp;
struct RTSP *rtsp = Curl_meta_get(data, CURL_META_RTSP_EASY);
struct dynbuf req_buffer;
unsigned char httpversion = 11; /* RTSP is close to HTTP/1.1, sort of... */
@ -256,6 +298,9 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
const char *p_userpwd = NULL;
*done = TRUE;
if(!rtsp)
return CURLE_FAILED_INIT;
/* Initialize a dynamic send buffer */
Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
@ -621,10 +666,10 @@ out:
* write any BODY bytes missing to the client, ignore the rest.
*/
static CURLcode rtp_write_body_junk(struct Curl_easy *data,
struct rtsp_conn *rtspc,
const char *buf,
size_t blen)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
curl_off_t body_remain;
bool in_body;
@ -642,11 +687,11 @@ static CURLcode rtp_write_body_junk(struct Curl_easy *data,
}
static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
const char *buf,
size_t blen,
size_t *pconsumed)
struct rtsp_conn *rtspc,
const char *buf,
size_t blen,
size_t *pconsumed)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
CURLcode result = CURLE_OK;
size_t skip_len = 0;
@ -683,7 +728,7 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
/* possible start of an RTP message, buffer */
if(skip_len) {
/* end of junk/BODY bytes, flush */
result = rtp_write_body_junk(data, buf - skip_len, skip_len);
result = rtp_write_body_junk(data, rtspc, buf - skip_len, skip_len);
skip_len = 0;
if(result)
goto out;
@ -714,7 +759,8 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
/* We did not consume the initial '$' in our buffer, but had
* it from an earlier call. We cannot un-consume it and have
* to write it directly as BODY data */
result = rtp_write_body_junk(data, Curl_dyn_ptr(&rtspc->buf), 1);
result = rtp_write_body_junk(data, rtspc,
Curl_dyn_ptr(&rtspc->buf), 1);
if(result)
goto out;
}
@ -799,7 +845,7 @@ static CURLcode rtsp_filter_rtp(struct Curl_easy *data,
}
out:
if(!result && skip_len)
result = rtp_write_body_junk(data, buf - skip_len, skip_len);
result = rtp_write_body_junk(data, rtspc, buf - skip_len, skip_len);
return result;
}
@ -808,10 +854,14 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
size_t blen,
bool is_eos)
{
struct rtsp_conn *rtspc = &(data->conn->proto.rtspc);
struct rtsp_conn *rtspc =
Curl_conn_meta_get(data->conn, CURL_META_RTSP_CONN);
CURLcode result = CURLE_OK;
size_t consumed = 0;
if(!rtspc)
return CURLE_FAILED_INIT;
if(!data->req.header)
rtspc->in_header = FALSE;
if(!blen) {
@ -823,7 +873,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
/* If header parsing is not ongoing, extract RTP messages */
if(!rtspc->in_header) {
result = rtsp_filter_rtp(data, buf, blen, &consumed);
result = rtsp_filter_rtp(data, rtspc, buf, blen, &consumed);
if(result)
goto out;
buf += consumed;
@ -855,7 +905,7 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data,
data->req.size = 0;
data->req.download_done = TRUE;
}
result = rtsp_filter_rtp(data, buf, blen, &consumed);
result = rtsp_filter_rtp(data, rtspc, buf, blen, &consumed);
if(result)
goto out;
blen -= consumed;
@ -933,8 +983,10 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header)
{
if(checkprefix("CSeq:", header)) {
curl_off_t CSeq = 0;
struct RTSP *rtsp = data->req.p.rtsp;
struct RTSP *rtsp = Curl_meta_get(data, CURL_META_RTSP_EASY);
const char *p = &header[5];
if(!rtsp)
return CURLE_FAILED_INIT;
Curl_str_passblanks(&p);
if(Curl_str_number(&p, &CSeq, LONG_MAX)) {
failf(data, "Unable to read the CSeq header: [%s]", header);

View file

@ -36,33 +36,4 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, const char *header);
#endif /* CURL_DISABLE_RTSP */
typedef enum {
RTP_PARSE_SKIP,
RTP_PARSE_CHANNEL,
RTP_PARSE_LEN,
RTP_PARSE_DATA
} rtp_parse_st;
/*
* RTSP Connection data
*
* Currently, only used for tracking incomplete RTP data reads
*/
struct rtsp_conn {
struct dynbuf buf;
int rtp_channel;
size_t rtp_len;
rtp_parse_st state;
BIT(in_header);
BIT(initialised);
};
/****************************************************************************
* RTSP unique setup
***************************************************************************/
struct RTSP {
long CSeq_sent; /* CSeq of this request */
long CSeq_recv; /* CSeq received */
};
#endif /* HEADER_CURL_RTSP_H */

View file

@ -872,9 +872,6 @@ struct connectdata {
#ifndef CURL_DISABLE_SMTP
struct smtp_conn smtpc;
#endif
#ifndef CURL_DISABLE_RTSP
struct rtsp_conn rtspc;
#endif
#ifdef USE_LIBRTMP
void *rtmp;
#endif