Skip to content

Commit ba15619

Browse files
committed
feat: enhance RTSP session handling with OPTIONS support and improved state management
1 parent 20e7f95 commit ba15619

File tree

7 files changed

+3749
-3660
lines changed

7 files changed

+3749
-3660
lines changed

src/rtsp.c

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ void rtsp_session_init(rtsp_session_t *session)
158158
session->last_keepalive_ms = 0;
159159
session->keepalive_pending = 0;
160160
session->awaiting_keepalive_response = 0;
161+
session->use_get_parameter = 1; /* Start with GET_PARAMETER, fallback to OPTIONS if not supported */
161162

162163
/* Initialize teardown state */
163164
session->teardown_requested = 0;
@@ -175,6 +176,8 @@ static void rtsp_session_set_state(rtsp_session_t *session, rtsp_state_t new_sta
175176
[RTSP_STATE_INIT] = CLIENT_STATE_RTSP_INIT,
176177
[RTSP_STATE_CONNECTING] = CLIENT_STATE_RTSP_CONNECTING,
177178
[RTSP_STATE_CONNECTED] = CLIENT_STATE_RTSP_CONNECTED,
179+
[RTSP_STATE_SENDING_OPTIONS] = CLIENT_STATE_RTSP_SENDING_OPTIONS,
180+
[RTSP_STATE_AWAITING_OPTIONS] = CLIENT_STATE_RTSP_AWAITING_OPTIONS,
178181
[RTSP_STATE_SENDING_DESCRIBE] = CLIENT_STATE_RTSP_SENDING_DESCRIBE,
179182
[RTSP_STATE_AWAITING_DESCRIBE] = CLIENT_STATE_RTSP_AWAITING_DESCRIBE,
180183
[RTSP_STATE_DESCRIBED] = CLIENT_STATE_RTSP_DESCRIBED,
@@ -945,13 +948,15 @@ int rtsp_send_keepalive(rtsp_session_t *session)
945948
char extra_headers[RTSP_HEADERS_BUFFER_SIZE];
946949
if (snprintf(extra_headers, sizeof(extra_headers), "Session: %s\r\n", session->session_id) >= (int)sizeof(extra_headers))
947950
{
948-
logger(LOG_ERROR, "RTSP: Failed to format OPTIONS keepalive headers");
951+
logger(LOG_ERROR, "RTSP: Failed to format keepalive headers");
949952
return -1;
950953
}
951954

952-
if (rtsp_prepare_request(session, RTSP_METHOD_OPTIONS, extra_headers) < 0)
955+
/* Use GET_PARAMETER if supported, otherwise use OPTIONS */
956+
const char *method = session->use_get_parameter ? RTSP_METHOD_GET_PARAMETER : RTSP_METHOD_OPTIONS;
957+
if (rtsp_prepare_request(session, method, extra_headers) < 0)
953958
{
954-
logger(LOG_ERROR, "RTSP: Failed to prepare OPTIONS keepalive request");
959+
logger(LOG_ERROR, "RTSP: Failed to prepare %s keepalive request", method);
955960
return -1;
956961
}
957962

@@ -964,15 +969,15 @@ int rtsp_send_keepalive(rtsp_session_t *session)
964969
ev.data.fd = session->socket;
965970
if (epoll_ctl(session->epoll_fd, EPOLL_CTL_MOD, session->socket, &ev) < 0)
966971
{
967-
logger(LOG_ERROR, "RTSP: Failed to enable EPOLLOUT for OPTIONS keepalive: %s", strerror(errno));
972+
logger(LOG_ERROR, "RTSP: Failed to enable EPOLLOUT for %s keepalive: %s", method, strerror(errno));
968973
session->pending_request_len = 0;
969974
session->pending_request_sent = 0;
970975
session->keepalive_pending = 0;
971976
return -1;
972977
}
973978
}
974979

975-
logger(LOG_DEBUG, "RTSP: Queued OPTIONS keepalive request");
980+
logger(LOG_DEBUG, "RTSP: Queued %s keepalive request", method);
976981
return 0;
977982
}
978983

@@ -1023,7 +1028,11 @@ static int rtsp_try_send_pending(rtsp_session_t *session)
10231028
}
10241029

10251030
/* Update state to awaiting response */
1026-
if (session->state == RTSP_STATE_SENDING_DESCRIBE)
1031+
if (session->state == RTSP_STATE_SENDING_OPTIONS)
1032+
{
1033+
rtsp_session_set_state(session, RTSP_STATE_AWAITING_OPTIONS);
1034+
}
1035+
else if (session->state == RTSP_STATE_SENDING_DESCRIBE)
10271036
{
10281037
rtsp_session_set_state(session, RTSP_STATE_AWAITING_DESCRIBE);
10291038
}
@@ -1122,11 +1131,19 @@ static int rtsp_try_receive_response(rtsp_session_t *session)
11221131
if (was_keepalive)
11231132
{
11241133
session->response_buffer_pos = 0;
1125-
logger(LOG_DEBUG, "RTSP: OPTIONS keepalive acknowledged");
1134+
const char *method = session->use_get_parameter ? "GET_PARAMETER" : "OPTIONS";
1135+
logger(LOG_DEBUG, "RTSP: %s keepalive acknowledged", method);
11261136
return RTSP_RESPONSE_KEEPALIVE;
11271137
}
11281138

11291139
/* Advance to next state based on current state */
1140+
if (session->state == RTSP_STATE_AWAITING_OPTIONS)
1141+
{
1142+
/* OPTIONS response received - keep state as AWAITING_OPTIONS,
1143+
* state machine will transition to SENDING_DESCRIBE */
1144+
session->response_buffer_pos = 0;
1145+
return RTSP_RESPONSE_ADVANCE;
1146+
}
11301147
if (session->state == RTSP_STATE_AWAITING_DESCRIBE)
11311148
{
11321149
rtsp_session_set_state(session, RTSP_STATE_DESCRIBED);
@@ -1179,7 +1196,19 @@ static int rtsp_state_machine_advance(rtsp_session_t *session)
11791196
switch (session->state)
11801197
{
11811198
case RTSP_STATE_CONNECTED:
1182-
/* Ready to send DESCRIBE */
1199+
/* Ready to send OPTIONS (RFC 2326 requires OPTIONS before DESCRIBE) */
1200+
extra_headers[0] = '\0'; /* No extra headers needed for OPTIONS */
1201+
if (rtsp_prepare_request(session, RTSP_METHOD_OPTIONS, extra_headers) < 0)
1202+
{
1203+
logger(LOG_ERROR, "RTSP: Failed to prepare OPTIONS request");
1204+
return -1;
1205+
}
1206+
rtsp_session_set_state(session, RTSP_STATE_SENDING_OPTIONS);
1207+
/* Will send when socket becomes writable */
1208+
return 0;
1209+
1210+
case RTSP_STATE_AWAITING_OPTIONS:
1211+
/* OPTIONS response received, ready to send DESCRIBE */
11831212
snprintf(extra_headers, sizeof(extra_headers), "Accept: application/sdp\r\n");
11841213
if (rtsp_prepare_request(session, RTSP_METHOD_DESCRIBE, extra_headers) < 0)
11851214
{
@@ -1496,6 +1525,7 @@ static void rtsp_force_cleanup(rtsp_session_t *session)
14961525
session->last_keepalive_ms = 0;
14971526
session->keepalive_pending = 0;
14981527
session->awaiting_keepalive_response = 0;
1528+
session->use_get_parameter = 1;
14991529

15001530
/* Reset teardown state */
15011531
session->teardown_requested = 0;
@@ -1694,6 +1724,7 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
16941724
char *session_header = NULL;
16951725
char *transport_header = NULL;
16961726
char *location_header = NULL;
1727+
char *public_header = NULL;
16971728
int status_code;
16981729
int result = 0;
16991730

@@ -1725,11 +1756,48 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
17251756
}
17261757
else if (status_code != 200)
17271758
{
1759+
/* Check if this is a GET_PARAMETER not supported error during keepalive */
1760+
if ((status_code == 454 || status_code == 501) &&
1761+
session->awaiting_keepalive_response && session->use_get_parameter)
1762+
{
1763+
logger(LOG_DEBUG, "RTSP: GET_PARAMETER not supported (code %d), falling back to OPTIONS for keepalive", status_code);
1764+
session->use_get_parameter = 0;
1765+
session->awaiting_keepalive_response = 0;
1766+
result = 0; /* Treat as success, will use OPTIONS next time */
1767+
goto cleanup;
1768+
}
1769+
17281770
logger(LOG_ERROR, "RTSP: Server returned error code %d", status_code);
17291771
result = -1;
17301772
goto cleanup;
17311773
}
17321774

1775+
/* Parse Public header from OPTIONS response to determine supported methods */
1776+
if (session->state == RTSP_STATE_AWAITING_OPTIONS)
1777+
{
1778+
public_header = rtsp_find_header(response, "Public");
1779+
if (public_header)
1780+
{
1781+
/* Check if GET_PARAMETER is supported */
1782+
if (strstr(public_header, "GET_PARAMETER"))
1783+
{
1784+
session->use_get_parameter = 1;
1785+
logger(LOG_DEBUG, "RTSP: Server supports GET_PARAMETER for keepalive");
1786+
}
1787+
else
1788+
{
1789+
session->use_get_parameter = 0;
1790+
logger(LOG_DEBUG, "RTSP: Server does not advertise GET_PARAMETER, will use OPTIONS for keepalive");
1791+
}
1792+
logger(LOG_DEBUG, "RTSP: Server advertised methods: %s", public_header);
1793+
}
1794+
else
1795+
{
1796+
/* No Public header - try GET_PARAMETER anyway, fallback on error */
1797+
logger(LOG_DEBUG, "RTSP: No Public header in OPTIONS response, will try GET_PARAMETER with fallback");
1798+
}
1799+
}
1800+
17331801
/* Extract Session header if present */
17341802
session_header = rtsp_find_header(response, "Session");
17351803
if (session_header)
@@ -1758,6 +1826,8 @@ static int rtsp_parse_response(rtsp_session_t *session, const char *response)
17581826
free(transport_header);
17591827
if (location_header)
17601828
free(location_header);
1829+
if (public_header)
1830+
free(public_header);
17611831

17621832
return result;
17631833
}
@@ -2128,6 +2198,7 @@ static void rtsp_parse_transport_header(rtsp_session_t *session, const char *tra
21282198
session->last_keepalive_ms = 0;
21292199
session->keepalive_pending = 0;
21302200
session->awaiting_keepalive_response = 0;
2201+
session->use_get_parameter = 1; /* Try GET_PARAMETER first, fallback to OPTIONS */
21312202
logger(LOG_INFO, "RTSP: Using UDP transport");
21322203

21332204
/* Parse source parameter if provided */

src/rtsp.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,9 @@ typedef enum
6767
{
6868
RTSP_STATE_INIT = 0,
6969
RTSP_STATE_CONNECTING, /* Async TCP connection in progress */
70-
RTSP_STATE_CONNECTED, /* Connected, ready to send DESCRIBE */
70+
RTSP_STATE_CONNECTED, /* Connected, ready to send OPTIONS */
71+
RTSP_STATE_SENDING_OPTIONS, /* Sending OPTIONS request */
72+
RTSP_STATE_AWAITING_OPTIONS, /* Waiting for OPTIONS response */
7173
RTSP_STATE_SENDING_DESCRIBE, /* Sending DESCRIBE request */
7274
RTSP_STATE_AWAITING_DESCRIBE, /* Waiting for DESCRIBE response */
7375
RTSP_STATE_DESCRIBED, /* DESCRIBE complete, ready to send SETUP */
@@ -154,10 +156,11 @@ typedef struct
154156
int awaiting_response; /* Flag: waiting for response */
155157

156158
/* Keepalive tracking */
157-
int keepalive_interval_ms; /* OPTIONS keepalive interval (0 = disabled) */
158-
int64_t last_keepalive_ms; /* Timestamp of last OPTIONS keepalive */
159+
int keepalive_interval_ms; /* Keepalive interval (0 = disabled) */
160+
int64_t last_keepalive_ms; /* Timestamp of last keepalive */
159161
int keepalive_pending; /* Pending keepalive request queued for send */
160-
int awaiting_keepalive_response; /* Awaiting OPTIONS keepalive response */
162+
int awaiting_keepalive_response; /* Awaiting keepalive response */
163+
int use_get_parameter; /* Use GET_PARAMETER for keepalive (1), fallback to OPTIONS (0) */
161164

162165
/* Teardown and cleanup state */
163166
int teardown_requested; /* Flag: TEARDOWN has been requested (cleanup initiated) */

src/status.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ typedef enum
4242
CLIENT_STATE_RTSP_INIT,
4343
CLIENT_STATE_RTSP_CONNECTING,
4444
CLIENT_STATE_RTSP_CONNECTED,
45+
CLIENT_STATE_RTSP_SENDING_OPTIONS,
46+
CLIENT_STATE_RTSP_AWAITING_OPTIONS,
4547
CLIENT_STATE_RTSP_SENDING_DESCRIBE,
4648
CLIENT_STATE_RTSP_AWAITING_DESCRIBE,
4749
CLIENT_STATE_RTSP_DESCRIBED,

0 commit comments

Comments
 (0)