2 * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
24 * Permission is hereby granted, free of charge, to any person obtaining a copy of
25 * this software and associated documentation files (the "Software"), to deal in
26 * the Software without restriction, including without limitation the rights to
27 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28 * of the Software, and to permit persons to whom the Software is furnished to do
29 * so, subject to the following conditions:
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
44 * SECTION:gstrtspconnection
45 * @short_description: manage RTSP connections
46 * @see_also: gstrtspurl
50 * This object manages the RTSP connection to the server. It provides function
51 * to receive and send bytes and messages.
55 * Last reviewed on 2007-07-24 (0.10.14)
73 /* we include this here to get the G_OS_* defines */
79 #define EINPROGRESS WSAEINPROGRESS
81 #include <sys/ioctl.h>
83 #include <sys/socket.h>
84 #include <netinet/in.h>
85 #include <arpa/inet.h>
89 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
90 #include <sys/filio.h>
93 #include "gstrtspconnection.h"
94 #include "gstrtspbase64.h"
97 #define FIONREAD_TYPE gulong
98 #define IOCTL_SOCKET ioctlsocket
99 #define READ_SOCKET(fd, buf, len) recv (fd, buf, len, 0)
100 #define WRITE_SOCKET(fd, buf, len) send (fd, buf, len, 0)
101 #define CLOSE_SOCKET(sock) closesocket (sock)
102 #define ERRNO_IS_NOT_EAGAIN (WSAGetLastError () != WSAEWOULDBLOCK)
103 #define ERRNO_IS_NOT_EINTR (WSAGetLastError () != WSAEINTR)
104 /* According to Microsoft's connect() documentation this one returns
105 * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
106 #define ERRNO_IS_NOT_EINPROGRESS (WSAGetLastError () != WSAEWOULDBLOCK)
108 #define FIONREAD_TYPE gint
109 #define IOCTL_SOCKET ioctl
110 #define READ_SOCKET(fd, buf, len) read (fd, buf, len)
111 #define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
112 #define CLOSE_SOCKET(sock) close (sock)
113 #define ERRNO_IS_NOT_EAGAIN (errno != EAGAIN)
114 #define ERRNO_IS_NOT_EINTR (errno != EINTR)
115 #define ERRNO_IS_NOT_EINPROGRESS (errno != EINPROGRESS)
120 inet_aton (const char *c, struct in_addr *paddr)
122 /* note that inet_addr is deprecated on unix because
123 * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
125 paddr->s_addr = inet_addr (c);
127 if (paddr->s_addr == INADDR_NONE)
135 * gst_rtsp_connection_create:
136 * @url: a #GstRTSPUrl
137 * @conn: a #GstRTSPConnection
139 * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
140 * The connection will not yet attempt to connect to @url, use
141 * gst_rtsp_connection_connect().
143 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
146 gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
148 GstRTSPConnection *newconn;
150 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
152 newconn = g_new0 (GstRTSPConnection, 1);
154 if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
159 newconn->timer = g_timer_new ();
161 newconn->auth_method = GST_RTSP_AUTH_NONE;
162 newconn->username = NULL;
163 newconn->passwd = NULL;
173 return GST_RTSP_ESYS;
178 * gst_rtsp_connection_connect:
179 * @conn: a #GstRTSPConnection
180 * @timeout: a #GTimeVal timeout
182 * Attempt to connect to the url of @conn made with
183 * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
184 * forever. If @timeout contains a valid timeout, this function will return
185 * #GST_RTSP_ETIMEOUT after the timeout expired.
187 * This function can be cancelled with gst_rtsp_connection_flush().
189 * Returns: #GST_RTSP_OK when a connection could be made.
192 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
195 struct sockaddr_in sa_in;
196 struct hostent *hostinfo;
206 unsigned long flags = 1;
207 struct in_addr *addrp;
210 gchar ipbuf[INET_ADDRSTRLEN];
211 #endif /* G_OS_WIN32 */
213 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
214 g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
215 g_return_val_if_fail (conn->fd.fd < 0, GST_RTSP_EINVAL);
219 /* first check if it already is an IP address */
220 if (inet_aton (url->host, &addr)) {
223 hostinfo = gethostbyname (url->host);
225 goto not_resolved; /* h_errno set */
227 if (hostinfo->h_addrtype != AF_INET)
228 goto not_ip; /* host not an IP host */
230 addrp = (struct in_addr *) hostinfo->h_addr_list[0];
231 /* this is not threadsafe */
232 ip = inet_ntoa (*addrp);
234 addrs = hostinfo->h_addr_list;
235 ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
237 #endif /* G_OS_WIN32 */
240 /* get the port from the url */
241 gst_rtsp_url_get_port (url, &port);
243 memset (&sa_in, 0, sizeof (sa_in));
244 sa_in.sin_family = AF_INET; /* network socket */
245 sa_in.sin_port = htons (port); /* on port */
246 sa_in.sin_addr.s_addr = inet_addr (ip); /* on host ip */
248 fd = socket (AF_INET, SOCK_STREAM, 0);
252 /* set to non-blocking mode so that we can cancel the connect */
254 fcntl (fd, F_SETFL, O_NONBLOCK);
256 ioctlsocket (fd, FIONBIO, &flags);
257 #endif /* G_OS_WIN32 */
259 /* add the socket to our fdset */
261 gst_poll_add_fd (conn->fdset, &conn->fd);
263 /* we are going to connect ASYNC now */
264 ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
267 if (ERRNO_IS_NOT_EINPROGRESS)
270 /* wait for connect to complete up to the specified timeout or until we got
272 gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
274 to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
277 retval = gst_poll_wait (conn->fdset, to);
278 } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
282 else if (retval == -1)
285 gst_poll_fd_ignored (conn->fdset, &conn->fd);
288 conn->ip = g_strdup (ip);
294 if (conn->fd.fd >= 0) {
295 gst_poll_remove_fd (conn->fdset, &conn->fd);
300 return GST_RTSP_ESYS;
304 return GST_RTSP_ENET;
308 return GST_RTSP_ENOTIP;
312 if (conn->fd.fd >= 0) {
313 gst_poll_remove_fd (conn->fdset, &conn->fd);
318 return GST_RTSP_ETIMEOUT;
323 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
325 switch (conn->auth_method) {
326 case GST_RTSP_AUTH_BASIC:{
328 g_strdup_printf ("%s:%s", conn->username, conn->passwd);
330 gst_rtsp_base64_encode (user_pass, strlen (user_pass));
331 gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
333 gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
337 g_free (user_pass64);
338 g_free (auth_string);
348 add_date_header (GstRTSPMessage * message)
351 gchar date_string[100];
358 g_get_current_time (&tv);
359 t = (time_t) tv.tv_sec;
362 strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
363 gmtime_r (&t, &tm_));
365 strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
369 gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
373 * gst_rtsp_connection_write:
374 * @conn: a #GstRTSPConnection
375 * @data: the data to write
376 * @size: the size of @data
377 * @timeout: a timeout value or #NULL
379 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
380 * the specified @timeout. @timeout can be #NULL, in which case this function
381 * might block forever.
383 * This function can be cancelled with gst_rtsp_connection_flush().
385 * Returns: #GST_RTSP_OK on success.
388 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
389 guint size, GTimeVal * timeout)
395 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
396 g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
398 gst_poll_set_controllable (conn->fdset, TRUE);
399 gst_poll_fd_ctl_write (conn->fdset, &conn->fd, TRUE);
400 gst_poll_fd_ctl_read (conn->fdset, &conn->fd, FALSE);
402 to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
406 while (towrite > 0) {
410 retval = gst_poll_wait (conn->fdset, to);
411 } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
423 /* now we can write */
424 written = WRITE_SOCKET (conn->fd.fd, data, towrite);
426 if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
438 return GST_RTSP_ETIMEOUT;
442 return GST_RTSP_ESYS;
446 return GST_RTSP_EINTR;
450 return GST_RTSP_ESYS;
455 * gst_rtsp_connection_send:
456 * @conn: a #GstRTSPConnection
457 * @message: the message to send
458 * @timeout: a timeout value or #NULL
460 * Attempt to send @message to the connected @conn, blocking up to
461 * the specified @timeout. @timeout can be #NULL, in which case this function
462 * might block forever.
464 * This function can be cancelled with gst_rtsp_connection_flush().
466 * Returns: #GST_RTSP_OK on success.
469 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
480 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
481 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
484 error = WSAStartup (0x0202, &w);
489 if (w.wVersion != 0x0202)
493 str = g_string_new ("");
495 switch (message->type) {
496 case GST_RTSP_MESSAGE_REQUEST:
497 /* create request string, add CSeq */
498 g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
500 gst_rtsp_method_as_text (message->type_data.request.method),
501 message->type_data.request.uri, conn->cseq++);
502 /* add session id if we have one */
503 if (conn->session_id[0] != '\0') {
504 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
507 /* add any authentication headers */
508 add_auth_header (conn, message);
510 case GST_RTSP_MESSAGE_RESPONSE:
511 /* create response string */
512 g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
513 message->type_data.response.code, message->type_data.response.reason);
515 case GST_RTSP_MESSAGE_DATA:
517 guint8 data_header[4];
519 /* prepare data header */
520 data_header[0] = '$';
521 data_header[1] = message->type_data.data.channel;
522 data_header[2] = (message->body_size >> 8) & 0xff;
523 data_header[3] = message->body_size & 0xff;
525 /* create string with header and data */
526 str = g_string_append_len (str, (gchar *) data_header, 4);
528 g_string_append_len (str, (gchar *) message->body,
533 g_return_val_if_reached (GST_RTSP_EINVAL);
537 /* append headers and body */
538 if (message->type != GST_RTSP_MESSAGE_DATA) {
539 /* add date header */
540 add_date_header (message);
543 gst_rtsp_message_append_headers (message, str);
545 /* append Content-Length and body if needed */
546 if (message->body != NULL && message->body_size > 0) {
549 len = g_strdup_printf ("%d", message->body_size);
550 g_string_append_printf (str, "%s: %s\r\n",
551 gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
553 /* header ends here */
554 g_string_append (str, "\r\n");
556 g_string_append_len (str, (gchar *) message->body,
559 /* just end headers */
560 g_string_append (str, "\r\n");
566 gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
568 g_string_free (str, TRUE);
575 g_warning ("Error %d on WSAStartup", error);
576 return GST_RTSP_EWSASTART;
580 g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
583 return GST_RTSP_EWSAVERSION;
589 read_line (gint fd, gchar * buffer, guint size)
597 r = READ_SOCKET (fd, &c, 1);
601 if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
604 if (c == '\n') /* end on \n */
606 if (c == '\r') /* ignore \r */
619 return GST_RTSP_EEOF;
623 return GST_RTSP_ESYS;
628 read_string (gchar * dest, gint size, gchar ** src)
634 while (g_ascii_isspace (**src))
637 while (!g_ascii_isspace (**src) && **src != '\0') {
647 read_key (gchar * dest, gint size, gchar ** src)
652 while (**src != ':' && **src != '\0') {
662 parse_response_status (gchar * buffer, GstRTSPMessage * msg)
665 gchar versionstr[20];
672 read_string (versionstr, sizeof (versionstr), &bptr);
673 read_string (codestr, sizeof (codestr), &bptr);
674 code = atoi (codestr);
676 while (g_ascii_isspace (*bptr))
679 if (strcmp (versionstr, "RTSP/1.0") == 0)
680 GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
682 else if (strncmp (versionstr, "RTSP/", 5) == 0) {
683 GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
685 msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
693 return GST_RTSP_EPARSE;
698 parse_request_line (gchar * buffer, GstRTSPMessage * msg)
700 GstRTSPResult res = GST_RTSP_OK;
701 gchar versionstr[20];
705 GstRTSPMethod method;
709 read_string (methodstr, sizeof (methodstr), &bptr);
710 method = gst_rtsp_find_method (methodstr);
712 read_string (urlstr, sizeof (urlstr), &bptr);
714 res = GST_RTSP_EPARSE;
716 read_string (versionstr, sizeof (versionstr), &bptr);
719 res = GST_RTSP_EPARSE;
721 if (strcmp (versionstr, "RTSP/1.0") == 0) {
722 if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
723 res = GST_RTSP_EPARSE;
724 } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
725 if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
726 res = GST_RTSP_EPARSE;
727 msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
729 gst_rtsp_message_init_request (msg, method, urlstr);
730 msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
731 res = GST_RTSP_EPARSE;
737 /* parsing lines means reading a Key: Value pair */
739 parse_line (gchar * buffer, GstRTSPMessage * msg)
743 GstRTSPHeaderField field;
748 read_key (key, sizeof (key), &bptr);
754 field = gst_rtsp_find_header_field (key);
755 if (field != GST_RTSP_HDR_INVALID) {
756 while (g_ascii_isspace (*bptr))
758 gst_rtsp_message_add_header (msg, field, bptr);
765 return GST_RTSP_EPARSE;
770 * gst_rtsp_connection_read_internal:
771 * @conn: a #GstRTSPConnection
772 * @data: the data to read
773 * @size: the size of @data
774 * @timeout: a timeout value or #NULL
775 * @allow_interrupt: can the pending read be interrupted
777 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
778 * the specified @timeout. @timeout can be #NULL, in which case this function
779 * might block forever.
781 * This function can be cancelled with gst_rtsp_connection_flush() only if
782 * @allow_interrupt is set.
784 * Returns: #GST_RTSP_OK on success.
787 gst_rtsp_connection_read_internal (GstRTSPConnection * conn, guint8 * data,
788 guint size, GTimeVal * timeout, gboolean allow_interrupt)
795 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
796 g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
803 /* configure timeout if any */
804 to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
806 /* if the call fails, just go in the select.. it should not fail. Else if
807 * there is enough data to read, skip the select call al together.*/
808 if (IOCTL_SOCKET (conn->fd.fd, FIONREAD, &avail) < 0)
810 else if (avail >= toread)
813 gst_poll_set_controllable (conn->fdset, allow_interrupt);
814 gst_poll_fd_ctl_write (conn->fdset, &conn->fd, FALSE);
815 gst_poll_fd_ctl_read (conn->fdset, &conn->fd, TRUE);
821 retval = gst_poll_wait (conn->fdset, to);
822 } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
831 /* check for timeout */
836 /* if we get here there is activity on the real fd since the select
837 * completed and the control socket was not readable. */
838 bytes = READ_SOCKET (conn->fd.fd, data, toread);
841 } else if (bytes < 0) {
842 if (ERRNO_IS_NOT_EAGAIN && ERRNO_IS_NOT_EINTR)
854 return GST_RTSP_ESYS;
858 return GST_RTSP_ETIMEOUT;
862 return GST_RTSP_EINTR;
866 return GST_RTSP_EEOF;
870 return GST_RTSP_ESYS;
875 * gst_rtsp_connection_read:
876 * @conn: a #GstRTSPConnection
877 * @data: the data to read
878 * @size: the size of @data
879 * @timeout: a timeout value or #NULL
881 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
882 * the specified @timeout. @timeout can be #NULL, in which case this function
883 * might block forever.
885 * This function can be cancelled with gst_rtsp_connection_flush().
887 * Returns: #GST_RTSP_OK on success.
890 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
893 return gst_rtsp_connection_read_internal (conn, data, size, timeout, TRUE);
898 read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
904 if (content_length <= 0) {
910 body = g_malloc (content_length + 1);
911 body[content_length] = '\0';
913 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, body, content_length,
914 timeout, FALSE), read_error);
919 gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
932 * gst_rtsp_connection_receive:
933 * @conn: a #GstRTSPConnection
934 * @message: the message to read
935 * @timeout: a timeout value or #NULL
937 * Attempt to read into @message from the connected @conn, blocking up to
938 * the specified @timeout. @timeout can be #NULL, in which case this function
939 * might block forever.
941 * This function can be cancelled with gst_rtsp_connection_flush().
943 * Returns: #GST_RTSP_OK on success.
946 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
951 glong content_length;
955 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
956 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
963 /* parse first line and headers */
964 while (res == GST_RTSP_OK) {
967 /* read first character, this identifies data messages */
968 /* This is the only read() that we allow to be interrupted */
969 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
972 /* check for data packet, first character is $ */
976 /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
978 /* read channel, which is the next char */
979 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
982 /* now we create a data message */
983 gst_rtsp_message_init_data (message, c);
985 /* next two bytes are the length of the data */
986 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn,
987 (guint8 *) & size, 2, timeout, FALSE), read_error);
989 size = GUINT16_FROM_BE (size);
991 /* and read the body */
992 res = read_body (conn, size, message, timeout);
998 /* we have a regular response */
1003 /* should not happen */
1008 GST_RTSP_CHECK (read_line (conn->fd.fd, buffer + offset,
1009 sizeof (buffer) - offset), read_error);
1011 if (buffer[0] == '\0')
1015 /* first line, check for response status */
1016 if (g_str_has_prefix (buffer, "RTSP")) {
1017 res = parse_response_status (buffer, message);
1019 res = parse_request_line (buffer, message);
1022 /* else just parse the line */
1023 parse_line (buffer, message);
1029 /* read the rest of the body if needed */
1034 /* see if there is a Content-Length header */
1035 if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_CONTENT_LENGTH,
1036 &hdrval, 0) == GST_RTSP_OK) {
1037 /* there is, read the body */
1038 content_length = atol (hdrval);
1039 GST_RTSP_CHECK (read_body (conn, content_length, message, timeout),
1043 /* save session id in the connection for further use */
1044 if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
1045 &session_id, 0) == GST_RTSP_OK) {
1048 /* default session timeout */
1051 maxlen = sizeof (conn->session_id) - 1;
1052 /* the sessionid can have attributes marked with ;
1053 * Make sure we strip them */
1054 for (i = 0; session_id[i] != '\0'; i++) {
1055 if (session_id[i] == ';') {
1060 } while (g_ascii_isspace (session_id[i]));
1061 if (g_str_has_prefix (&session_id[i], "timeout=")) {
1064 /* if we parsed something valid, configure */
1065 if ((to = atoi (&session_id[i + 9])) > 0)
1072 /* make sure to not overflow */
1073 strncpy (conn->session_id, session_id, maxlen);
1074 conn->session_id[maxlen] = '\0';
1086 * gst_rtsp_connection_close:
1087 * @conn: a #GstRTSPConnection
1089 * Close the connected @conn.
1091 * Returns: #GST_RTSP_OK on success.
1094 gst_rtsp_connection_close (GstRTSPConnection * conn)
1098 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1103 if (conn->fd.fd != -1) {
1104 gst_poll_remove_fd (conn->fdset, &conn->fd);
1105 res = CLOSE_SOCKET (conn->fd.fd);
1118 return GST_RTSP_ESYS;
1123 * gst_rtsp_connection_free:
1124 * @conn: a #GstRTSPConnection
1126 * Close and free @conn.
1128 * Returns: #GST_RTSP_OK on success.
1131 gst_rtsp_connection_free (GstRTSPConnection * conn)
1135 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1137 res = gst_rtsp_connection_close (conn);
1138 gst_poll_free (conn->fdset);
1142 g_timer_destroy (conn->timer);
1143 g_free (conn->username);
1144 g_free (conn->passwd);
1151 * gst_rtsp_connection_poll:
1152 * @conn: a #GstRTSPConnection
1153 * @events: a bitmask of #GstRTSPEvent flags to check
1154 * @revents: location for result flags
1155 * @timeout: a timeout
1157 * Wait up to the specified @timeout for the connection to become available for
1158 * at least one of the operations specified in @events. When the function returns
1159 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
1162 * @timeout can be #NULL, in which case this function might block forever.
1164 * This function can be cancelled with gst_rtsp_connection_flush().
1166 * Returns: #GST_RTSP_OK on success.
1171 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
1172 GstRTSPEvent * revents, GTimeVal * timeout)
1177 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1178 g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
1179 g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
1181 gst_poll_set_controllable (conn->fdset, TRUE);
1183 /* add fd to writer set when asked to */
1184 gst_poll_fd_ctl_write (conn->fdset, &conn->fd, events & GST_RTSP_EV_WRITE);
1186 /* add fd to reader set when asked to */
1187 gst_poll_fd_ctl_read (conn->fdset, &conn->fd, events & GST_RTSP_EV_READ);
1189 /* configure timeout if any */
1190 to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
1193 retval = gst_poll_wait (conn->fdset, to);
1194 } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
1197 goto select_timeout;
1207 if (events & GST_RTSP_EV_READ) {
1208 if (gst_poll_fd_can_read (conn->fdset, &conn->fd))
1209 *revents |= GST_RTSP_EV_READ;
1211 if (events & GST_RTSP_EV_WRITE) {
1212 if (gst_poll_fd_can_write (conn->fdset, &conn->fd))
1213 *revents |= GST_RTSP_EV_WRITE;
1220 return GST_RTSP_ETIMEOUT;
1224 return GST_RTSP_ESYS;
1228 return GST_RTSP_EINTR;
1233 * gst_rtsp_connection_next_timeout:
1234 * @conn: a #GstRTSPConnection
1235 * @timeout: a timeout
1237 * Calculate the next timeout for @conn, storing the result in @timeout.
1239 * Returns: #GST_RTSP_OK.
1242 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
1248 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1249 g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
1251 elapsed = g_timer_elapsed (conn->timer, &usec);
1252 if (elapsed >= conn->timeout) {
1256 sec = conn->timeout - elapsed;
1259 timeout->tv_sec = sec;
1260 timeout->tv_usec = usec;
1266 * gst_rtsp_connection_reset_timeout:
1267 * @conn: a #GstRTSPConnection
1269 * Reset the timeout of @conn.
1271 * Returns: #GST_RTSP_OK.
1274 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
1276 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1278 g_timer_start (conn->timer);
1284 * gst_rtsp_connection_flush:
1285 * @conn: a #GstRTSPConnection
1286 * @flush: start or stop the flush
1288 * Start or stop the flushing action on @conn. When flushing, all current
1289 * and future actions on @conn will return #GST_RTSP_EINTR until the connection
1290 * is set to non-flushing mode again.
1292 * Returns: #GST_RTSP_OK.
1295 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
1297 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1299 gst_poll_set_flushing (conn->fdset, flush);
1305 * gst_rtsp_connection_set_auth:
1306 * @conn: a #GstRTSPConnection
1307 * @method: authentication method
1309 * @pass: the password
1311 * Configure @conn for authentication mode @method with @user and @pass as the
1312 * user and password respectively.
1314 * Returns: #GST_RTSP_OK.
1317 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
1318 GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
1320 /* Digest isn't implemented yet */
1321 if (method == GST_RTSP_AUTH_DIGEST)
1322 return GST_RTSP_ENOTIMPL;
1324 /* Make sure the username and passwd are being set for authentication */
1325 if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
1326 return GST_RTSP_EINVAL;
1328 /* ":" chars are not allowed in usernames for basic auth */
1329 if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
1330 return GST_RTSP_EINVAL;
1332 g_free (conn->username);
1333 g_free (conn->passwd);
1335 conn->auth_method = method;
1336 conn->username = g_strdup (user);
1337 conn->passwd = g_strdup (pass);