aboutsummaryrefslogtreecommitdiffstats
path: root/libavformat/rtsp.c
diff options
context:
space:
mode:
authorTommy Winther <tommy@net-comm.dk>2011-10-12 12:26:45 +0300
committerMartin Storsjö <martin@martin.st>2012-02-27 12:04:11 +0200
commit1a6b9a98ceacc3aca35ab354f9e97e3ac01b0ded (patch)
tree28a631cf4e9485550c3044dd2e850be74028119a /libavformat/rtsp.c
parentf234e8a32e6c69d7b63f8627f278be7c2c987f43 (diff)
downloadffmpeg-1a6b9a98ceacc3aca35ab354f9e97e3ac01b0ded.tar.gz
rtsp: Handle requests from server to client
This returns 200 OK for OPTIONS requests and 501 Not Implemented for all other requests. Even though this doesn't do much actual handling of the requests, it makes the code properly identify server requests as such, instead of interpreting it as a reply to the client's request as it did before. Signed-off-by: Martin Storsjö <martin@martin.st>
Diffstat (limited to 'libavformat/rtsp.c')
-rw-r--r--libavformat/rtsp.c58
1 files changed, 53 insertions, 5 deletions
diff --git a/libavformat/rtsp.c b/libavformat/rtsp.c
index 29994e4eb3..dd79407036 100644
--- a/libavformat/rtsp.c
+++ b/libavformat/rtsp.c
@@ -900,9 +900,13 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
char buf[4096], buf1[1024], *q;
unsigned char ch;
const char *p;
- int ret, content_length, line_count = 0;
+ int ret, content_length, line_count = 0, request = 0;
unsigned char *content = NULL;
+start:
+ line_count = 0;
+ request = 0;
+ content = NULL;
memset(reply, 0, sizeof(*reply));
/* parse reply (XXX: use buffers) */
@@ -938,9 +942,15 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
if (line_count == 0) {
/* get reply code */
get_word(buf1, sizeof(buf1), &p);
- get_word(buf1, sizeof(buf1), &p);
- reply->status_code = atoi(buf1);
- av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ if (!strncmp(buf1, "RTSP/", 5)) {
+ get_word(buf1, sizeof(buf1), &p);
+ reply->status_code = atoi(buf1);
+ av_strlcpy(reply->reason, p, sizeof(reply->reason));
+ } else {
+ av_strlcpy(reply->reason, buf1, sizeof(reply->reason)); // method
+ get_word(buf1, sizeof(buf1), &p); // object
+ request = 1;
+ }
} else {
ff_rtsp_parse_line(reply, p, rt, method);
av_strlcat(rt->last_reply, p, sizeof(rt->last_reply));
@@ -949,7 +959,7 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
line_count++;
}
- if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0')
+ if (rt->session_id[0] == '\0' && reply->session_id[0] != '\0' && !request)
av_strlcpy(rt->session_id, reply->session_id, sizeof(rt->session_id));
content_length = reply->content_length;
@@ -964,6 +974,44 @@ int ff_rtsp_read_reply(AVFormatContext *s, RTSPMessageHeader *reply,
else
av_free(content);
+ if (request) {
+ char buf[1024];
+ char base64buf[AV_BASE64_SIZE(sizeof(buf))];
+ const char* ptr = buf;
+
+ if (!strcmp(reply->reason, "OPTIONS")) {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 200 OK\r\n");
+ if (reply->seq)
+ av_strlcatf(buf, sizeof(buf), "CSeq: %d\r\n", reply->seq);
+ if (reply->session_id[0])
+ av_strlcatf(buf, sizeof(buf), "Session: %s\r\n",
+ reply->session_id);
+ } else {
+ snprintf(buf, sizeof(buf), "RTSP/1.0 501 Not Implemented\r\n");
+ }
+ av_strlcat(buf, "\r\n", sizeof(buf));
+
+ if (rt->control_transport == RTSP_MODE_TUNNEL) {
+ av_base64_encode(base64buf, sizeof(base64buf), buf, strlen(buf));
+ ptr = base64buf;
+ }
+ ffurl_write(rt->rtsp_hd_out, ptr, strlen(ptr));
+
+ rt->last_cmd_time = av_gettime();
+ /* Even if the request from the server had data, it is not the data
+ * that the caller wants or expects. The memory could also be leaked
+ * if the actual following reply has content data. */
+ if (content_ptr)
+ av_freep(content_ptr);
+ /* If method is set, this is called from ff_rtsp_send_cmd,
+ * where a reply to exactly this request is awaited. For
+ * callers from within packet reciving, we just want to
+ * return to the caller and go back to receiving packets. */
+ if (method)
+ goto start;
+ return 0;
+ }
+
if (rt->seq != reply->seq) {
av_log(s, AV_LOG_WARNING, "CSeq %d expected, %d received.\n",
rt->seq, reply->seq);