From: Wim Taymans Date: Wed, 2 May 2007 13:32:57 +0000 (+0000) Subject: gst/rtsp/gstrtspsrc.*: Fix sending RTCP to the right place. X-Git-Tag: RELEASE-0_10_6~128 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=92396be1523b27a99b1c83247d058a5d8bba9cf8;p=platform%2Fupstream%2Fgst-plugins-good.git gst/rtsp/gstrtspsrc.*: Fix sending RTCP to the right place. Original commit message from CVS: * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), (gst_rtspsrc_finalize), (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_handle_request), (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_loop_udp), (gst_rtspsrc_loop_send_cmd), (gst_rtspsrc_try_send), (gst_rtspsrc_open), (gst_rtspsrc_handle_message): * gst/rtsp/gstrtspsrc.h: Fix sending RTCP to the right place. Fix bug in reffing the wrong UDP element. Use new pad names for the session manager. Implement handling server requests in interleaved and UDP modes. Handle session keep-alive in UDP modes. Remove GCond for handling UDP timeouts. * gst/rtsp/rtspconnection.c: (rtsp_connection_connect), (rtsp_connection_send), (rtsp_connection_read), (read_body), (rtsp_connection_receive), (rtsp_connection_close): * gst/rtsp/rtspconnection.h: Store connection IP address for later. Add timeout args to all operations that might block forever. Parse session timeout. Only close sockets when not already closed. * gst/rtsp/rtspdefs.c: * gst/rtsp/rtspdefs.h: Add timeout return value and error string. * gst/rtsp/rtspmessage.c: (rtsp_message_init_response): Add small comment. --- diff --git a/ChangeLog b/ChangeLog index c530457..500f1b4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2007-05-02 Wim Taymans + + * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_init), + (gst_rtspsrc_finalize), (gst_rtspsrc_stream_configure_transport), + (gst_rtspsrc_handle_request), (gst_rtspsrc_loop_interleaved), + (gst_rtspsrc_send_keep_alive), (gst_rtspsrc_loop_udp), + (gst_rtspsrc_loop_send_cmd), (gst_rtspsrc_try_send), + (gst_rtspsrc_open), (gst_rtspsrc_handle_message): + * gst/rtsp/gstrtspsrc.h: + Fix sending RTCP to the right place. + Fix bug in reffing the wrong UDP element. + Use new pad names for the session manager. + Implement handling server requests in interleaved and UDP modes. + Handle session keep-alive in UDP modes. + Remove GCond for handling UDP timeouts. + + * gst/rtsp/rtspconnection.c: (rtsp_connection_connect), + (rtsp_connection_send), (rtsp_connection_read), (read_body), + (rtsp_connection_receive), (rtsp_connection_close): + * gst/rtsp/rtspconnection.h: + Store connection IP address for later. + Add timeout args to all operations that might block forever. + Parse session timeout. + Only close sockets when not already closed. + + * gst/rtsp/rtspdefs.c: + * gst/rtsp/rtspdefs.h: + Add timeout return value and error string. + + * gst/rtsp/rtspmessage.c: (rtsp_message_init_response): + Add small comment. + 2007-05-01 Wim Taymans Patch by: Sjoerd Simons diff --git a/gst/rtsp/gstrtspsrc.c b/gst/rtsp/gstrtspsrc.c index ee383a4..a99a102 100644 --- a/gst/rtsp/gstrtspsrc.c +++ b/gst/rtsp/gstrtspsrc.c @@ -290,8 +290,6 @@ gst_rtspsrc_init (GstRTSPSrc * src, GstRTSPSrcClass * g_class) src->stream_rec_lock = g_new (GStaticRecMutex, 1); g_static_rec_mutex_init (src->stream_rec_lock); - src->loop_cond = g_cond_new (); - src->location = g_strdup (DEFAULT_LOCATION); src->url = NULL; @@ -316,7 +314,6 @@ gst_rtspsrc_finalize (GObject * object) g_static_rec_mutex_free (rtspsrc->stream_rec_lock); g_free (rtspsrc->stream_rec_lock); - g_cond_free (rtspsrc->loop_cond); g_free (rtspsrc->location); g_free (rtspsrc->req_location); g_free (rtspsrc->content_base); @@ -1280,8 +1277,8 @@ use_no_manager: goto no_element; /* take ownership */ - gst_object_ref (stream->udpsrc[0]); - gst_object_sink (stream->udpsrc[0]); + gst_object_ref (stream->udpsrc[1]); + gst_object_sink (stream->udpsrc[1]); gst_element_set_state (stream->udpsrc[1], GST_STATE_READY); } @@ -1350,9 +1347,11 @@ use_no_manager: else port = transport->server_port.max; - destination = transport->destination; + /* first take the source, then the endpoint to figure out where to send + * the RTCP. */ + destination = transport->source; if (destination == NULL) - destination = src->addr; + destination = src->connection->ip; GST_DEBUG_OBJECT (src, "configure UDP sink for %s:%d", destination, port); @@ -1375,7 +1374,7 @@ use_no_manager: stream->rtcppad = gst_element_get_pad (stream->udpsink, "sink"); /* get session RTCP pad */ - name = g_strdup_printf ("rtcp_src_%d", stream->id); + name = g_strdup_printf ("send_rtcp_src_%d", stream->id); pad = gst_element_get_request_pad (src->session, name); g_free (name); @@ -1557,10 +1556,43 @@ gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event) gst_event_unref (event); } +/* FIXME, handle server request, reply with OK, for now */ +static RTSPResult +gst_rtspsrc_handle_request (GstRTSPSrc * src, RTSPMessage * request) +{ + RTSPMessage response = { 0 }; + RTSPResult res; + + GST_DEBUG_OBJECT (src, "got server request message"); + + if (src->debug) + rtsp_message_dump (request); + + res = rtsp_message_init_response (&response, RTSP_STS_OK, "OK", request); + if (res < 0) + goto send_error; + + GST_DEBUG_OBJECT (src, "replying with OK"); + + if (src->debug) + rtsp_message_dump (&response); + + if ((res = rtsp_connection_send (src->connection, &response, NULL)) < 0) + goto send_error; + + return RTSP_OK; + + /* ERRORS */ +send_error: + { + return res; + } +} + static void gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) { - RTSPMessage response = { 0 }; + RTSPMessage message = { 0 }; RTSPResult res; gint channel; GList *lstream; @@ -1570,18 +1602,38 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) guint size; GstFlowReturn ret = GST_FLOW_OK; GstBuffer *buf; - gboolean is_rtcp = FALSE; + gboolean is_rtcp, have_data; + have_data = FALSE; do { GST_DEBUG_OBJECT (src, "doing receive"); - if ((res = rtsp_connection_receive (src->connection, &response)) < 0) + + if ((res = rtsp_connection_receive (src->connection, &message, NULL)) < 0) goto receive_error; - GST_DEBUG_OBJECT (src, "got packet type %d", response.type); + switch (message.type) { + case RTSP_MESSAGE_REQUEST: + /* server sends us a request message, handle it */ + if ((res = gst_rtspsrc_handle_request (src, &message)) < 0) + goto handle_request_failed; + break; + case RTSP_MESSAGE_RESPONSE: + /* we ignore response messages */ + GST_DEBUG_OBJECT (src, "ignoring response message"); + break; + case RTSP_MESSAGE_DATA: + GST_DEBUG_OBJECT (src, "got data message"); + have_data = TRUE; + break; + default: + GST_WARNING_OBJECT (src, "ignoring unknown message type %d", + message.type); + break; + } } - while (response.type != RTSP_MESSAGE_DATA); + while (!have_data); - channel = response.type_data.data.channel; + channel = message.type_data.data.channel; lstream = g_list_find_custom (src->streams, GINT_TO_POINTER (channel), (GCompareFunc) find_stream_by_channel); @@ -1591,13 +1643,16 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) stream = (GstRTSPStream *) lstream->data; if (channel == stream->channel[0]) { outpad = stream->channelpad[0]; + is_rtcp = FALSE; } else if (channel == stream->channel[1]) { outpad = stream->channelpad[1]; is_rtcp = TRUE; + } else { + is_rtcp = FALSE; } /* take a look at the body to figure out what we have */ - rtsp_message_get_body (&response, &data, &size); + rtsp_message_get_body (&message, &data, &size); if (size < 2) goto invalid_length; @@ -1612,8 +1667,8 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) if (outpad == NULL) goto unknown_stream; - /* and chain buffer to internal element */ - rtsp_message_steal_body (&response, &data, &size); + /* take the message body for further processing */ + rtsp_message_steal_body (&message, &data, &size); /* strip the trailing \0 */ size -= 1; @@ -1624,7 +1679,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) GST_BUFFER_SIZE (buf) = size; /* don't need message anymore */ - rtsp_message_unset (&response); + rtsp_message_unset (&message); GST_DEBUG_OBJECT (src, "pushing data of size %d on channel %d", size, channel); @@ -1652,7 +1707,7 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src) unknown_stream: { GST_DEBUG_OBJECT (src, "unknown stream on channel %d, ignored", channel); - rtsp_message_unset (&response); + rtsp_message_unset (&message); return; } receive_error: @@ -1664,9 +1719,20 @@ receive_error: g_free (str); if (src->debug) - rtsp_message_dump (&response); + rtsp_message_dump (&message); - rtsp_message_unset (&response); + rtsp_message_unset (&message); + ret = GST_FLOW_UNEXPECTED; + goto need_pause; + } +handle_request_failed: + { + gchar *str = rtsp_strresult (res); + + GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), + ("Could not send message. (%s)", str)); + g_free (str); + rtsp_message_unset (&message); ret = GST_FLOW_UNEXPECTED; goto need_pause; } @@ -1674,7 +1740,7 @@ invalid_length: { GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), ("Short message received.")); - rtsp_message_unset (&response); + rtsp_message_unset (&message); return; } need_pause: @@ -1707,21 +1773,118 @@ need_pause: } } +/* send server keep-alive */ +static RTSPResult +gst_rtspsrc_send_keep_alive (GstRTSPSrc * src) +{ + RTSPMessage request = { 0 }; + RTSPMessage response = { 0 }; + RTSPResult res; + + GST_DEBUG_OBJECT (src, "creating server keep-alive"); + + res = + rtsp_message_init_request (&request, RTSP_GET_PARAMETER, + src->req_location); + if (res < 0) + goto send_error; + + if (!gst_rtspsrc_send (src, &request, &response, NULL)) + goto send_error; + + rtsp_message_unset (&request); + + return RTSP_OK; + + /* ERRORS */ +send_error: + { + gchar *str = rtsp_strresult (res); + + rtsp_message_unset (&request); + GST_ELEMENT_WARNING (src, RESOURCE, WRITE, (NULL), + ("Could not send keep-alive. (%s)", str)); + g_free (str); + return res; + } +} + static void gst_rtspsrc_loop_udp (GstRTSPSrc * src) { gboolean restart = FALSE; + RTSPResult res; GST_OBJECT_LOCK (src); if (src->loop_cmd == CMD_STOP) goto stopping; - /* FIXME, we should continue reading the TCP socket because the server might - * send us requests */ while (src->loop_cmd == CMD_WAIT) { - GST_DEBUG_OBJECT (src, "waiting"); - GST_RTSP_LOOP_WAIT (src); - GST_DEBUG_OBJECT (src, "waiting done"); + GTimeVal tv_timeout; + gint timeout; + + GST_OBJECT_UNLOCK (src); + + while (TRUE) { + RTSPMessage message = { 0 }; + + /* calculate the session timeout. We should send the keep-alive request a + * little earlier to compensate for the round trip time to the server. We + * subtract 1 second here. */ + timeout = src->connection->timeout; + if (timeout > 1) + timeout -= 1; + + /* use the session timeout for receiving data */ + tv_timeout.tv_sec = timeout; + tv_timeout.tv_usec = 0; + + GST_DEBUG_OBJECT (src, "doing receive with timeout %d seconds", timeout); + + /* we should continue reading the TCP socket because the server might + * send us requests. When the session timeout expires, we need to send a + * keep-alive request to keep the session open. */ + res = rtsp_connection_receive (src->connection, &message, &tv_timeout); + + switch (res) { + case RTSP_OK: + GST_DEBUG_OBJECT (src, "we received a server message"); + break; + case RTSP_EINTR: + /* we got interrupted, see what we have to do */ + GST_DEBUG_OBJECT (src, "we got interrupted"); + /* unset flushing so we can do something else */ + rtsp_connection_flush (src->connection, FALSE); + goto interrupt; + case RTSP_ETIMEOUT: + /* ignore result, a warning was posted */ + GST_DEBUG_OBJECT (src, "timout, sending keep-alive"); + res = gst_rtspsrc_send_keep_alive (src); + continue; + default: + goto receive_error; + } + + switch (message.type) { + case RTSP_MESSAGE_REQUEST: + /* server sends us a request message, handle it */ + if ((res = gst_rtspsrc_handle_request (src, &message)) < 0) + goto handle_request_failed; + break; + case RTSP_MESSAGE_RESPONSE: + case RTSP_MESSAGE_DATA: + /* we ignore response and data messages */ + GST_DEBUG_OBJECT (src, "ignoring message"); + break; + default: + GST_WARNING_OBJECT (src, "ignoring unknown message type %d", + message.type); + break; + } + } + interrupt: + GST_OBJECT_LOCK (src); + GST_DEBUG_OBJECT (src, "we have command %d", src->loop_cmd); if (src->loop_cmd == CMD_STOP) goto stopping; } @@ -1762,7 +1925,7 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src) gst_rtspsrc_close (src); /* see if we have TCP left to try */ - if (!(src->cur_protocols & RTSP_LOWER_TRANS_TCP)) + if (!(src->protocols & RTSP_LOWER_TRANS_TCP)) goto no_protocols; /* open new connection using tcp */ @@ -1790,6 +1953,24 @@ stopping: gst_task_pause (src->task); return; } +receive_error: + { + gchar *str = rtsp_strresult (res); + + GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), + ("Could not receive message. (%s)", str)); + g_free (str); + return; + } +handle_request_failed: + { + gchar *str = rtsp_strresult (res); + + GST_ELEMENT_WARNING (src, RESOURCE, READ, (NULL), + ("Could not handle server message. (%s)", str)); + g_free (str); + return; + } no_protocols: { src->cur_protocols = 0; @@ -1815,7 +1996,8 @@ gst_rtspsrc_loop_send_cmd (GstRTSPSrc * src, gint cmd) { GST_OBJECT_LOCK (src); src->loop_cmd = cmd; - GST_RTSP_LOOP_SIGNAL (src); + if (cmd != CMD_WAIT) + rtsp_connection_flush (src->connection, TRUE); GST_OBJECT_UNLOCK (src); } @@ -1828,36 +2010,6 @@ gst_rtspsrc_loop (GstRTSPSrc * src) gst_rtspsrc_loop_udp (src); } -static RTSPResult -gst_rtspsrc_handle_request (GstRTSPSrc * src, RTSPMessage * request) -{ - RTSPMessage response = { 0 }; - RTSPResult res; - - res = rtsp_message_init_response (&response, RTSP_STS_OK, "OK", request); - if (res < 0) - goto send_error; - - if (src->debug) - rtsp_message_dump (&response); - - if ((res = rtsp_connection_send (src->connection, &response)) < 0) - goto send_error; - - return RTSP_OK; - - /* ERRORS */ -send_error: - { - gchar *str = rtsp_strresult (res); - - GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL), - ("Could not send message. (%s)", str)); - g_free (str); - return res; - } -} - #ifndef GST_DISABLE_GST_DEBUG const gchar * rtsp_auth_method_to_string (RTSPAuthMethod method) @@ -2085,11 +2237,11 @@ gst_rtspsrc_try_send (GstRTSPSrc * src, RTSPMessage * request, if (src->debug) rtsp_message_dump (request); - if ((res = rtsp_connection_send (src->connection, request)) < 0) + if ((res = rtsp_connection_send (src->connection, request, NULL)) < 0) goto send_error; next: - if ((res = rtsp_connection_receive (src->connection, response)) < 0) + if ((res = rtsp_connection_receive (src->connection, response, NULL)) < 0) goto receive_error; if (src->debug) @@ -2097,16 +2249,17 @@ next: switch (response->type) { case RTSP_MESSAGE_REQUEST: - /* FIXME, handle server request, reply with OK, for now */ if ((res = gst_rtspsrc_handle_request (src, response)) < 0) goto handle_request_failed; goto next; case RTSP_MESSAGE_RESPONSE: /* ok, a response is good */ + GST_DEBUG_OBJECT (src, "received response message"); break; default: case RTSP_MESSAGE_DATA: /* get next response */ + GST_DEBUG_OBJECT (src, "ignoring data response message"); goto next; } @@ -2587,7 +2740,7 @@ gst_rtspsrc_open (GstRTSPSrc * src) /* connect */ GST_DEBUG_OBJECT (src, "connecting (%s)...", src->req_location); - if ((res = rtsp_connection_connect (src->connection)) < 0) + if ((res = rtsp_connection_connect (src->connection, NULL)) < 0) goto could_not_connect; /* create OPTIONS */ @@ -3116,8 +3269,8 @@ gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message) gst_message_unref (message); break; - /* fatal our not our message, forward */ forward: + /* fatal but not our message, forward */ GST_BIN_CLASS (parent_class)->handle_message (bin, message); break; } diff --git a/gst/rtsp/gstrtspsrc.h b/gst/rtsp/gstrtspsrc.h index 7d595f6..96569bb 100644 --- a/gst/rtsp/gstrtspsrc.h +++ b/gst/rtsp/gstrtspsrc.h @@ -71,10 +71,6 @@ typedef struct _GstRTSPSrcClass GstRTSPSrcClass; #define GST_RTSP_STATE_LOCK(rtsp) (g_mutex_lock (GST_RTSP_STATE_GET_LOCK(rtsp))) #define GST_RTSP_STATE_UNLOCK(rtsp) (g_mutex_unlock (GST_RTSP_STATE_GET_LOCK(rtsp))) -#define GST_RTSP_LOOP_GET_COND(rtsp) (GST_RTSPSRC_CAST(rtsp)->loop_cond) -#define GST_RTSP_LOOP_WAIT(rtsp) (g_cond_wait(GST_RTSP_LOOP_GET_COND (rtsp), GST_OBJECT_GET_LOCK (rtsp))) -#define GST_RTSP_LOOP_SIGNAL(rtsp) (g_cond_signal(GST_RTSP_LOOP_GET_COND (rtsp))) - typedef struct _GstRTSPStream GstRTSPStream; #include "rtspext.h" @@ -126,7 +122,6 @@ struct _GstRTSPSrc { gint free_channel; /* cond to signal loop */ - GCond *loop_cond; gint loop_cmd; GMutex *state_lock; diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c index 448dccd..e2d375e 100644 --- a/gst/rtsp/rtspconnection.c +++ b/gst/rtsp/rtspconnection.c @@ -160,7 +160,7 @@ no_socket_pair: } RTSPResult -rtsp_connection_connect (RTSPConnection * conn) +rtsp_connection_connect (RTSPConnection * conn, GTimeVal * timeout) { gint fd; struct sockaddr_in sin; @@ -210,6 +210,7 @@ rtsp_connection_connect (RTSPConnection * conn) goto sys_error; conn->fd = fd; + conn->ip = ip; return RTSP_OK; @@ -259,7 +260,8 @@ append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str) } RTSPResult -rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message) +rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message, + GTimeVal * timeout) { GString *str; gint towrite; @@ -543,11 +545,13 @@ no_column: } RTSPResult -rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size) +rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size, + GTimeVal * timeout) { fd_set readfds; guint toread; gint retval; + struct timeval tv_timeout, *ptv_timeout = NULL; #ifndef G_OS_WIN32 gint avail; @@ -570,6 +574,13 @@ rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size) else if (avail >= toread) goto do_read; + /* configure timeout if any */ + if (timeout != NULL) { + tv_timeout.tv_sec = timeout->tv_sec; + tv_timeout.tv_usec = timeout->tv_usec; + ptv_timeout = &tv_timeout; + } + FD_ZERO (&readfds); FD_SET (conn->fd, &readfds); FD_SET (READ_SOCKET (conn), &readfds); @@ -578,12 +589,16 @@ rtsp_connection_read (RTSPConnection * conn, gpointer data, guint size) gint bytes; do { - retval = select (FD_SETSIZE, &readfds, NULL, NULL, NULL); + retval = select (FD_SETSIZE, &readfds, NULL, NULL, ptv_timeout); } while ((retval == -1 && errno == EINTR)); if (retval == -1) goto select_error; + /* check for timeout */ + if (retval == 0) + goto select_timeout; + if (FD_ISSET (READ_SOCKET (conn), &readfds)) { /* read all stop commands */ while (TRUE) { @@ -621,6 +636,10 @@ select_error: { return RTSP_ESYS; } +select_timeout: + { + return RTSP_ETIMEOUT; + } stopped: { return RTSP_EINTR; @@ -636,7 +655,8 @@ read_error: } static RTSPResult -read_body (RTSPConnection * conn, glong content_length, RTSPMessage * msg) +read_body (RTSPConnection * conn, glong content_length, RTSPMessage * msg, + GTimeVal * timeout) { gchar *body; RTSPResult res; @@ -650,7 +670,8 @@ read_body (RTSPConnection * conn, glong content_length, RTSPMessage * msg) body = g_malloc (content_length + 1); body[content_length] = '\0'; - RTSP_CHECK (rtsp_connection_read (conn, body, content_length), read_error); + RTSP_CHECK (rtsp_connection_read (conn, body, content_length, timeout), + read_error); content_length += 1; @@ -668,7 +689,8 @@ read_error: } RTSPResult -rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg) +rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg, + GTimeVal * timeout) { gchar buffer[4096]; gint line; @@ -690,7 +712,7 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg) guint8 c; /* read first character, this identifies data messages */ - RTSP_CHECK (rtsp_connection_read (conn, &c, 1), read_error); + RTSP_CHECK (rtsp_connection_read (conn, &c, 1, timeout), read_error); /* check for data packet, first character is $ */ if (c == '$') { @@ -699,18 +721,18 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg) /* data packets are $<1 byte channel><2 bytes length,BE> */ /* read channel, which is the next char */ - RTSP_CHECK (rtsp_connection_read (conn, &c, 1), read_error); + RTSP_CHECK (rtsp_connection_read (conn, &c, 1, timeout), read_error); /* now we create a data message */ rtsp_message_init_data (msg, (gint) c); /* next two bytes are the length of the data */ - RTSP_CHECK (rtsp_connection_read (conn, &size, 2), read_error); + RTSP_CHECK (rtsp_connection_read (conn, &size, 2, timeout), read_error); size = GUINT16_FROM_BE (size); /* and read the body */ - res = read_body (conn, size, msg); + res = read_body (conn, size, msg, timeout); need_body = FALSE; break; } else { @@ -754,7 +776,7 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg) &hdrval) == RTSP_OK) { /* there is, read the body */ content_length = atol (hdrval); - RTSP_CHECK (read_body (conn, content_length, msg), read_error); + RTSP_CHECK (read_body (conn, content_length, msg, timeout), read_error); } /* save session id in the connection for further use */ @@ -765,13 +787,25 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg) &session_id) == RTSP_OK) { gint sesslen, maxlen, i; + /* default session timeout */ + conn->timeout = 60; + sesslen = strlen (session_id); maxlen = sizeof (conn->session_id) - 1; /* the sessionid can have attributes marked with ; * Make sure we strip them */ for (i = 0; i < sesslen; i++) { - if (session_id[i] == ';') + if (session_id[i] == ';') { maxlen = i; + /* parse timeout */ + if (g_str_has_prefix (&session_id[i], ";timeout=")) { + gint timeout; + + /* if we parsed something valid, configure */ + if ((timeout = atoi (&session_id[i + 9])) > 0) + conn->timeout = timeout; + } + } } /* make sure to not overflow */ @@ -796,13 +830,15 @@ rtsp_connection_close (RTSPConnection * conn) g_return_val_if_fail (conn != NULL, RTSP_EINVAL); g_return_val_if_fail (conn->fd >= 0, RTSP_EINVAL); - res = CLOSE_SOCKET (conn->fd); + if (conn->fd != -1) { + res = CLOSE_SOCKET (conn->fd); #ifdef G_OS_WIN32 - WSACleanup (); + WSACleanup (); #endif - conn->fd = -1; - if (res != 0) - goto sys_error; + conn->fd = -1; + if (res != 0) + goto sys_error; + } return RTSP_OK; diff --git a/gst/rtsp/rtspconnection.h b/gst/rtsp/rtspconnection.h index fc3b28c..8ddaa4c 100644 --- a/gst/rtsp/rtspconnection.h +++ b/gst/rtsp/rtspconnection.h @@ -57,12 +57,14 @@ typedef struct _RTSPConnection RTSPUrl *url; /* connection state */ - gint fd; - gint control_sock[2]; + gint fd; + gint control_sock[2]; + gchar *ip; /* Session state */ gint cseq; /* sequence number */ gchar session_id[512]; /* session id */ + gint timeout; /* session timeout in seconds */ /* Authentication */ RTSPAuthMethod auth_method; @@ -71,20 +73,20 @@ typedef struct _RTSPConnection } RTSPConnection; /* opening/closing a connection */ -RTSPResult rtsp_connection_create (RTSPUrl *url, RTSPConnection **conn); -RTSPResult rtsp_connection_connect (RTSPConnection *conn); -RTSPResult rtsp_connection_close (RTSPConnection *conn); -RTSPResult rtsp_connection_free (RTSPConnection *conn); +RTSPResult rtsp_connection_create (RTSPUrl *url, RTSPConnection **conn); +RTSPResult rtsp_connection_connect (RTSPConnection *conn, GTimeVal *timeout); +RTSPResult rtsp_connection_close (RTSPConnection *conn); +RTSPResult rtsp_connection_free (RTSPConnection *conn); /* sending/receiving messages */ -RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message); -RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message); +RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); +RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message, GTimeVal *timeout); -RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush); +RTSPResult rtsp_connection_flush (RTSPConnection *conn, gboolean flush); /* Configure Authentication data */ -RTSPResult rtsp_connection_set_auth (RTSPConnection *conn, - RTSPAuthMethod method, gchar *user, gchar *pass); +RTSPResult rtsp_connection_set_auth (RTSPConnection *conn, RTSPAuthMethod method, + gchar *user, gchar *pass); G_END_DECLS diff --git a/gst/rtsp/rtspdefs.c b/gst/rtsp/rtspdefs.c index 413470e..70cef7e 100644 --- a/gst/rtsp/rtspdefs.c +++ b/gst/rtsp/rtspdefs.c @@ -66,6 +66,7 @@ static const gchar *rtsp_results[] = { "Received end-of-file", "Network error: %s", "Host is not a valid IP address", + "Timout while waiting for server response", "Unknown error (%d)", NULL }; diff --git a/gst/rtsp/rtspdefs.h b/gst/rtsp/rtspdefs.h index f72a9a6..0be90c7 100644 --- a/gst/rtsp/rtspdefs.h +++ b/gst/rtsp/rtspdefs.h @@ -66,8 +66,9 @@ typedef enum { RTSP_EEOF = -11, RTSP_ENET = -12, RTSP_ENOTIP = -13, + RTSP_ETIMEOUT = -14, - RTSP_ELAST = -14, + RTSP_ELAST = -15, } RTSPResult; typedef enum { diff --git a/gst/rtsp/rtspmessage.c b/gst/rtsp/rtspmessage.c index de68699..abd6d4d 100644 --- a/gst/rtsp/rtspmessage.c +++ b/gst/rtsp/rtspmessage.c @@ -142,10 +142,12 @@ rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code, if (request) { gchar *header; + /* copy CSEQ */ if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header) == RTSP_OK) { rtsp_message_add_header (msg, RTSP_HDR_CSEQ, header); } + /* copy session id */ if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header) == RTSP_OK) { char *pos;