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)
71 /* we include this here to get the G_OS_* defines */
77 #define EINPROGRESS WSAEINPROGRESS
79 #include <sys/ioctl.h>
81 #include <sys/socket.h>
82 #include <netinet/in.h>
83 #include <arpa/inet.h>
86 #ifdef HAVE_FIONREAD_IN_SYS_FILIO
87 #include <sys/filio.h>
90 #include "gstrtspconnection.h"
91 #include "gstrtspbase64.h"
93 /* the select call is also performed on the control sockets, that way
94 * we can send special commands to unlock or restart the select call */
95 #define CONTROL_RESTART 'R' /* restart the select call */
96 #define CONTROL_STOP 'S' /* stop the select call */
97 #define CONTROL_SOCKETS(conn) conn->control_sock
98 #define WRITE_SOCKET(conn) conn->control_sock[1]
99 #define READ_SOCKET(conn) conn->control_sock[0]
101 #define SEND_COMMAND(conn, command) \
103 unsigned char c; c = command; \
104 write (WRITE_SOCKET(conn), &c, 1); \
107 #define READ_COMMAND(conn, command, res) \
109 res = read(READ_SOCKET(conn), &command, 1); \
113 #define FIONREAD_TYPE gulong
114 #define IOCTL_SOCKET ioctlsocket
115 #define CLOSE_SOCKET(sock) closesocket(sock);
117 #define FIONREAD_TYPE gint
118 #define IOCTL_SOCKET ioctl
119 #define CLOSE_SOCKET(sock) close(sock);
124 inet_aton (const char *c, struct in_addr *paddr)
126 /* note that inet_addr is deprecated on unix because
127 * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
129 paddr->s_addr = inet_addr (c);
131 if (paddr->s_addr == INADDR_NONE)
139 * gst_rtsp_connection_create:
140 * @url: a #GstRTSPUrl
141 * @conn: a #GstRTSPConnection
143 * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
144 * The connection will not yet attempt to connect to @url, use
145 * gst_rtsp_connection_connect().
147 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
150 gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
153 GstRTSPConnection *newconn;
157 #endif /* G_OS_WIN32 */
159 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
161 newconn = g_new0 (GstRTSPConnection, 1);
164 /* This should work on UNIX too. PF_UNIX sockets replaced with pipe */
165 /* pipe( CONTROL_SOCKETS(newconn) ) */
166 if ((ret = _pipe (CONTROL_SOCKETS (newconn), 4096, _O_BINARY)) < 0)
169 ioctlsocket (READ_SOCKET (newconn), FIONBIO, &flags);
170 ioctlsocket (WRITE_SOCKET (newconn), FIONBIO, &flags);
173 socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (newconn))) < 0)
176 fcntl (READ_SOCKET (newconn), F_SETFL, O_NONBLOCK);
177 fcntl (WRITE_SOCKET (newconn), F_SETFL, O_NONBLOCK);
182 newconn->timer = g_timer_new ();
184 newconn->auth_method = GST_RTSP_AUTH_NONE;
185 newconn->username = NULL;
186 newconn->passwd = NULL;
196 return GST_RTSP_ESYS;
201 * gst_rtsp_connection_connect:
202 * @conn: a #GstRTSPConnection
203 * @timeout: a #GTimeVal timeout
205 * Attempt to connect to the url of @conn made with
206 * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
207 * forever. If @timeout contains a valid timeout, this function will return
208 * #GST_RTSP_ETIMEOUT after the timeout expired.
210 * Returns: #GST_RTSP_OK when a connection could be made.
213 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
216 struct sockaddr_in sa_in;
217 struct hostent *hostinfo;
225 struct timeval tv, *tvp;
230 struct in_addr *addrp;
233 gchar ipbuf[INET_ADDRSTRLEN];
234 #endif /* G_OS_WIN32 */
236 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
237 g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
238 g_return_val_if_fail (conn->fd < 0, GST_RTSP_EINVAL);
242 /* first check if it already is an IP address */
243 if (inet_aton (url->host, &addr)) {
246 hostinfo = gethostbyname (url->host);
248 goto not_resolved; /* h_errno set */
250 if (hostinfo->h_addrtype != AF_INET)
251 goto not_ip; /* host not an IP host */
253 addrp = (struct in_addr *) hostinfo->h_addr_list[0];
254 /* this is not threadsafe */
255 ip = inet_ntoa (*addrp);
257 addrs = hostinfo->h_addr_list;
258 ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
260 #endif /* G_OS_WIN32 */
263 /* get the port from the url */
264 gst_rtsp_url_get_port (url, &port);
266 memset (&sa_in, 0, sizeof (sa_in));
267 sa_in.sin_family = AF_INET; /* network socket */
268 sa_in.sin_port = htons (port); /* on port */
269 sa_in.sin_addr.s_addr = inet_addr (ip); /* on host ip */
271 fd = socket (AF_INET, SOCK_STREAM, 0);
275 /* set to non-blocking mode so that we can cancel the connect */
277 fcntl (fd, F_SETFL, O_NONBLOCK);
279 ioctlsocket (fd, FIONBIO, &flags);
280 #endif /* G_OS_WIN32 */
282 /* we are going to connect ASYNC now */
283 ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
286 if (errno != EINPROGRESS)
289 /* wait for connect to complete up to the specified timeout or until we got
292 FD_SET (fd, &writefds);
294 FD_SET (READ_SOCKET (conn), &readfds);
297 tv.tv_sec = timeout->tv_sec;
298 tv.tv_usec = timeout->tv_usec;
304 max_fd = MAX (fd, READ_SOCKET (conn));
307 retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
308 } while ((retval == -1 && errno == EINTR));
312 else if (retval == -1)
317 conn->ip = g_strdup (ip);
325 return GST_RTSP_ESYS;
329 return GST_RTSP_ENET;
333 return GST_RTSP_ENOTIP;
337 return GST_RTSP_ETIMEOUT;
342 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
344 switch (conn->auth_method) {
345 case GST_RTSP_AUTH_BASIC:{
347 g_strdup_printf ("%s:%s", conn->username, conn->passwd);
349 gst_rtsp_base64_encode (user_pass, strlen (user_pass));
350 gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
352 gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
356 g_free (user_pass64);
357 g_free (auth_string);
367 add_date_header (GstRTSPMessage * message)
370 gchar date_string[100];
372 g_get_current_time (&tv);
373 strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
374 gmtime (&tv.tv_sec));
376 gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
380 * gst_rtsp_connection_write:
381 * @conn: a #GstRTSPConnection
382 * @data: the data to write
383 * @size: the size of @data
384 * @timeout: a timeout value or #NULL
386 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
387 * the specified @timeout. @timeout can be #NULL, in which case this function
388 * might block forever.
390 * This function can be canceled with gst_rtsp_connection_flush().
392 * Returns: #GST_RTSP_OK on success.
395 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
396 guint size, GTimeVal * timeout)
403 struct timeval tv, *tvp;
405 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
406 g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
409 FD_SET (conn->fd, &writefds);
412 max_fd = MAX (conn->fd, READ_SOCKET (conn));
415 tv.tv_sec = timeout->tv_sec;
416 tv.tv_usec = timeout->tv_usec;
424 while (towrite > 0) {
427 /* set bit inside the loop for when we loop to read the rest of the data */
428 FD_SET (READ_SOCKET (conn), &readfds);
431 retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
432 } while ((retval == -1 && errno == EINTR));
440 if (FD_ISSET (READ_SOCKET (conn), &readfds))
443 /* now we can write */
444 written = write (conn->fd, data, towrite);
446 if (errno != EAGAIN && errno != EINTR)
458 return GST_RTSP_ETIMEOUT;
462 return GST_RTSP_ESYS;
466 return GST_RTSP_EINTR;
470 return GST_RTSP_ESYS;
475 * gst_rtsp_connection_send:
476 * @conn: a #GstRTSPConnection
477 * @message: the message to send
478 * @timeout: a timeout value or #NULL
480 * Attempt to send @message to the connected @conn, blocking up to
481 * the specified @timeout. @timeout can be #NULL, in which case this function
482 * might block forever.
484 * This function can be canceled with gst_rtsp_connection_flush().
486 * Returns: #GST_RTSP_OK on success.
489 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
500 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
501 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
504 error = WSAStartup (0x0202, &w);
509 if (w.wVersion != 0x0202)
513 str = g_string_new ("");
515 switch (message->type) {
516 case GST_RTSP_MESSAGE_REQUEST:
517 /* create request string, add CSeq */
518 g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
520 gst_rtsp_method_as_text (message->type_data.request.method),
521 message->type_data.request.uri, conn->cseq++);
522 /* add session id if we have one */
523 if (conn->session_id[0] != '\0') {
524 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
527 /* add any authentication headers */
528 add_auth_header (conn, message);
530 case GST_RTSP_MESSAGE_RESPONSE:
531 /* create response string */
532 g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
533 message->type_data.response.code, message->type_data.response.reason);
535 case GST_RTSP_MESSAGE_DATA:
537 guint8 data_header[4];
539 /* prepare data header */
540 data_header[0] = '$';
541 data_header[1] = message->type_data.data.channel;
542 data_header[2] = (message->body_size >> 8) & 0xff;
543 data_header[3] = message->body_size & 0xff;
545 /* create string with header and data */
546 str = g_string_append_len (str, (gchar *) data_header, 4);
548 g_string_append_len (str, (gchar *) message->body,
553 g_return_val_if_reached (GST_RTSP_EINVAL);
557 /* append headers and body */
558 if (message->type != GST_RTSP_MESSAGE_DATA) {
559 /* add date header */
560 add_date_header (message);
563 gst_rtsp_message_append_headers (message, str);
565 /* append Content-Length and body if needed */
566 if (message->body != NULL && message->body_size > 0) {
569 len = g_strdup_printf ("%d", message->body_size);
570 g_string_append_printf (str, "%s: %s\r\n",
571 gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
573 /* header ends here */
574 g_string_append (str, "\r\n");
576 g_string_append_len (str, (gchar *) message->body,
579 /* just end headers */
580 g_string_append (str, "\r\n");
586 gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
588 g_string_free (str, TRUE);
595 g_warning ("Error %d on WSAStartup", error);
596 return GST_RTSP_EWSASTART;
600 g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
603 return GST_RTSP_EWSAVERSION;
609 read_line (gint fd, gchar * buffer, guint size)
617 r = read (fd, &c, 1);
621 if (errno != EAGAIN && errno != EINTR)
624 if (c == '\n') /* end on \n */
626 if (c == '\r') /* ignore \r */
639 return GST_RTSP_EEOF;
643 return GST_RTSP_ESYS;
648 read_string (gchar * dest, gint size, gchar ** src)
654 while (g_ascii_isspace (**src))
657 while (!g_ascii_isspace (**src) && **src != '\0') {
667 read_key (gchar * dest, gint size, gchar ** src)
672 while (**src != ':' && **src != '\0') {
682 parse_response_status (gchar * buffer, GstRTSPMessage * msg)
685 gchar versionstr[20];
692 read_string (versionstr, sizeof (versionstr), &bptr);
693 read_string (codestr, sizeof (codestr), &bptr);
694 code = atoi (codestr);
696 while (g_ascii_isspace (*bptr))
699 if (strcmp (versionstr, "RTSP/1.0") == 0)
700 GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
702 else if (strncmp (versionstr, "RTSP/", 5) == 0) {
703 GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
705 msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
713 return GST_RTSP_EPARSE;
718 parse_request_line (gchar * buffer, GstRTSPMessage * msg)
720 GstRTSPResult res = GST_RTSP_OK;
721 gchar versionstr[20];
725 GstRTSPMethod method;
729 read_string (methodstr, sizeof (methodstr), &bptr);
730 method = gst_rtsp_find_method (methodstr);
732 read_string (urlstr, sizeof (urlstr), &bptr);
734 res = GST_RTSP_EPARSE;
736 read_string (versionstr, sizeof (versionstr), &bptr);
739 res = GST_RTSP_EPARSE;
741 if (strcmp (versionstr, "RTSP/1.0") == 0) {
742 if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
743 res = GST_RTSP_EPARSE;
744 } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
745 if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
746 res = GST_RTSP_EPARSE;
747 msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
749 gst_rtsp_message_init_request (msg, method, urlstr);
750 msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
751 res = GST_RTSP_EPARSE;
757 /* parsing lines means reading a Key: Value pair */
759 parse_line (gchar * buffer, GstRTSPMessage * msg)
763 GstRTSPHeaderField field;
768 read_key (key, sizeof (key), &bptr);
774 field = gst_rtsp_find_header_field (key);
775 if (field != GST_RTSP_HDR_INVALID) {
776 while (g_ascii_isspace (*bptr))
778 gst_rtsp_message_add_header (msg, field, bptr);
785 return GST_RTSP_EPARSE;
790 * gst_rtsp_connection_read_internal:
791 * @conn: a #GstRTSPConnection
792 * @data: the data to read
793 * @size: the size of @data
794 * @timeout: a timeout value or #NULL
795 * @allow_interrupt: can the pending read be interrupted
797 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
798 * the specified @timeout. @timeout can be #NULL, in which case this function
799 * might block forever.
801 * This function can be canceled with gst_rtsp_connection_flush() only if the
802 * @allow_interrupt is set.
804 * Returns: #GST_RTSP_OK on success.
807 gst_rtsp_connection_read_internal (GstRTSPConnection * conn, guint8 * data,
808 guint size, GTimeVal * timeout, gboolean allow_interrupt)
813 struct timeval tv_timeout, *ptv_timeout;
816 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
817 g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
824 /* configure timeout if any */
825 if (timeout != NULL) {
826 tv_timeout.tv_sec = timeout->tv_sec;
827 tv_timeout.tv_usec = timeout->tv_usec;
828 ptv_timeout = &tv_timeout;
832 /* if the call fails, just go in the select.. it should not fail. Else if
833 * there is enough data to read, skip the select call al together.*/
834 if (IOCTL_SOCKET (conn->fd, FIONREAD, &avail) < 0)
836 else if (avail >= toread)
840 FD_SET (conn->fd, &readfds);
845 /* set inside the loop so that when we did not read enough and we have to
846 * continue, we still have the cancel socket bit set */
848 FD_SET (READ_SOCKET (conn), &readfds);
851 retval = select (FD_SETSIZE, &readfds, NULL, NULL, ptv_timeout);
852 } while ((retval == -1 && errno == EINTR));
857 /* check for timeout */
861 if (FD_ISSET (READ_SOCKET (conn), &readfds))
865 /* if we get here there is activity on the real fd since the select
866 * completed and the control socket was not readable. */
867 bytes = read (conn->fd, data, toread);
871 } else if (bytes < 0) {
872 if (errno != EAGAIN && errno != EINTR)
884 return GST_RTSP_ESYS;
888 return GST_RTSP_ETIMEOUT;
892 return GST_RTSP_EINTR;
896 return GST_RTSP_EEOF;
900 return GST_RTSP_ESYS;
905 * gst_rtsp_connection_read:
906 * @conn: a #GstRTSPConnection
907 * @data: the data to read
908 * @size: the size of @data
909 * @timeout: a timeout value or #NULL
911 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
912 * the specified @timeout. @timeout can be #NULL, in which case this function
913 * might block forever.
915 * This function can be canceled with gst_rtsp_connection_flush().
917 * Returns: #GST_RTSP_OK on success.
920 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
923 return gst_rtsp_connection_read_internal (conn, data, size, timeout, TRUE);
928 read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
934 if (content_length <= 0) {
940 body = g_malloc (content_length + 1);
941 body[content_length] = '\0';
943 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, body, content_length,
944 timeout, FALSE), read_error);
949 gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
962 * gst_rtsp_connection_receive:
963 * @conn: a #GstRTSPConnection
964 * @message: the message to read
965 * @timeout: a timeout value or #NULL
967 * Attempt to read into @message from the connected @conn, blocking up to
968 * the specified @timeout. @timeout can be #NULL, in which case this function
969 * might block forever.
971 * This function can be canceled with gst_rtsp_connection_flush().
973 * Returns: #GST_RTSP_OK on success.
976 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
981 glong content_length;
985 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
986 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
993 /* parse first line and headers */
994 while (res == GST_RTSP_OK) {
997 /* read first character, this identifies data messages */
998 /* This is the only read() that we allow to be interrupted */
999 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
1002 /* check for data packet, first character is $ */
1006 /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
1008 /* read channel, which is the next char */
1009 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn, &c, 1, timeout,
1010 FALSE), read_error);
1012 /* now we create a data message */
1013 gst_rtsp_message_init_data (message, c);
1015 /* next two bytes are the length of the data */
1016 GST_RTSP_CHECK (gst_rtsp_connection_read_internal (conn,
1017 (guint8 *) & size, 2, timeout, FALSE), read_error);
1019 size = GUINT16_FROM_BE (size);
1021 /* and read the body */
1022 res = read_body (conn, size, message, timeout);
1028 /* we have a regular response */
1033 /* should not happen */
1038 GST_RTSP_CHECK (read_line (conn->fd, buffer + offset,
1039 sizeof (buffer) - offset), read_error);
1041 if (buffer[0] == '\0')
1045 /* first line, check for response status */
1046 if (g_str_has_prefix (buffer, "RTSP")) {
1047 res = parse_response_status (buffer, message);
1049 res = parse_request_line (buffer, message);
1052 /* else just parse the line */
1053 parse_line (buffer, message);
1059 /* read the rest of the body if needed */
1064 /* see if there is a Content-Length header */
1065 if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_CONTENT_LENGTH,
1066 &hdrval, 0) == GST_RTSP_OK) {
1067 /* there is, read the body */
1068 content_length = atol (hdrval);
1069 GST_RTSP_CHECK (read_body (conn, content_length, message, timeout),
1073 /* save session id in the connection for further use */
1074 if (gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
1075 &session_id, 0) == GST_RTSP_OK) {
1078 /* default session timeout */
1081 maxlen = sizeof (conn->session_id) - 1;
1082 /* the sessionid can have attributes marked with ;
1083 * Make sure we strip them */
1084 for (i = 0; session_id[i] != '\0'; i++) {
1085 if (session_id[i] == ';') {
1090 } while (g_ascii_isspace (session_id[i]));
1091 if (g_str_has_prefix (&session_id[i], "timeout=")) {
1094 /* if we parsed something valid, configure */
1095 if ((to = atoi (&session_id[i + 9])) > 0)
1102 /* make sure to not overflow */
1103 strncpy (conn->session_id, session_id, maxlen);
1104 conn->session_id[maxlen] = '\0';
1116 * gst_rtsp_connection_close:
1117 * @conn: a #GstRTSPConnection
1119 * Close the connected @conn.
1121 * Returns: #GST_RTSP_OK on success.
1124 gst_rtsp_connection_close (GstRTSPConnection * conn)
1128 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1133 if (conn->fd != -1) {
1134 res = CLOSE_SOCKET (conn->fd);
1147 return GST_RTSP_ESYS;
1152 * gst_rtsp_connection_free:
1153 * @conn: a #GstRTSPConnection
1155 * Close and free @conn.
1157 * Returns: #GST_RTSP_OK on success.
1160 gst_rtsp_connection_free (GstRTSPConnection * conn)
1164 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1166 if (WRITE_SOCKET (conn) >= 0)
1167 CLOSE_SOCKET (WRITE_SOCKET (conn));
1168 if (READ_SOCKET (conn) >= 0)
1169 CLOSE_SOCKET (READ_SOCKET (conn));
1173 res = gst_rtsp_connection_close (conn);
1174 g_timer_destroy (conn->timer);
1175 g_free (conn->username);
1176 g_free (conn->passwd);
1183 * gst_rtsp_connection_poll:
1184 * @conn: a #GstRTSPConnection
1185 * @events: a bitmask of #GstRTSPEvent flags to check
1186 * @revents: location for result flags
1187 * @timeout: a timeout
1189 * Wait up to the specified @timeout for the connection to become available for
1190 * at least one of the operations specified in @events. When the function returns
1191 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
1194 * @timeout can be #NULL, in which case this function might block forever.
1196 * This function can be canceled with gst_rtsp_connection_flush().
1198 * Returns: #GST_RTSP_OK on success.
1203 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
1204 GstRTSPEvent * revents, GTimeVal * timeout)
1206 fd_set writefds, *pwritefds;
1210 struct timeval tv, *tvp;
1212 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1213 g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
1214 g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
1216 if (events & GST_RTSP_EV_WRITE) {
1217 /* add fd to writer set when asked to */
1218 FD_ZERO (&writefds);
1219 FD_SET (conn->fd, &writefds);
1220 pwritefds = &writefds;
1224 /* always add cancel socket to readfds */
1226 FD_SET (READ_SOCKET (conn), &readfds);
1227 if (events & GST_RTSP_EV_READ) {
1228 /* add fd to reader set when asked to */
1229 FD_SET (conn->fd, &readfds);
1231 max_fd = MAX (conn->fd, READ_SOCKET (conn));
1234 tv.tv_sec = timeout->tv_sec;
1235 tv.tv_usec = timeout->tv_usec;
1241 retval = select (max_fd + 1, &readfds, pwritefds, NULL, tvp);
1242 } while ((retval == -1 && errno == EINTR));
1245 goto select_timeout;
1250 if (FD_ISSET (READ_SOCKET (conn), &readfds))
1254 if (events & GST_RTSP_EV_READ) {
1255 if (FD_ISSET (conn->fd, &readfds))
1256 *revents |= GST_RTSP_EV_READ;
1258 if (events & GST_RTSP_EV_WRITE) {
1259 if (FD_ISSET (conn->fd, &writefds))
1260 *revents |= GST_RTSP_EV_WRITE;
1267 return GST_RTSP_ETIMEOUT;
1271 return GST_RTSP_ESYS;
1275 return GST_RTSP_EINTR;
1280 * gst_rtsp_connection_next_timeout:
1281 * @conn: a #GstRTSPConnection
1282 * @timeout: a timeout
1284 * Calculate the next timeout for @conn, storing the result in @timeout.
1286 * Returns: #GST_RTSP_OK.
1289 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
1295 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1296 g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
1298 elapsed = g_timer_elapsed (conn->timer, &usec);
1299 if (elapsed >= conn->timeout) {
1303 sec = conn->timeout - elapsed;
1306 timeout->tv_sec = sec;
1307 timeout->tv_usec = usec;
1313 * gst_rtsp_connection_reset_timeout:
1314 * @conn: a #GstRTSPConnection
1316 * Reset the timeout of @conn.
1318 * Returns: #GST_RTSP_OK.
1321 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
1323 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1325 g_timer_start (conn->timer);
1331 * gst_rtsp_connection_flush:
1332 * @conn: a #GstRTSPConnection
1333 * @flush: start or stop the flush
1335 * Start or stop the flushing action on @conn. When flushing, all current
1336 * and future actions on @conn will return #GST_RTSP_EINTR until the connection
1337 * is set to non-flushing mode again.
1339 * Returns: #GST_RTSP_OK.
1342 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
1344 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1347 SEND_COMMAND (conn, CONTROL_STOP);
1353 READ_COMMAND (conn, command, res);
1355 /* no more commands */
1364 * gst_rtsp_connection_set_auth:
1365 * @conn: a #GstRTSPConnection
1366 * @method: authentication method
1368 * @pass: the password
1370 * Configure @conn for authentication mode @method with @user and @pass as the
1371 * user and password respectively.
1373 * Returns: #GST_RTSP_OK.
1376 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
1377 GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
1379 /* Digest isn't implemented yet */
1380 if (method == GST_RTSP_AUTH_DIGEST)
1381 return GST_RTSP_ENOTIMPL;
1383 /* Make sure the username and passwd are being set for authentication */
1384 if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
1385 return GST_RTSP_EINVAL;
1387 /* ":" chars are not allowed in usernames for basic auth */
1388 if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
1389 return GST_RTSP_EINVAL;
1391 g_free (conn->username);
1392 g_free (conn->passwd);
1394 conn->auth_method = method;
1395 conn->username = g_strdup (user);
1396 conn->passwd = g_strdup (pass);