2 * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, 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 * @title: GstRTSPConnection
46 * @short_description: manage RTSP connections
47 * @see_also: gstrtspurl
49 * This object manages the RTSP connection to the server. It provides function
50 * to receive and send bytes and messages.
63 /* we include this here to get the G_OS_* defines */
66 #include <gst/base/base.h>
68 /* necessary for IP_TOS define */
69 #include <gio/gnetworking.h>
71 #include "gstrtspconnection.h"
77 struct sockaddr_in sa_in;
78 struct sockaddr_in6 sa_in6;
79 struct sockaddr_storage sa_stor;
87 guchar out[3]; /* the size must be evenly divisible by 3 */
94 /* If %TRUE we only own data and none of the
99 /* Header or full message */
102 gboolean data_is_data_header;
104 /* Payload following data, if any */
106 guint body_data_size;
108 GstBuffer *body_buffer;
110 /* DATA packet header statically allocated for above */
111 guint8 data_header[4];
113 /* all below only for async writing */
115 guint data_offset; /* == data_size when done */
116 guint body_offset; /* into body_data or the buffer */
118 /* ID of the message for notification */
120 } GstRTSPSerializedMessage;
123 gst_rtsp_serialized_message_clear (GstRTSPSerializedMessage * msg)
125 if (!msg->borrowed) {
126 g_free (msg->body_data);
127 gst_buffer_replace (&msg->body_buffer, NULL);
133 #define SEND_FLAGS MSG_NOSIGNAL
143 TUNNEL_STATE_COMPLETE
144 } GstRTSPTunnelState;
146 #define TUNNELID_LEN 24
148 struct _GstRTSPConnection
151 /* URL for the remote connection */
153 GstRTSPVersion version;
156 GSocketClient *client;
160 GInputStream *input_stream;
161 GOutputStream *output_stream;
162 /* this is a read source we add on the write socket in tunneled mode to be
163 * able to detect when client disconnects the GET channel */
164 GInputStream *control_stream;
166 /* connection state */
167 GSocket *read_socket;
168 GSocket *write_socket;
169 GSocket *socket0, *socket1;
170 gboolean manual_http;
172 GCancellable *cancellable;
174 gchar tunnelid[TUNNELID_LEN];
176 gboolean ignore_x_server_reply;
177 GstRTSPTunnelState tstate;
179 /* the remote and local ip */
185 gchar *initial_buffer;
186 gsize initial_buffer_offset;
188 gboolean remember_session_id; /* remember the session id or not */
191 gint cseq; /* sequence number */
192 gchar session_id[512]; /* session id */
193 gint timeout; /* session timeout in seconds */
194 GTimer *timer; /* timeout timer */
197 GstRTSPAuthMethod auth_method;
200 GHashTable *auth_params;
202 guint content_length_limit;
205 GTlsDatabase *tls_database;
206 GTlsInteraction *tls_interaction;
208 GstRTSPConnectionAcceptCertificateFunc accept_certificate_func;
209 GDestroyNotify accept_certificate_destroy_notify;
210 gpointer accept_certificate_user_data;
231 READ_AHEAD_EOH = -1, /* end of headers */
232 READ_AHEAD_CRLF = -2,
233 READ_AHEAD_CRLFCR = -3
236 /* a structure for constructing RTSPMessages */
240 GstRTSPResult status;
249 /* function prototypes */
250 static void add_auth_header (GstRTSPConnection * conn,
251 GstRTSPMessage * message);
254 build_reset (GstRTSPBuilder * builder)
256 g_free (builder->body_data);
257 memset (builder, 0, sizeof (GstRTSPBuilder));
261 gst_rtsp_result_from_g_io_error (GError * error, GstRTSPResult default_res)
266 if (error->domain != G_IO_ERROR)
269 switch (error->code) {
270 case G_IO_ERROR_TIMED_OUT:
271 return GST_RTSP_ETIMEOUT;
272 case G_IO_ERROR_INVALID_ARGUMENT:
273 return GST_RTSP_EINVAL;
274 case G_IO_ERROR_CANCELLED:
275 case G_IO_ERROR_WOULD_BLOCK:
276 return GST_RTSP_EINTR;
283 tls_accept_certificate (GTlsConnection * conn, GTlsCertificate * peer_cert,
284 GTlsCertificateFlags errors, GstRTSPConnection * rtspconn)
286 GError *error = NULL;
287 gboolean accept = FALSE;
289 if (rtspconn->tls_database) {
290 GSocketConnectable *peer_identity;
291 GTlsCertificateFlags validation_flags;
293 GST_DEBUG ("TLS peer certificate not accepted, checking user database...");
296 g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION
300 g_tls_database_verify_chain (rtspconn->tls_database, peer_cert,
301 G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER, peer_identity,
302 g_tls_connection_get_interaction (conn), G_TLS_DATABASE_VERIFY_NONE,
308 validation_flags = gst_rtsp_connection_get_tls_validation_flags (rtspconn);
310 accept = ((errors & validation_flags) == 0);
312 GST_DEBUG ("Peer certificate accepted");
314 GST_DEBUG ("Peer certificate not accepted (errors: 0x%08X)", errors);
317 if (!accept && rtspconn->accept_certificate_func) {
319 rtspconn->accept_certificate_func (conn, peer_cert, errors,
320 rtspconn->accept_certificate_user_data);
321 GST_DEBUG ("Peer certificate %saccepted by accept-certificate function",
322 accept ? "" : "not ");
330 GST_ERROR ("An error occurred while verifying the peer certificate: %s",
332 g_clear_error (&error);
338 socket_client_event (GSocketClient * client, GSocketClientEvent event,
339 GSocketConnectable * connectable, GTlsConnection * connection,
340 GstRTSPConnection * rtspconn)
342 if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) {
343 GST_DEBUG ("TLS handshaking about to start...");
345 g_signal_connect (connection, "accept-certificate",
346 (GCallback) tls_accept_certificate, rtspconn);
348 g_tls_connection_set_interaction (connection, rtspconn->tls_interaction);
353 * gst_rtsp_connection_create:
354 * @url: a #GstRTSPUrl
355 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
357 * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
358 * The connection will not yet attempt to connect to @url, use
359 * gst_rtsp_connection_connect().
361 * A copy of @url will be made.
363 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
366 gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
368 GstRTSPConnection *newconn;
370 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
371 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
373 newconn = g_new0 (GstRTSPConnection, 1);
375 newconn->may_cancel = TRUE;
376 newconn->cancellable = g_cancellable_new ();
377 newconn->client = g_socket_client_new ();
379 if (url->transports & GST_RTSP_LOWER_TRANS_TLS)
380 g_socket_client_set_tls (newconn->client, TRUE);
382 g_signal_connect (newconn->client, "event", (GCallback) socket_client_event,
385 newconn->url = gst_rtsp_url_copy (url);
386 newconn->timer = g_timer_new ();
387 newconn->timeout = 60;
388 newconn->cseq = 1; /* RFC 7826: "it is RECOMMENDED to start at 0.",
389 but some servers don't copy values <1 due to bugs. */
391 newconn->remember_session_id = TRUE;
393 newconn->auth_method = GST_RTSP_AUTH_NONE;
394 newconn->username = NULL;
395 newconn->passwd = NULL;
396 newconn->auth_params = NULL;
397 newconn->version = 0;
399 newconn->content_length_limit = G_MAXUINT;
407 collect_addresses (GSocket * socket, gchar ** ip, guint16 * port,
408 gboolean remote, GError ** error)
410 GSocketAddress *addr;
413 addr = g_socket_get_remote_address (socket, error);
415 addr = g_socket_get_local_address (socket, error);
420 *ip = g_inet_address_to_string (g_inet_socket_address_get_address
421 (G_INET_SOCKET_ADDRESS (addr)));
423 *port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
425 g_object_unref (addr);
432 * gst_rtsp_connection_create_from_socket:
433 * @socket: a #GSocket
434 * @ip: the IP address of the other end
435 * @port: the port used by the other end
436 * @initial_buffer: data already read from @fd
437 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
439 * Create a new #GstRTSPConnection for handling communication on the existing
440 * socket @socket. The @initial_buffer contains zero terminated data already
441 * read from @socket which should be used before starting to read new data.
443 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
445 /* FIXME 2.0 We don't need the ip and port since they can be got from the
448 gst_rtsp_connection_create_from_socket (GSocket * socket, const gchar * ip,
449 guint16 port, const gchar * initial_buffer, GstRTSPConnection ** conn)
451 GstRTSPConnection *newconn = NULL;
458 g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
459 g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL);
460 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
462 if (!collect_addresses (socket, &local_ip, NULL, FALSE, &err))
463 goto getnameinfo_failed;
465 /* create a url for the client address */
466 url = g_new0 (GstRTSPUrl, 1);
467 url->host = g_strdup (ip);
470 /* now create the connection object */
471 GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
472 gst_rtsp_url_free (url);
474 stream = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
476 /* both read and write initially */
477 newconn->server = TRUE;
478 newconn->socket0 = socket;
479 newconn->stream0 = stream;
480 newconn->write_socket = newconn->read_socket = newconn->socket0;
481 newconn->input_stream = g_io_stream_get_input_stream (stream);
482 newconn->output_stream = g_io_stream_get_output_stream (stream);
483 newconn->control_stream = NULL;
484 newconn->remote_ip = g_strdup (ip);
485 newconn->local_ip = local_ip;
486 newconn->initial_buffer = g_strdup (initial_buffer);
495 GST_ERROR ("failed to get local address: %s", err->message);
496 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ERROR);
497 g_clear_error (&err);
502 GST_ERROR ("failed to make connection");
504 gst_rtsp_url_free (url);
510 * gst_rtsp_connection_accept:
512 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
513 * @cancellable: a #GCancellable to cancel the operation
515 * Accept a new connection on @socket and create a new #GstRTSPConnection for
516 * handling communication on new socket.
518 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
521 gst_rtsp_connection_accept (GSocket * socket, GstRTSPConnection ** conn,
522 GCancellable * cancellable)
527 GSocket *client_sock;
530 g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
531 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
533 client_sock = g_socket_accept (socket, cancellable, &err);
537 /* get the remote ip address and port */
538 if (!collect_addresses (client_sock, &ip, &port, TRUE, &err))
539 goto getnameinfo_failed;
542 gst_rtsp_connection_create_from_socket (client_sock, ip, port, NULL,
544 g_object_unref (client_sock);
552 GST_DEBUG ("Accepting client failed: %s", err->message);
553 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
554 g_clear_error (&err);
559 GST_DEBUG ("getnameinfo failed: %s", err->message);
560 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ERROR);
561 g_clear_error (&err);
562 if (!g_socket_close (client_sock, &err)) {
563 GST_DEBUG ("Closing socket failed: %s", err->message);
564 g_clear_error (&err);
566 g_object_unref (client_sock);
572 * gst_rtsp_connection_get_tls:
573 * @conn: a #GstRTSPConnection
574 * @error: #GError for error reporting, or NULL to ignore.
576 * Get the TLS connection of @conn.
578 * For client side this will return the #GTlsClientConnection when connected
581 * For server side connections, this function will create a GTlsServerConnection
582 * when called the first time and will return that same connection on subsequent
583 * calls. The server is then responsible for configuring the TLS connection.
585 * Returns: (transfer none): the TLS connection for @conn.
590 gst_rtsp_connection_get_tls (GstRTSPConnection * conn, GError ** error)
592 GTlsConnection *result;
594 if (G_IS_TLS_CONNECTION (conn->stream0)) {
595 /* we already had one, return it */
596 result = G_TLS_CONNECTION (conn->stream0);
597 } else if (conn->server) {
598 /* no TLS connection but we are server, make one */
599 result = (GTlsConnection *)
600 g_tls_server_connection_new (conn->stream0, NULL, error);
602 g_object_unref (conn->stream0);
603 conn->stream0 = G_IO_STREAM (result);
604 conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
605 conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
610 g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
611 "client not connected with TLS");
617 * gst_rtsp_connection_set_tls_validation_flags:
618 * @conn: a #GstRTSPConnection
619 * @flags: the validation flags.
621 * Sets the TLS validation flags to be used to verify the peer
622 * certificate when a TLS connection is established.
624 * Returns: TRUE if the validation flags are set correctly, or FALSE if
625 * @conn is NULL or is not a TLS connection.
630 gst_rtsp_connection_set_tls_validation_flags (GstRTSPConnection * conn,
631 GTlsCertificateFlags flags)
633 gboolean res = FALSE;
635 g_return_val_if_fail (conn != NULL, FALSE);
637 res = g_socket_client_get_tls (conn->client);
639 g_socket_client_set_tls_validation_flags (conn->client, flags);
645 * gst_rtsp_connection_get_tls_validation_flags:
646 * @conn: a #GstRTSPConnection
648 * Gets the TLS validation flags used to verify the peer certificate
649 * when a TLS connection is established.
651 * Returns: the validationg flags.
656 gst_rtsp_connection_get_tls_validation_flags (GstRTSPConnection * conn)
658 g_return_val_if_fail (conn != NULL, 0);
660 return g_socket_client_get_tls_validation_flags (conn->client);
664 * gst_rtsp_connection_set_tls_database:
665 * @conn: a #GstRTSPConnection
666 * @database: a #GTlsDatabase
668 * Sets the anchor certificate authorities database. This certificate
669 * database will be used to verify the server's certificate in case it
670 * can't be verified with the default certificate database first.
675 gst_rtsp_connection_set_tls_database (GstRTSPConnection * conn,
676 GTlsDatabase * database)
678 GTlsDatabase *old_db;
680 g_return_if_fail (conn != NULL);
683 g_object_ref (database);
685 old_db = conn->tls_database;
686 conn->tls_database = database;
689 g_object_unref (old_db);
693 * gst_rtsp_connection_get_tls_database:
694 * @conn: a #GstRTSPConnection
696 * Gets the anchor certificate authorities database that will be used
697 * after a server certificate can't be verified with the default
698 * certificate database.
700 * Returns: (transfer full): the anchor certificate authorities database, or NULL if no
701 * database has been previously set. Use g_object_unref() to release the
702 * certificate database.
707 gst_rtsp_connection_get_tls_database (GstRTSPConnection * conn)
709 GTlsDatabase *result;
711 g_return_val_if_fail (conn != NULL, NULL);
713 if ((result = conn->tls_database))
714 g_object_ref (result);
720 * gst_rtsp_connection_set_tls_interaction:
721 * @conn: a #GstRTSPConnection
722 * @interaction: a #GTlsInteraction
724 * Sets a #GTlsInteraction object to be used when the connection or certificate
725 * database need to interact with the user. This will be used to prompt the
726 * user for passwords where necessary.
731 gst_rtsp_connection_set_tls_interaction (GstRTSPConnection * conn,
732 GTlsInteraction * interaction)
734 GTlsInteraction *old_interaction;
736 g_return_if_fail (conn != NULL);
739 g_object_ref (interaction);
741 old_interaction = conn->tls_interaction;
742 conn->tls_interaction = interaction;
745 g_object_unref (old_interaction);
749 * gst_rtsp_connection_get_tls_interaction:
750 * @conn: a #GstRTSPConnection
752 * Gets a #GTlsInteraction object to be used when the connection or certificate
753 * database need to interact with the user. This will be used to prompt the
754 * user for passwords where necessary.
756 * Returns: (transfer full): a reference on the #GTlsInteraction. Use
757 * g_object_unref() to release.
762 gst_rtsp_connection_get_tls_interaction (GstRTSPConnection * conn)
764 GTlsInteraction *result;
766 g_return_val_if_fail (conn != NULL, NULL);
768 if ((result = conn->tls_interaction))
769 g_object_ref (result);
775 * gst_rtsp_connection_set_accept_certificate_func:
776 * @conn: a #GstRTSPConnection
777 * @func: a #GstRTSPConnectionAcceptCertificateFunc to check certificates
778 * @destroy_notify: #GDestroyNotify for @user_data
779 * @user_data: User data passed to @func
781 * Sets a custom accept-certificate function for checking certificates for
782 * validity. This will directly map to #GTlsConnection 's "accept-certificate"
783 * signal and be performed after the default checks of #GstRTSPConnection
784 * (checking against the #GTlsDatabase with the given #GTlsCertificateFlags)
785 * have failed. If no #GTlsDatabase is set on this connection, only @func will
791 gst_rtsp_connection_set_accept_certificate_func (GstRTSPConnection * conn,
792 GstRTSPConnectionAcceptCertificateFunc func,
793 gpointer user_data, GDestroyNotify destroy_notify)
795 if (conn->accept_certificate_destroy_notify)
797 accept_certificate_destroy_notify (conn->accept_certificate_user_data);
798 conn->accept_certificate_func = func;
799 conn->accept_certificate_user_data = user_data;
800 conn->accept_certificate_destroy_notify = destroy_notify;
804 get_tunneled_connection_uri_strdup (GstRTSPUrl * url, guint16 port)
806 const gchar *pre_host = "";
807 const gchar *post_host = "";
809 if (url->family == GST_RTSP_FAM_INET6) {
814 return g_strdup_printf ("http://%s%s%s:%d%s%s%s", pre_host, url->host,
815 post_host, port, url->abspath, url->query ? "?" : "",
816 url->query ? url->query : "");
820 setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
821 GstRTSPMessage * response)
830 GError *error = NULL;
831 GSocketConnection *connection;
833 gchar *connection_uri = NULL;
834 gchar *request_uri = NULL;
839 gst_rtsp_url_get_port (url, &url_port);
840 host = g_strdup_printf ("%s:%d", url->host, url_port);
842 /* create a random sessionid */
843 for (i = 0; i < TUNNELID_LEN; i++)
844 conn->tunnelid[i] = g_random_int_range ('a', 'z');
845 conn->tunnelid[TUNNELID_LEN - 1] = '\0';
847 /* create the GET request for the read connection */
848 GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
850 msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
852 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
854 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
855 "application/x-rtsp-tunnelled");
856 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
857 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
858 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, host);
860 /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
861 * request from being base64 encoded */
862 conn->tunneled = FALSE;
863 GST_RTSP_CHECK (gst_rtsp_connection_send_usec (conn, msg, timeout),
865 gst_rtsp_message_free (msg);
866 conn->tunneled = TRUE;
868 /* receive the response to the GET request */
869 /* we need to temporarily set manual_http to TRUE since
870 * gst_rtsp_connection_receive() will treat the HTTP response as a parsing
871 * failure otherwise */
872 old_http = conn->manual_http;
873 conn->manual_http = TRUE;
874 GST_RTSP_CHECK (gst_rtsp_connection_receive_usec (conn, response, timeout),
876 conn->manual_http = old_http;
878 if (response->type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
879 response->type_data.response.code != GST_RTSP_STS_OK)
882 if (!conn->ignore_x_server_reply &&
883 gst_rtsp_message_get_header (response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
884 &value, 0) == GST_RTSP_OK) {
886 url->host = g_strdup (value);
887 g_free (conn->remote_ip);
888 conn->remote_ip = g_strdup (value);
891 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
893 /* connect to the host/port */
894 if (conn->proxy_host) {
895 connection = g_socket_client_connect_to_host (conn->client,
896 conn->proxy_host, conn->proxy_port, conn->cancellable, &error);
897 request_uri = g_strdup (connection_uri);
899 connection = g_socket_client_connect_to_uri (conn->client,
900 connection_uri, 0, conn->cancellable, &error);
902 g_strdup_printf ("%s%s%s", url->abspath,
903 url->query ? "?" : "", url->query ? url->query : "");
905 if (connection == NULL)
908 socket = g_socket_connection_get_socket (connection);
910 /* get remote address */
911 g_free (conn->remote_ip);
912 conn->remote_ip = NULL;
914 if (!collect_addresses (socket, &conn->remote_ip, NULL, TRUE, &error))
915 goto remote_address_failed;
917 /* this is now our writing socket */
918 conn->stream1 = G_IO_STREAM (connection);
919 conn->socket1 = socket;
920 conn->write_socket = conn->socket1;
921 conn->output_stream = g_io_stream_get_output_stream (conn->stream1);
922 conn->control_stream = NULL;
924 /* create the POST request for the write connection */
925 GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST,
926 request_uri), no_message);
927 msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
929 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
931 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
932 "application/x-rtsp-tunnelled");
933 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
934 "application/x-rtsp-tunnelled");
935 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
936 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
937 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES,
938 "Sun, 9 Jan 1972 00:00:00 GMT");
939 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767");
940 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, host);
942 /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
943 * request from being base64 encoded */
944 conn->tunneled = FALSE;
945 GST_RTSP_CHECK (gst_rtsp_connection_send_usec (conn, msg, timeout),
947 gst_rtsp_message_free (msg);
948 conn->tunneled = TRUE;
951 g_free (connection_uri);
952 g_free (request_uri);
960 GST_ERROR ("failed to create request (%d)", res);
965 GST_ERROR ("write failed (%d)", res);
966 gst_rtsp_message_free (msg);
967 conn->tunneled = TRUE;
972 GST_ERROR ("read failed (%d)", res);
973 conn->manual_http = FALSE;
978 GST_ERROR ("got failure response %d %s",
979 response->type_data.response.code, response->type_data.response.reason);
980 res = GST_RTSP_ERROR;
985 GST_ERROR ("failed to connect: %s", error->message);
986 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
987 g_clear_error (&error);
990 remote_address_failed:
992 GST_ERROR ("failed to resolve address: %s", error->message);
993 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
994 g_object_unref (connection);
995 g_clear_error (&error);
1001 * gst_rtsp_connection_connect_with_response_usec:
1002 * @conn: a #GstRTSPConnection
1003 * @timeout: a timeout in microseconds
1004 * @response: a #GstRTSPMessage
1006 * Attempt to connect to the url of @conn made with
1007 * gst_rtsp_connection_create(). If @timeout is 0 this function can block
1008 * forever. If @timeout contains a valid timeout, this function will return
1009 * #GST_RTSP_ETIMEOUT after the timeout expired. If @conn is set to tunneled,
1010 * @response will contain a response to the tunneling request messages.
1012 * This function can be cancelled with gst_rtsp_connection_flush().
1014 * Returns: #GST_RTSP_OK when a connection could be made.
1019 gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
1020 gint64 timeout, GstRTSPMessage * response)
1023 GSocketConnection *connection;
1025 GError *error = NULL;
1026 gchar *connection_uri, *request_uri, *remote_ip;
1031 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1032 g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
1033 g_return_val_if_fail (conn->stream0 == NULL, GST_RTSP_EINVAL);
1035 to = timeout * 1000;
1036 g_socket_client_set_timeout (conn->client,
1037 (to + GST_SECOND - 1) / GST_SECOND);
1041 gst_rtsp_url_get_port (url, &url_port);
1043 if (conn->tunneled) {
1044 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
1046 connection_uri = gst_rtsp_url_get_request_uri (url);
1049 if (conn->proxy_host) {
1050 connection = g_socket_client_connect_to_host (conn->client,
1051 conn->proxy_host, conn->proxy_port, conn->cancellable, &error);
1052 request_uri = g_strdup (connection_uri);
1054 connection = g_socket_client_connect_to_uri (conn->client,
1055 connection_uri, url_port, conn->cancellable, &error);
1057 /* use the relative component of the uri for non-proxy connections */
1058 request_uri = g_strdup_printf ("%s%s%s", url->abspath,
1059 url->query ? "?" : "", url->query ? url->query : "");
1061 if (connection == NULL)
1062 goto connect_failed;
1064 /* get remote address */
1065 socket = g_socket_connection_get_socket (connection);
1067 if (!collect_addresses (socket, &remote_ip, NULL, TRUE, &error))
1068 goto remote_address_failed;
1070 g_free (conn->remote_ip);
1071 conn->remote_ip = remote_ip;
1072 conn->stream0 = G_IO_STREAM (connection);
1073 conn->socket0 = socket;
1074 /* this is our read socket */
1075 conn->read_socket = conn->socket0;
1076 conn->write_socket = conn->socket0;
1077 conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
1078 conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
1079 conn->control_stream = NULL;
1081 if (conn->tunneled) {
1082 res = setup_tunneling (conn, timeout, request_uri, response);
1083 if (res != GST_RTSP_OK)
1084 goto tunneling_failed;
1086 g_free (connection_uri);
1087 g_free (request_uri);
1094 GST_ERROR ("failed to connect: %s", error->message);
1095 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
1096 g_clear_error (&error);
1097 g_free (connection_uri);
1098 g_free (request_uri);
1101 remote_address_failed:
1103 GST_ERROR ("failed to connect: %s", error->message);
1104 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
1105 g_object_unref (connection);
1106 g_clear_error (&error);
1107 g_free (connection_uri);
1108 g_free (request_uri);
1113 GST_ERROR ("failed to setup tunneling");
1114 g_free (connection_uri);
1115 g_free (request_uri);
1121 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
1123 switch (conn->auth_method) {
1124 case GST_RTSP_AUTH_BASIC:{
1129 if (conn->username == NULL || conn->passwd == NULL)
1132 user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
1133 user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
1134 auth_string = g_strdup_printf ("Basic %s", user_pass64);
1136 gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
1140 g_free (user_pass64);
1143 case GST_RTSP_AUTH_DIGEST:{
1145 gchar *auth_string, *auth_string2;
1150 const gchar *method;
1152 /* we need to have some params set */
1153 if (conn->auth_params == NULL || conn->username == NULL ||
1154 conn->passwd == NULL)
1157 /* we need the realm and nonce */
1158 realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
1159 nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
1160 if (realm == NULL || nonce == NULL)
1163 method = gst_rtsp_method_as_text (message->type_data.request.method);
1164 uri = message->type_data.request.uri;
1167 gst_rtsp_generate_digest_auth_response (NULL, method, realm,
1168 conn->username, conn->passwd, uri, nonce);
1170 g_strdup_printf ("Digest username=\"%s\", "
1171 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
1172 conn->username, realm, nonce, uri, response);
1175 opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
1177 auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
1179 g_free (auth_string);
1180 auth_string = auth_string2;
1182 /* Do not keep any old Authorization headers */
1183 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_AUTHORIZATION, -1);
1184 gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
1195 * gst_rtsp_connection_connect_usec:
1196 * @conn: a #GstRTSPConnection
1197 * @timeout: a timeout in microseconds
1199 * Attempt to connect to the url of @conn made with
1200 * gst_rtsp_connection_create(). If @timeout is 0 this function can block
1201 * forever. If @timeout contains a valid timeout, this function will return
1202 * #GST_RTSP_ETIMEOUT after the timeout expired.
1204 * This function can be cancelled with gst_rtsp_connection_flush().
1206 * Returns: #GST_RTSP_OK when a connection could be made.
1211 gst_rtsp_connection_connect_usec (GstRTSPConnection * conn, gint64 timeout)
1213 GstRTSPResult result;
1214 GstRTSPMessage response;
1216 memset (&response, 0, sizeof (response));
1217 gst_rtsp_message_init (&response);
1219 result = gst_rtsp_connection_connect_with_response_usec (conn, timeout,
1222 gst_rtsp_message_unset (&response);
1228 gen_date_string (gchar * date_string, guint len)
1230 static const char wkdays[7][4] =
1231 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1232 static const char months[12][4] =
1233 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
1241 #ifdef HAVE_GMTIME_R
1247 g_snprintf (date_string, len, "%s, %02d %s %04d %02d:%02d:%02d GMT",
1248 wkdays[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900,
1249 tm.tm_hour, tm.tm_min, tm.tm_sec);
1252 static GstRTSPResult
1253 write_bytes (GOutputStream * stream, const guint8 * buffer, guint * idx,
1254 guint size, gboolean block, GCancellable * cancellable)
1261 if (G_UNLIKELY (*idx > size))
1262 return GST_RTSP_ERROR;
1268 r = g_output_stream_write (stream, (gchar *) & buffer[*idx], left,
1271 r = g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM
1272 (stream), (gchar *) & buffer[*idx], left, cancellable, &err);
1273 if (G_UNLIKELY (r < 0))
1284 if (G_UNLIKELY (r == 0))
1285 return GST_RTSP_EEOF;
1287 if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1288 GST_WARNING ("%s", err->message);
1290 GST_DEBUG ("%s", err->message);
1292 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1293 g_clear_error (&err);
1298 /* NOTE: This changes the values of vectors if multiple iterations are needed! */
1299 #if GLIB_CHECK_VERSION(2, 59, 1)
1300 static GstRTSPResult
1301 writev_bytes (GOutputStream * stream, GOutputVector * vectors, gint n_vectors,
1302 gsize * bytes_written, gboolean block, GCancellable * cancellable)
1304 gsize _bytes_written = 0;
1308 GPollableReturn res = G_POLLABLE_RETURN_OK;
1310 while (n_vectors > 0) {
1312 if (G_UNLIKELY (!g_output_stream_writev (stream, vectors, n_vectors,
1313 &written, cancellable, &err))) {
1314 /* This will never return G_IO_ERROR_WOULD_BLOCK */
1315 res = G_POLLABLE_RETURN_FAILED;
1320 g_pollable_output_stream_writev_nonblocking (G_POLLABLE_OUTPUT_STREAM
1321 (stream), vectors, n_vectors, &written, cancellable, &err);
1323 if (res != G_POLLABLE_RETURN_OK) {
1324 g_assert (written == 0);
1328 _bytes_written += written;
1330 /* skip vectors that have been written in full */
1331 while (written > 0 && written >= vectors[0].size) {
1332 written -= vectors[0].size;
1337 /* skip partially written vector data */
1339 vectors[0].size -= written;
1340 vectors[0].buffer = ((guint8 *) vectors[0].buffer) + written;
1344 *bytes_written = _bytes_written;
1351 *bytes_written = _bytes_written;
1354 GST_WARNING ("%s", err->message);
1355 if (res == G_POLLABLE_RETURN_WOULD_BLOCK) {
1357 return GST_RTSP_EINTR;
1358 } else if (G_UNLIKELY (written == 0)) {
1359 g_clear_error (&err);
1360 return GST_RTSP_EEOF;
1363 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1364 g_clear_error (&err);
1369 static GstRTSPResult
1370 writev_bytes (GOutputStream * stream, GOutputVector * vectors, gint n_vectors,
1371 gsize * bytes_written, gboolean block, GCancellable * cancellable)
1373 gsize _bytes_written = 0;
1376 GstRTSPResult res = GST_RTSP_OK;
1378 for (i = 0; i < n_vectors; i++) {
1381 write_bytes (stream, vectors[i].buffer, &written, vectors[i].size,
1382 block, cancellable);
1383 _bytes_written += written;
1384 if (G_UNLIKELY (res != GST_RTSP_OK))
1388 *bytes_written = _bytes_written;
1395 fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1396 gboolean block, GError ** err)
1400 if (G_UNLIKELY (conn->initial_buffer != NULL)) {
1401 gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
1403 out = MIN (left, size);
1404 memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
1406 if (left == (gsize) out) {
1407 g_free (conn->initial_buffer);
1408 conn->initial_buffer = NULL;
1409 conn->initial_buffer_offset = 0;
1411 conn->initial_buffer_offset += out;
1414 if (G_LIKELY (size > (guint) out)) {
1416 gsize count = size - out;
1418 r = g_input_stream_read (conn->input_stream, (gchar *) & buffer[out],
1419 count, conn->may_cancel ? conn->cancellable : NULL, err);
1421 r = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM
1422 (conn->input_stream), (gchar *) & buffer[out], count,
1423 conn->may_cancel ? conn->cancellable : NULL, err);
1425 if (G_UNLIKELY (r < 0)) {
1427 /* propagate the error */
1430 /* we have some data ignore error */
1431 g_clear_error (err);
1441 fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1442 gboolean block, GError ** err)
1444 DecodeCtx *ctx = conn->ctxp;
1449 guint8 in[sizeof (ctx->out) * 4 / 3];
1452 while (size > 0 && ctx->cout < ctx->coutl) {
1453 /* we have some leftover bytes */
1454 *buffer++ = ctx->out[ctx->cout++];
1459 /* got what we needed? */
1463 /* try to read more bytes */
1464 r = fill_raw_bytes (conn, in, sizeof (in), block, err);
1469 /* we have some data ignore error */
1470 g_clear_error (err);
1477 g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
1481 out = fill_raw_bytes (conn, buffer, size, block, err);
1487 static GstRTSPResult
1488 read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1496 if (G_UNLIKELY (*idx > size))
1497 return GST_RTSP_ERROR;
1502 r = fill_bytes (conn, &buffer[*idx], left, block, &err);
1503 if (G_UNLIKELY (r <= 0))
1514 if (G_UNLIKELY (r == 0))
1515 return GST_RTSP_EEOF;
1517 GST_DEBUG ("%s", err->message);
1518 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1519 g_clear_error (&err);
1524 /* The code below tries to handle clients using \r, \n or \r\n to indicate the
1525 * end of a line. It even does its best to handle clients which mix them (even
1526 * though this is a really stupid idea (tm).) It also handles Line White Space
1527 * (LWS), where a line end followed by whitespace is considered LWS. This is
1528 * the method used in RTSP (and HTTP) to break long lines.
1530 static GstRTSPResult
1531 read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1540 if (conn->read_ahead == READ_AHEAD_EOH) {
1541 /* the last call to read_line() already determined that we have reached
1542 * the end of the headers, so convey that information now */
1543 conn->read_ahead = 0;
1545 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1546 /* the last call to read_line() left off after having read \r\n */
1548 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1549 /* the last call to read_line() left off after having read \r\n\r */
1551 } else if (conn->read_ahead != 0) {
1552 /* the last call to read_line() left us with a character to start with */
1553 c = (guint8) conn->read_ahead;
1554 conn->read_ahead = 0;
1556 /* read the next character */
1558 res = read_bytes (conn, &c, &i, 1, block);
1559 if (G_UNLIKELY (res != GST_RTSP_OK))
1563 /* special treatment of line endings */
1564 if (c == '\r' || c == '\n') {
1568 /* need to read ahead one more character to know what to do... */
1570 res = read_bytes (conn, &read_ahead, &i, 1, block);
1571 if (G_UNLIKELY (res != GST_RTSP_OK))
1574 if (read_ahead == ' ' || read_ahead == '\t') {
1575 if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1576 /* got \r\n\r followed by whitespace, treat it as a normal line
1577 * followed by one starting with LWS */
1578 conn->read_ahead = read_ahead;
1581 /* got LWS, change the line ending to a space and continue */
1583 conn->read_ahead = read_ahead;
1585 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1586 if (read_ahead == '\r' || read_ahead == '\n') {
1587 /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
1588 conn->read_ahead = READ_AHEAD_EOH;
1591 /* got \r\n\r followed by something else, this is not really
1592 * supported since we have probably just eaten the first character
1593 * of the body or the next message, so just ignore the second \r
1594 * and live with it... */
1595 conn->read_ahead = read_ahead;
1598 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1599 if (read_ahead == '\r') {
1600 /* got \r\n\r so far, need one more character... */
1601 conn->read_ahead = READ_AHEAD_CRLFCR;
1603 } else if (read_ahead == '\n') {
1604 /* got \r\n\n, treat it as the end of the headers */
1605 conn->read_ahead = READ_AHEAD_EOH;
1608 /* found the end of a line, keep read_ahead for the next line */
1609 conn->read_ahead = read_ahead;
1612 } else if (c == read_ahead) {
1613 /* got double \r or \n, treat it as the end of the headers */
1614 conn->read_ahead = READ_AHEAD_EOH;
1616 } else if (c == '\r' && read_ahead == '\n') {
1617 /* got \r\n so far, still need more to know what to do... */
1618 conn->read_ahead = READ_AHEAD_CRLF;
1621 /* found the end of a line, keep read_ahead for the next line */
1622 conn->read_ahead = read_ahead;
1627 if (G_LIKELY (*idx < size - 1))
1628 buffer[(*idx)++] = c;
1630 buffer[*idx] = '\0';
1636 * gst_rtsp_connection_write_usec:
1637 * @conn: a #GstRTSPConnection
1638 * @data: the data to write
1639 * @size: the size of @data
1640 * @timeout: a timeout value or 0
1642 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
1643 * the specified @timeout. @timeout can be 0, in which case this function
1644 * might block forever.
1646 * This function can be cancelled with gst_rtsp_connection_flush().
1648 * Returns: #GST_RTSP_OK on success.
1652 /* FIXME 2.0: This should've been static! */
1654 gst_rtsp_connection_write_usec (GstRTSPConnection * conn, const guint8 * data,
1655 guint size, gint64 timeout)
1661 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1662 g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
1663 g_return_val_if_fail (conn->output_stream != NULL, GST_RTSP_EINVAL);
1667 to = timeout * 1000;
1669 g_socket_set_timeout (conn->write_socket, (to + GST_SECOND - 1) / GST_SECOND);
1671 write_bytes (conn->output_stream, data, &offset, size, TRUE,
1673 g_socket_set_timeout (conn->write_socket, 0);
1679 serialize_message (GstRTSPConnection * conn, GstRTSPMessage * message,
1680 GstRTSPSerializedMessage * serialized_message)
1682 GString *str = NULL;
1684 memset (serialized_message, 0, sizeof (*serialized_message));
1686 /* Initially we borrow the body_data / body_buffer fields from
1688 serialized_message->borrowed = TRUE;
1690 switch (message->type) {
1691 case GST_RTSP_MESSAGE_REQUEST:
1692 str = g_string_new ("");
1694 /* create request string, add CSeq */
1695 g_string_append_printf (str, "%s %s RTSP/%s\r\n"
1697 gst_rtsp_method_as_text (message->type_data.request.method),
1698 message->type_data.request.uri,
1699 gst_rtsp_version_as_text (message->type_data.request.version),
1701 /* add session id if we have one */
1702 if (conn->session_id[0] != '\0') {
1703 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
1704 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
1707 /* add any authentication headers */
1708 add_auth_header (conn, message);
1710 case GST_RTSP_MESSAGE_RESPONSE:
1711 str = g_string_new ("");
1713 /* create response string */
1714 g_string_append_printf (str, "RTSP/%s %d %s\r\n",
1715 gst_rtsp_version_as_text (message->type_data.response.version),
1716 message->type_data.response.code, message->type_data.response.reason);
1718 case GST_RTSP_MESSAGE_HTTP_REQUEST:
1719 str = g_string_new ("");
1721 /* create request string */
1722 g_string_append_printf (str, "%s %s HTTP/%s\r\n",
1723 gst_rtsp_method_as_text (message->type_data.request.method),
1724 message->type_data.request.uri,
1725 gst_rtsp_version_as_text (message->type_data.request.version));
1726 /* add any authentication headers */
1727 add_auth_header (conn, message);
1729 case GST_RTSP_MESSAGE_HTTP_RESPONSE:
1730 str = g_string_new ("");
1732 /* create response string */
1733 g_string_append_printf (str, "HTTP/%s %d %s\r\n",
1734 gst_rtsp_version_as_text (message->type_data.request.version),
1735 message->type_data.response.code, message->type_data.response.reason);
1737 case GST_RTSP_MESSAGE_DATA:
1739 guint8 *data_header = serialized_message->data_header;
1741 /* prepare data header */
1742 data_header[0] = '$';
1743 data_header[1] = message->type_data.data.channel;
1744 data_header[2] = (message->body_size >> 8) & 0xff;
1745 data_header[3] = message->body_size & 0xff;
1747 /* create serialized message with header and data */
1748 serialized_message->data_is_data_header = TRUE;
1749 serialized_message->data_size = 4;
1751 if (message->body) {
1752 serialized_message->body_data = message->body;
1753 serialized_message->body_data_size = message->body_size;
1755 g_assert (message->body_buffer != NULL);
1756 serialized_message->body_buffer = message->body_buffer;
1761 g_string_free (str, TRUE);
1762 g_return_val_if_reached (FALSE);
1766 /* append headers and body */
1767 if (message->type != GST_RTSP_MESSAGE_DATA) {
1768 gchar date_string[100];
1770 g_assert (str != NULL);
1772 gen_date_string (date_string, sizeof (date_string));
1774 /* add date header */
1775 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
1776 gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
1778 /* append headers */
1779 gst_rtsp_message_append_headers (message, str);
1781 /* append Content-Length and body if needed */
1782 if (message->body_size > 0) {
1785 len = g_strdup_printf ("%d", message->body_size);
1786 g_string_append_printf (str, "%s: %s\r\n",
1787 gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
1789 /* header ends here */
1790 g_string_append (str, "\r\n");
1792 if (message->body) {
1793 serialized_message->body_data = message->body;
1794 serialized_message->body_data_size = message->body_size;
1796 g_assert (message->body_buffer != NULL);
1797 serialized_message->body_buffer = message->body_buffer;
1800 /* just end headers */
1801 g_string_append (str, "\r\n");
1804 serialized_message->data_size = str->len;
1805 serialized_message->data = (guint8 *) g_string_free (str, FALSE);
1812 * gst_rtsp_connection_send_usec:
1813 * @conn: a #GstRTSPConnection
1814 * @message: the message to send
1815 * @timeout: a timeout value in microseconds
1817 * Attempt to send @message to the connected @conn, blocking up to
1818 * the specified @timeout. @timeout can be 0, in which case this function
1819 * might block forever.
1821 * This function can be cancelled with gst_rtsp_connection_flush().
1823 * Returns: #GST_RTSP_OK on success.
1828 gst_rtsp_connection_send_usec (GstRTSPConnection * conn,
1829 GstRTSPMessage * message, gint64 timeout)
1831 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1832 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1834 return gst_rtsp_connection_send_messages_usec (conn, message, 1, timeout);
1838 * gst_rtsp_connection_send_messages_usec:
1839 * @conn: a #GstRTSPConnection
1840 * @messages: (array length=n_messages): the messages to send
1841 * @n_messages: the number of messages to send
1842 * @timeout: a timeout value in microseconds
1844 * Attempt to send @messages to the connected @conn, blocking up to
1845 * the specified @timeout. @timeout can be 0, in which case this function
1846 * might block forever.
1848 * This function can be cancelled with gst_rtsp_connection_flush().
1850 * Returns: #GST_RTSP_OK on Since.
1855 gst_rtsp_connection_send_messages_usec (GstRTSPConnection * conn,
1856 GstRTSPMessage * messages, guint n_messages, gint64 timeout)
1860 GstRTSPSerializedMessage *serialized_messages;
1861 GOutputVector *vectors;
1862 GstMapInfo *map_infos;
1863 guint n_vectors, n_memories;
1865 gsize bytes_to_write, bytes_written;
1867 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1868 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
1870 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
1871 memset (serialized_messages, 0,
1872 sizeof (GstRTSPSerializedMessage) * n_messages);
1874 for (i = 0, n_vectors = 0, n_memories = 0, bytes_to_write = 0; i < n_messages;
1876 if (G_UNLIKELY (!serialize_message (conn, &messages[i],
1877 &serialized_messages[i])))
1880 if (conn->tunneled) {
1881 gint state = 0, save = 0;
1882 gchar *base64_buffer, *out_buffer;
1886 in_length = serialized_messages[i].data_size;
1887 if (serialized_messages[i].body_data)
1888 in_length += serialized_messages[i].body_data_size;
1889 else if (serialized_messages[i].body_buffer)
1890 in_length += gst_buffer_get_size (serialized_messages[i].body_buffer);
1892 in_length = (in_length / 3 + 1) * 4 + 4 + 1;
1893 base64_buffer = out_buffer = g_malloc0 (in_length);
1896 g_base64_encode_step (serialized_messages[i].data_is_data_header ?
1897 serialized_messages[i].data_header : serialized_messages[i].data,
1898 serialized_messages[i].data_size, FALSE, out_buffer, &state, &save);
1899 out_buffer += written;
1901 if (serialized_messages[i].body_data) {
1903 g_base64_encode_step (serialized_messages[i].body_data,
1904 serialized_messages[i].body_data_size, FALSE, out_buffer, &state,
1906 out_buffer += written;
1907 } else if (serialized_messages[i].body_buffer) {
1908 guint j, n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
1910 for (j = 0; j < n; j++) {
1912 gst_buffer_peek_memory (serialized_messages[i].body_buffer, j);
1915 gst_memory_map (mem, &map, GST_MAP_READ);
1917 written = g_base64_encode_step (map.data, map.size,
1918 FALSE, out_buffer, &state, &save);
1919 out_buffer += written;
1921 gst_memory_unmap (mem, &map);
1925 written = g_base64_encode_close (FALSE, out_buffer, &state, &save);
1926 out_buffer += written;
1928 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
1929 memset (&serialized_messages[i], 0, sizeof (serialized_messages[i]));
1931 serialized_messages[i].data = (guint8 *) base64_buffer;
1932 serialized_messages[i].data_size = (out_buffer - base64_buffer);
1936 if (serialized_messages[i].body_data) {
1938 } else if (serialized_messages[i].body_buffer) {
1939 n_vectors += gst_buffer_n_memory (serialized_messages[i].body_buffer);
1940 n_memories += gst_buffer_n_memory (serialized_messages[i].body_buffer);
1945 vectors = g_newa (GOutputVector, n_vectors);
1946 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
1948 for (i = 0, j = 0, k = 0; i < n_messages; i++) {
1949 vectors[j].buffer = serialized_messages[i].data_is_data_header ?
1950 serialized_messages[i].data_header : serialized_messages[i].data;
1951 vectors[j].size = serialized_messages[i].data_size;
1952 bytes_to_write += vectors[j].size;
1955 if (serialized_messages[i].body_data) {
1956 vectors[j].buffer = serialized_messages[i].body_data;
1957 vectors[j].size = serialized_messages[i].body_data_size;
1958 bytes_to_write += vectors[j].size;
1960 } else if (serialized_messages[i].body_buffer) {
1963 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
1964 for (l = 0; l < n; l++) {
1966 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
1968 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
1969 vectors[j].buffer = map_infos[k].data;
1970 vectors[j].size = map_infos[k].size;
1971 bytes_to_write += vectors[j].size;
1979 /* write request: this is synchronous */
1980 to = timeout * 1000;
1982 g_socket_set_timeout (conn->write_socket, (to + GST_SECOND - 1) / GST_SECOND);
1984 writev_bytes (conn->output_stream, vectors, n_vectors, &bytes_written,
1985 TRUE, conn->cancellable);
1986 g_socket_set_timeout (conn->write_socket, 0);
1988 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
1990 /* free everything */
1991 for (i = 0, k = 0; i < n_messages; i++) {
1992 if (serialized_messages[i].body_buffer) {
1995 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
1996 for (l = 0; l < n; l++) {
1998 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
2000 gst_memory_unmap (mem, &map_infos[k]);
2005 g_free (serialized_messages[i].data);
2012 for (i = 0; i < n_messages; i++) {
2013 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
2015 g_warning ("Wrong message");
2016 return GST_RTSP_EINVAL;
2020 static GstRTSPResult
2021 parse_string (gchar * dest, gint size, gchar ** src)
2023 GstRTSPResult res = GST_RTSP_OK;
2028 while (g_ascii_isspace (**src))
2031 while (!g_ascii_isspace (**src) && **src != '\0') {
2033 dest[idx++] = **src;
2035 res = GST_RTSP_EPARSE;
2044 static GstRTSPResult
2045 parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
2046 GstRTSPVersion * version)
2048 GstRTSPVersion rversion;
2049 GstRTSPResult res = GST_RTSP_OK;
2052 if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
2059 /* the version number must be formatted as X.Y with nothing following */
2060 if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
2061 res = GST_RTSP_EPARSE;
2063 rversion = major * 0x10 + minor;
2064 if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
2066 if (rversion != GST_RTSP_VERSION_1_0 && rversion != GST_RTSP_VERSION_2_0) {
2067 *version = GST_RTSP_VERSION_INVALID;
2068 res = GST_RTSP_ERROR;
2070 } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
2071 if (*type == GST_RTSP_MESSAGE_REQUEST)
2072 *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
2073 else if (*type == GST_RTSP_MESSAGE_RESPONSE)
2074 *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
2076 if (rversion != GST_RTSP_VERSION_1_0 &&
2077 rversion != GST_RTSP_VERSION_1_1 && rversion != GST_RTSP_VERSION_2_0)
2078 res = GST_RTSP_ERROR;
2080 res = GST_RTSP_EPARSE;
2082 res = GST_RTSP_EPARSE;
2084 if (res == GST_RTSP_OK)
2085 *version = rversion;
2090 static GstRTSPResult
2091 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
2093 GstRTSPResult res = GST_RTSP_OK;
2095 gchar versionstr[20];
2100 bptr = (gchar *) buffer;
2102 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2103 res = GST_RTSP_EPARSE;
2105 if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
2106 res = GST_RTSP_EPARSE;
2107 code = atoi (codestr);
2108 if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
2109 res = GST_RTSP_EPARSE;
2111 while (g_ascii_isspace (*bptr))
2114 if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
2115 NULL) != GST_RTSP_OK))
2116 res = GST_RTSP_EPARSE;
2118 res2 = parse_protocol_version (versionstr, &msg->type,
2119 &msg->type_data.response.version);
2120 if (G_LIKELY (res == GST_RTSP_OK))
2126 static GstRTSPResult
2127 parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
2129 GstRTSPResult res = GST_RTSP_OK;
2131 gchar versionstr[20];
2132 gchar methodstr[20];
2135 GstRTSPMethod method;
2137 bptr = (gchar *) buffer;
2139 if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
2140 res = GST_RTSP_EPARSE;
2141 method = gst_rtsp_find_method (methodstr);
2143 if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
2144 res = GST_RTSP_EPARSE;
2145 if (G_UNLIKELY (*urlstr == '\0'))
2146 res = GST_RTSP_EPARSE;
2148 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2149 res = GST_RTSP_EPARSE;
2151 if (G_UNLIKELY (*bptr != '\0'))
2152 res = GST_RTSP_EPARSE;
2154 if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
2155 urlstr) != GST_RTSP_OK))
2156 res = GST_RTSP_EPARSE;
2158 res2 = parse_protocol_version (versionstr, &msg->type,
2159 &msg->type_data.request.version);
2160 if (G_LIKELY (res == GST_RTSP_OK))
2163 if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
2164 /* GET and POST are not allowed as RTSP methods */
2165 if (msg->type_data.request.method == GST_RTSP_GET ||
2166 msg->type_data.request.method == GST_RTSP_POST) {
2167 msg->type_data.request.method = GST_RTSP_INVALID;
2168 if (res == GST_RTSP_OK)
2169 res = GST_RTSP_ERROR;
2171 } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2172 /* only GET and POST are allowed as HTTP methods */
2173 if (msg->type_data.request.method != GST_RTSP_GET &&
2174 msg->type_data.request.method != GST_RTSP_POST) {
2175 msg->type_data.request.method = GST_RTSP_INVALID;
2176 if (res == GST_RTSP_OK)
2177 res = GST_RTSP_ERROR;
2184 /* parsing lines means reading a Key: Value pair */
2185 static GstRTSPResult
2186 parse_line (guint8 * buffer, GstRTSPMessage * msg)
2188 GstRTSPHeaderField field;
2189 gchar *line = (gchar *) buffer;
2190 gchar *field_name = NULL;
2193 if ((value = strchr (line, ':')) == NULL || value == line)
2196 /* trim space before the colon */
2197 if (value[-1] == ' ')
2200 /* replace the colon with a NUL */
2203 /* find the header */
2204 field = gst_rtsp_find_header_field (line);
2205 /* custom header not present in the list of pre-defined headers */
2206 if (field == GST_RTSP_HDR_INVALID)
2209 /* split up the value in multiple key:value pairs if it contains comma(s) */
2210 while (*value != '\0') {
2212 gchar *comma = NULL;
2213 gboolean quoted = FALSE;
2216 /* trim leading space */
2220 /* for headers which may not appear multiple times, and thus may not
2221 * contain multiple values on the same line, we can short-circuit the loop
2222 * below and the entire value results in just one key:value pair*/
2223 if (!gst_rtsp_header_allow_multiple (field))
2224 next_value = value + strlen (value);
2228 /* find the next value, taking special care of quotes and comments */
2229 while (*next_value != '\0') {
2230 if ((quoted || comment != 0) && *next_value == '\\' &&
2231 next_value[1] != '\0')
2233 else if (comment == 0 && *next_value == '"')
2235 else if (!quoted && *next_value == '(')
2237 else if (comment != 0 && *next_value == ')')
2239 else if (!quoted && comment == 0) {
2240 /* To quote RFC 2068: "User agents MUST take special care in parsing
2241 * the WWW-Authenticate field value if it contains more than one
2242 * challenge, or if more than one WWW-Authenticate header field is
2243 * provided, since the contents of a challenge may itself contain a
2244 * comma-separated list of authentication parameters."
2246 * What this means is that we cannot just look for an unquoted comma
2247 * when looking for multiple values in Proxy-Authenticate and
2248 * WWW-Authenticate headers. Instead we need to look for the sequence
2249 * "comma [space] token space token" before we can split after the
2252 if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
2253 field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
2254 if (*next_value == ',') {
2255 if (next_value[1] == ' ') {
2256 /* skip any space following the comma so we do not mistake it for
2257 * separating between two tokens */
2261 } else if (*next_value == ' ' && next_value[1] != ',' &&
2262 next_value[1] != '=' && comma != NULL) {
2267 } else if (*next_value == ',')
2274 if (msg->type == GST_RTSP_MESSAGE_REQUEST && field == GST_RTSP_HDR_SESSION) {
2275 /* The timeout parameter is only allowed in a session response header
2276 * but some clients send it as part of the session request header.
2277 * Ignore everything from the semicolon to the end of the line. */
2279 while (*next_value != '\0') {
2280 if (*next_value == ';') {
2288 if (value != next_value && next_value[-1] == ' ')
2289 next_value[-1] = '\0';
2291 if (*next_value != '\0')
2292 *next_value++ = '\0';
2294 /* add the key:value pair */
2295 if (*value != '\0') {
2296 if (field != GST_RTSP_HDR_INVALID)
2297 gst_rtsp_message_add_header (msg, field, value);
2299 gst_rtsp_message_add_header_by_name (msg, field_name, value);
2310 return GST_RTSP_EPARSE;
2314 /* convert all consecutive whitespace to a single space */
2316 normalize_line (guint8 * buffer)
2319 if (g_ascii_isspace (*buffer)) {
2323 for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
2326 memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
2334 cseq_validation (GstRTSPConnection * conn, GstRTSPMessage * message)
2340 if (message->type == GST_RTSP_MESSAGE_RESPONSE ||
2341 message->type == GST_RTSP_MESSAGE_REQUEST) {
2342 if ((res = gst_rtsp_message_get_header (message, GST_RTSP_HDR_CSEQ,
2343 &cseq_header, 0)) != GST_RTSP_OK) {
2344 /* rfc2326 This field MUST be present in all RTSP req and resp */
2345 goto invalid_format;
2349 cseq = g_ascii_strtoll (cseq_header, NULL, 10);
2350 if (errno != 0 || cseq < 0) {
2351 /* CSeq has no valid value */
2352 goto invalid_format;
2355 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2356 (conn->cseq == 0 || conn->cseq < cseq)) {
2357 /* Response CSeq can't be higher than the number of outgoing requests
2358 * neither is a response valid if no request has been made */
2359 goto invalid_format;
2366 return GST_RTSP_EPARSE;
2371 * GST_RTSP_OK when a complete message was read.
2372 * GST_RTSP_EEOF: when the read socket is closed
2373 * GST_RTSP_EINTR: when more data is needed.
2374 * GST_RTSP_..: some other error occurred.
2376 static GstRTSPResult
2377 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
2378 GstRTSPConnection * conn, gboolean block)
2383 switch (builder->state) {
2388 builder->offset = 0;
2390 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1,
2392 if (res != GST_RTSP_OK)
2395 c = builder->buffer[0];
2397 /* we have 1 bytes now and we can see if this is a data message or
2400 /* data message, prepare for the header */
2401 builder->state = STATE_DATA_HEADER;
2402 conn->may_cancel = FALSE;
2403 } else if (c == '\n' || c == '\r') {
2404 /* skip \n and \r */
2405 builder->offset = 0;
2408 builder->state = STATE_READ_LINES;
2409 conn->may_cancel = FALSE;
2413 case STATE_DATA_HEADER:
2416 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4,
2418 if (res != GST_RTSP_OK)
2421 gst_rtsp_message_init_data (message, builder->buffer[1]);
2423 builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
2424 builder->body_data = g_malloc (builder->body_len + 1);
2425 builder->body_data[builder->body_len] = '\0';
2426 builder->offset = 0;
2427 builder->state = STATE_DATA_BODY;
2430 case STATE_DATA_BODY:
2433 read_bytes (conn, builder->body_data, &builder->offset,
2434 builder->body_len, block);
2435 if (res != GST_RTSP_OK)
2438 /* we have the complete body now, store in the message adjusting the
2439 * length to include the trailing '\0' */
2440 gst_rtsp_message_take_body (message,
2441 (guint8 *) builder->body_data, builder->body_len + 1);
2442 builder->body_data = NULL;
2443 builder->body_len = 0;
2445 builder->state = STATE_END;
2448 case STATE_READ_LINES:
2450 res = read_line (conn, builder->buffer, &builder->offset,
2451 sizeof (builder->buffer), block);
2452 if (res != GST_RTSP_OK)
2455 /* we have a regular response */
2456 if (builder->buffer[0] == '\0') {
2458 gint64 content_length_parsed = 0;
2460 /* empty line, end of message header */
2461 /* see if there is a Content-Length header, but ignore it if this
2462 * is a POST request with an x-sessioncookie header */
2463 if (gst_rtsp_message_get_header (message,
2464 GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
2465 (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
2466 message->type_data.request.method != GST_RTSP_POST ||
2467 gst_rtsp_message_get_header (message,
2468 GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
2469 /* there is, prepare to read the body */
2471 content_length_parsed = g_ascii_strtoll (hdrval, NULL, 10);
2472 if (errno != 0 || content_length_parsed < 0) {
2473 res = GST_RTSP_EPARSE;
2474 goto invalid_body_len;
2475 } else if (content_length_parsed > conn->content_length_limit) {
2476 res = GST_RTSP_ENOMEM;
2477 goto invalid_body_len;
2479 builder->body_len = content_length_parsed;
2480 builder->body_data = g_try_malloc (builder->body_len + 1);
2481 /* we can't do much here, we need the length to know how many bytes
2482 * we need to read next and when allocation fails, we can't read the payload. */
2483 if (builder->body_data == NULL) {
2484 res = GST_RTSP_ENOMEM;
2485 goto invalid_body_len;
2488 builder->body_data[builder->body_len] = '\0';
2489 builder->offset = 0;
2490 builder->state = STATE_DATA_BODY;
2492 builder->state = STATE_END;
2497 /* we have a line */
2498 normalize_line (builder->buffer);
2499 if (builder->line == 0) {
2500 /* first line, check for response status */
2501 if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
2502 memcmp (builder->buffer, "HTTP", 4) == 0) {
2503 builder->status = parse_response_status (builder->buffer, message);
2505 builder->status = parse_request_line (builder->buffer, message);
2508 /* else just parse the line */
2509 res = parse_line (builder->buffer, message);
2510 if (res != GST_RTSP_OK)
2511 builder->status = res;
2513 if (builder->status != GST_RTSP_OK) {
2514 res = builder->status;
2515 goto invalid_format;
2519 builder->offset = 0;
2524 gchar *session_cookie;
2527 conn->may_cancel = TRUE;
2529 if ((res = cseq_validation (conn, message)) != GST_RTSP_OK) {
2530 /* message don't comply with rfc2326 regarding CSeq */
2531 goto invalid_format;
2534 if (message->type == GST_RTSP_MESSAGE_DATA) {
2535 /* data messages don't have headers */
2540 /* save the tunnel session in the connection */
2541 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
2542 !conn->manual_http &&
2543 conn->tstate == TUNNEL_STATE_NONE &&
2544 gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
2545 &session_cookie, 0) == GST_RTSP_OK) {
2546 strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
2547 conn->tunnelid[TUNNELID_LEN - 1] = '\0';
2548 conn->tunneled = TRUE;
2551 /* save session id in the connection for further use */
2552 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2553 gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
2554 &session_id, 0) == GST_RTSP_OK) {
2557 maxlen = sizeof (conn->session_id) - 1;
2558 /* the sessionid can have attributes marked with ;
2559 * Make sure we strip them */
2560 for (i = 0; i < maxlen && session_id[i] != '\0'; i++) {
2561 if (session_id[i] == ';') {
2566 } while (g_ascii_isspace (session_id[i]));
2567 if (g_str_has_prefix (&session_id[i], "timeout=")) {
2570 /* if we parsed something valid, configure */
2571 if ((to = atoi (&session_id[i + 8])) > 0)
2578 /* make sure to not overflow */
2579 if (conn->remember_session_id) {
2580 strncpy (conn->session_id, session_id, maxlen);
2581 conn->session_id[maxlen] = '\0';
2584 res = builder->status;
2588 res = GST_RTSP_ERROR;
2593 conn->may_cancel = TRUE;
2599 conn->may_cancel = TRUE;
2600 GST_DEBUG ("could not allocate body");
2605 conn->may_cancel = TRUE;
2606 GST_DEBUG ("could not parse");
2612 * gst_rtsp_connection_read_usec:
2613 * @conn: a #GstRTSPConnection
2614 * @data: the data to read
2615 * @size: the size of @data
2616 * @timeout: a timeout value in microseconds
2618 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
2619 * the specified @timeout. @timeout can be 0, in which case this function
2620 * might block forever.
2622 * This function can be cancelled with gst_rtsp_connection_flush().
2624 * Returns: #GST_RTSP_OK on success.
2629 gst_rtsp_connection_read_usec (GstRTSPConnection * conn, guint8 * data,
2630 guint size, gint64 timeout)
2636 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2637 g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
2638 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2640 if (G_UNLIKELY (size == 0))
2645 /* configure timeout if any */
2646 to = timeout * 1000;
2648 g_socket_set_timeout (conn->read_socket, (to + GST_SECOND - 1) / GST_SECOND);
2649 res = read_bytes (conn, data, &offset, size, TRUE);
2650 g_socket_set_timeout (conn->read_socket, 0);
2655 static GstRTSPMessage *
2656 gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
2657 const GstRTSPMessage * request)
2659 GstRTSPMessage *msg;
2662 if (gst_rtsp_status_as_text (code) == NULL)
2663 code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
2665 GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
2668 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
2669 "GStreamer RTSP Server");
2670 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
2671 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
2672 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
2674 if (code == GST_RTSP_STS_OK) {
2675 /* add the local ip address to the tunnel reply, this is where the client
2676 * should send the POST request to */
2678 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
2680 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
2681 "application/x-rtsp-tunnelled");
2694 * gst_rtsp_connection_receive_usec:
2695 * @conn: a #GstRTSPConnection
2696 * @message: the message to read
2697 * @timeout: a timeout value or 0
2699 * Attempt to read into @message from the connected @conn, blocking up to
2700 * the specified @timeout. @timeout can be 0, in which case this function
2701 * might block forever.
2703 * This function can be cancelled with gst_rtsp_connection_flush().
2705 * Returns: #GST_RTSP_OK on success.
2710 gst_rtsp_connection_receive_usec (GstRTSPConnection * conn,
2711 GstRTSPMessage * message, gint64 timeout)
2714 GstRTSPBuilder builder;
2717 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2718 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2719 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2721 /* configure timeout if any */
2722 to = timeout * 1000;
2724 g_socket_set_timeout (conn->read_socket, (to + GST_SECOND - 1) / GST_SECOND);
2725 memset (&builder, 0, sizeof (GstRTSPBuilder));
2726 res = build_next (&builder, message, conn, TRUE);
2727 g_socket_set_timeout (conn->read_socket, 0);
2729 if (G_UNLIKELY (res != GST_RTSP_OK))
2732 if (!conn->manual_http) {
2733 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2734 if (conn->tstate == TUNNEL_STATE_NONE &&
2735 message->type_data.request.method == GST_RTSP_GET) {
2736 GstRTSPMessage *response;
2738 conn->tstate = TUNNEL_STATE_GET;
2740 /* tunnel GET request, we can reply now */
2741 response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
2742 res = gst_rtsp_connection_send_usec (conn, response, timeout);
2743 gst_rtsp_message_free (response);
2744 if (res == GST_RTSP_OK)
2745 res = GST_RTSP_ETGET;
2747 } else if (conn->tstate == TUNNEL_STATE_NONE &&
2748 message->type_data.request.method == GST_RTSP_POST) {
2749 conn->tstate = TUNNEL_STATE_POST;
2751 /* tunnel POST request, the caller now has to link the two
2753 res = GST_RTSP_ETPOST;
2756 res = GST_RTSP_EPARSE;
2759 } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
2760 res = GST_RTSP_EPARSE;
2765 /* we have a message here */
2766 build_reset (&builder);
2774 build_reset (&builder);
2775 gst_rtsp_message_unset (message);
2781 * gst_rtsp_connection_close:
2782 * @conn: a #GstRTSPConnection
2784 * Close the connected @conn. After this call, the connection is in the same
2785 * state as when it was first created.
2787 * Returns: #GST_RTSP_OK on success.
2790 gst_rtsp_connection_close (GstRTSPConnection * conn)
2792 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2794 /* last unref closes the connection we don't want to explicitly close here
2795 * because these sockets might have been provided at construction */
2796 if (conn->stream0) {
2797 g_object_unref (conn->stream0);
2798 conn->stream0 = NULL;
2799 conn->socket0 = NULL;
2801 if (conn->stream1) {
2802 g_object_unref (conn->stream1);
2803 conn->stream1 = NULL;
2804 conn->socket1 = NULL;
2807 /* these were owned by the stream */
2808 conn->input_stream = NULL;
2809 conn->output_stream = NULL;
2810 conn->control_stream = NULL;
2812 g_free (conn->remote_ip);
2813 conn->remote_ip = NULL;
2814 g_free (conn->local_ip);
2815 conn->local_ip = NULL;
2817 conn->read_ahead = 0;
2819 g_free (conn->initial_buffer);
2820 conn->initial_buffer = NULL;
2821 conn->initial_buffer_offset = 0;
2823 conn->write_socket = NULL;
2824 conn->read_socket = NULL;
2825 conn->tunneled = FALSE;
2826 conn->tstate = TUNNEL_STATE_NONE;
2828 g_free (conn->username);
2829 conn->username = NULL;
2830 g_free (conn->passwd);
2831 conn->passwd = NULL;
2832 gst_rtsp_connection_clear_auth_params (conn);
2835 conn->session_id[0] = '\0';
2841 * gst_rtsp_connection_free:
2842 * @conn: a #GstRTSPConnection
2844 * Close and free @conn.
2846 * Returns: #GST_RTSP_OK on success.
2849 gst_rtsp_connection_free (GstRTSPConnection * conn)
2853 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2855 res = gst_rtsp_connection_close (conn);
2857 if (conn->cancellable)
2858 g_object_unref (conn->cancellable);
2860 g_object_unref (conn->client);
2861 if (conn->tls_database)
2862 g_object_unref (conn->tls_database);
2863 if (conn->tls_interaction)
2864 g_object_unref (conn->tls_interaction);
2865 if (conn->accept_certificate_destroy_notify)
2867 accept_certificate_destroy_notify (conn->accept_certificate_user_data);
2869 g_timer_destroy (conn->timer);
2870 gst_rtsp_url_free (conn->url);
2871 g_free (conn->proxy_host);
2878 * gst_rtsp_connection_poll_usec:
2879 * @conn: a #GstRTSPConnection
2880 * @events: a bitmask of #GstRTSPEvent flags to check
2881 * @revents: location for result flags
2882 * @timeout: a timeout in microseconds
2884 * Wait up to the specified @timeout for the connection to become available for
2885 * at least one of the operations specified in @events. When the function returns
2886 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
2889 * @timeout can be 0, in which case this function might block forever.
2891 * This function can be cancelled with gst_rtsp_connection_flush().
2893 * Returns: #GST_RTSP_OK on success.
2898 gst_rtsp_connection_poll_usec (GstRTSPConnection * conn, GstRTSPEvent events,
2899 GstRTSPEvent * revents, gint64 timeout)
2902 GSource *rs, *ws, *ts;
2903 GIOCondition condition;
2905 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2906 g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
2907 g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
2908 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2909 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
2911 ctx = g_main_context_new ();
2913 /* configure timeout if any */
2915 ts = g_timeout_source_new (timeout / 1000);
2916 g_source_set_dummy_callback (ts);
2917 g_source_attach (ts, ctx);
2918 g_source_unref (ts);
2921 if (events & GST_RTSP_EV_READ) {
2922 rs = g_socket_create_source (conn->read_socket, G_IO_IN | G_IO_PRI,
2924 g_source_set_dummy_callback (rs);
2925 g_source_attach (rs, ctx);
2926 g_source_unref (rs);
2929 if (events & GST_RTSP_EV_WRITE) {
2930 ws = g_socket_create_source (conn->write_socket, G_IO_OUT,
2932 g_source_set_dummy_callback (ws);
2933 g_source_attach (ws, ctx);
2934 g_source_unref (ws);
2937 /* Returns after handling all pending events */
2938 while (!g_main_context_iteration (ctx, TRUE));
2940 g_main_context_unref (ctx);
2943 if (events & GST_RTSP_EV_READ) {
2944 condition = g_socket_condition_check (conn->read_socket,
2945 G_IO_IN | G_IO_PRI);
2946 if ((condition & G_IO_IN) || (condition & G_IO_PRI))
2947 *revents |= GST_RTSP_EV_READ;
2949 if (events & GST_RTSP_EV_WRITE) {
2950 condition = g_socket_condition_check (conn->write_socket, G_IO_OUT);
2951 if ((condition & G_IO_OUT))
2952 *revents |= GST_RTSP_EV_WRITE;
2956 return GST_RTSP_ETIMEOUT;
2962 * gst_rtsp_connection_next_timeout_usec:
2963 * @conn: a #GstRTSPConnection
2965 * Calculate the next timeout for @conn
2967 * Returns: #the next timeout in microseconds
2972 gst_rtsp_connection_next_timeout_usec (GstRTSPConnection * conn)
2979 g_return_val_if_fail (conn != NULL, 1);
2981 ctimeout = conn->timeout;
2982 if (ctimeout >= 20) {
2983 /* Because we should act before the timeout we timeout 5
2984 * seconds in advance. */
2986 } else if (ctimeout >= 5) {
2987 /* else timeout 20% earlier */
2988 ctimeout -= ctimeout / 5;
2989 } else if (ctimeout >= 1) {
2990 /* else timeout 1 second earlier */
2994 elapsed = g_timer_elapsed (conn->timer, &usec);
2995 if (elapsed >= ctimeout) {
2998 gint64 sec = ctimeout - elapsed;
2999 if (usec <= G_USEC_PER_SEC)
3000 usec = G_USEC_PER_SEC - usec;
3003 timeout = usec + sec * G_USEC_PER_SEC;
3010 * gst_rtsp_connection_reset_timeout:
3011 * @conn: a #GstRTSPConnection
3013 * Reset the timeout of @conn.
3015 * Returns: #GST_RTSP_OK.
3018 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
3020 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3022 g_timer_start (conn->timer);
3028 * gst_rtsp_connection_flush:
3029 * @conn: a #GstRTSPConnection
3030 * @flush: start or stop the flush
3032 * Start or stop the flushing action on @conn. When flushing, all current
3033 * and future actions on @conn will return #GST_RTSP_EINTR until the connection
3034 * is set to non-flushing mode again.
3036 * Returns: #GST_RTSP_OK.
3039 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
3041 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3044 g_cancellable_cancel (conn->cancellable);
3046 g_object_unref (conn->cancellable);
3047 conn->cancellable = g_cancellable_new ();
3054 * gst_rtsp_connection_set_proxy:
3055 * @conn: a #GstRTSPConnection
3056 * @host: the proxy host
3057 * @port: the proxy port
3059 * Set the proxy host and port.
3061 * Returns: #GST_RTSP_OK.
3064 gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
3065 const gchar * host, guint port)
3067 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3069 g_free (conn->proxy_host);
3070 conn->proxy_host = g_strdup (host);
3071 conn->proxy_port = port;
3077 * gst_rtsp_connection_set_auth:
3078 * @conn: a #GstRTSPConnection
3079 * @method: authentication method
3081 * @pass: the password
3083 * Configure @conn for authentication mode @method with @user and @pass as the
3084 * user and password respectively.
3086 * Returns: #GST_RTSP_OK.
3089 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
3090 GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
3092 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3094 if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
3095 || g_strrstr (user, ":") != NULL))
3096 return GST_RTSP_EINVAL;
3098 /* Make sure the username and passwd are being set for authentication */
3099 if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
3100 return GST_RTSP_EINVAL;
3102 /* ":" chars are not allowed in usernames for basic auth */
3103 if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
3104 return GST_RTSP_EINVAL;
3106 g_free (conn->username);
3107 g_free (conn->passwd);
3109 conn->auth_method = method;
3110 conn->username = g_strdup (user);
3111 conn->passwd = g_strdup (pass);
3118 * @key: ASCII string to hash
3120 * Hashes @key in a case-insensitive manner.
3122 * Returns: the hash code.
3125 str_case_hash (gconstpointer key)
3127 const char *p = key;
3128 guint h = g_ascii_toupper (*p);
3131 for (p += 1; *p != '\0'; p++)
3132 h = (h << 5) - h + g_ascii_toupper (*p);
3139 * @v1: an ASCII string
3140 * @v2: another ASCII string
3142 * Compares @v1 and @v2 in a case-insensitive manner
3144 * Returns: %TRUE if they are equal (modulo case)
3147 str_case_equal (gconstpointer v1, gconstpointer v2)
3149 const char *string1 = v1;
3150 const char *string2 = v2;
3152 return g_ascii_strcasecmp (string1, string2) == 0;
3156 * gst_rtsp_connection_set_auth_param:
3157 * @conn: a #GstRTSPConnection
3158 * @param: authentication directive
3161 * Setup @conn with authentication directives. This is not necessary for
3162 * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
3163 * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
3164 * in the WWW-Authenticate response header and can include realm, domain,
3165 * nonce, opaque, stale, algorithm, qop as per RFC2617.
3168 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
3169 const gchar * param, const gchar * value)
3171 g_return_if_fail (conn != NULL);
3172 g_return_if_fail (param != NULL);
3174 if (conn->auth_params == NULL) {
3176 g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
3178 g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
3182 * gst_rtsp_connection_clear_auth_params:
3183 * @conn: a #GstRTSPConnection
3185 * Clear the list of authentication directives stored in @conn.
3188 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
3190 g_return_if_fail (conn != NULL);
3192 if (conn->auth_params != NULL) {
3193 g_hash_table_destroy (conn->auth_params);
3194 conn->auth_params = NULL;
3198 static GstRTSPResult
3199 set_qos_dscp (GSocket * socket, guint qos_dscp)
3202 GST_FIXME ("IP_TOS socket option is not defined, not setting dscp");
3206 union gst_sockaddr sa;
3207 socklen_t slen = sizeof (sa);
3214 fd = g_socket_get_fd (socket);
3215 if (getsockname (fd, &sa.sa, &slen) < 0)
3216 goto no_getsockname;
3218 af = sa.sa.sa_family;
3220 /* if this is an IPv4-mapped address then do IPv4 QoS */
3221 if (af == AF_INET6) {
3222 if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
3226 /* extract and shift 6 bits of the DSCP */
3227 tos = (qos_dscp & 0x3f) << 2;
3230 # define SETSOCKOPT_ARG4_TYPE const char *
3232 # define SETSOCKOPT_ARG4_TYPE const void *
3237 if (setsockopt (fd, IPPROTO_IP, IP_TOS, (SETSOCKOPT_ARG4_TYPE) & tos,
3243 if (setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS,
3244 (SETSOCKOPT_ARG4_TYPE) & tos, sizeof (tos)) < 0)
3258 return GST_RTSP_ESYS;
3262 return GST_RTSP_ERROR;
3268 * gst_rtsp_connection_set_qos_dscp:
3269 * @conn: a #GstRTSPConnection
3270 * @qos_dscp: DSCP value
3272 * Configure @conn to use the specified DSCP value.
3274 * Returns: #GST_RTSP_OK on success.
3277 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
3281 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3282 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
3283 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
3285 res = set_qos_dscp (conn->socket0, qos_dscp);
3286 if (res == GST_RTSP_OK)
3287 res = set_qos_dscp (conn->socket1, qos_dscp);
3293 * gst_rtsp_connection_set_content_length_limit:
3294 * @conn: a #GstRTSPConnection
3295 * @limit: Content-Length limit
3297 * Configure @conn to use the specified Content-Length limit.
3298 * Both requests and responses are validated. If content-length is
3299 * exceeded, ENOMEM error will be returned.
3304 gst_rtsp_connection_set_content_length_limit (GstRTSPConnection * conn,
3307 g_return_if_fail (conn != NULL);
3309 conn->content_length_limit = limit;
3313 * gst_rtsp_connection_get_url:
3314 * @conn: a #GstRTSPConnection
3316 * Retrieve the URL of the other end of @conn.
3318 * Returns: The URL. This value remains valid until the
3319 * connection is freed.
3322 gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
3324 g_return_val_if_fail (conn != NULL, NULL);
3330 * gst_rtsp_connection_get_ip:
3331 * @conn: a #GstRTSPConnection
3333 * Retrieve the IP address of the other end of @conn.
3335 * Returns: The IP address as a string. this value remains valid until the
3336 * connection is closed.
3339 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
3341 g_return_val_if_fail (conn != NULL, NULL);
3343 return conn->remote_ip;
3347 * gst_rtsp_connection_set_ip:
3348 * @conn: a #GstRTSPConnection
3349 * @ip: an ip address
3351 * Set the IP address of the server.
3354 gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
3356 g_return_if_fail (conn != NULL);
3358 g_free (conn->remote_ip);
3359 conn->remote_ip = g_strdup (ip);
3363 * gst_rtsp_connection_get_read_socket:
3364 * @conn: a #GstRTSPConnection
3366 * Get the file descriptor for reading.
3368 * Returns: (transfer none): the file descriptor used for reading or %NULL on
3369 * error. The file descriptor remains valid until the connection is closed.
3372 gst_rtsp_connection_get_read_socket (const GstRTSPConnection * conn)
3374 g_return_val_if_fail (conn != NULL, NULL);
3375 g_return_val_if_fail (conn->read_socket != NULL, NULL);
3377 return conn->read_socket;
3381 * gst_rtsp_connection_get_write_socket:
3382 * @conn: a #GstRTSPConnection
3384 * Get the file descriptor for writing.
3386 * Returns: (transfer none): the file descriptor used for writing or NULL on
3387 * error. The file descriptor remains valid until the connection is closed.
3390 gst_rtsp_connection_get_write_socket (const GstRTSPConnection * conn)
3392 g_return_val_if_fail (conn != NULL, NULL);
3393 g_return_val_if_fail (conn->write_socket != NULL, NULL);
3395 return conn->write_socket;
3399 * gst_rtsp_connection_set_http_mode:
3400 * @conn: a #GstRTSPConnection
3401 * @enable: %TRUE to enable manual HTTP mode
3403 * By setting the HTTP mode to %TRUE the message parsing will support HTTP
3404 * messages in addition to the RTSP messages. It will also disable the
3405 * automatic handling of setting up an HTTP tunnel.
3408 gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
3410 g_return_if_fail (conn != NULL);
3412 conn->manual_http = enable;
3416 * gst_rtsp_connection_set_tunneled:
3417 * @conn: a #GstRTSPConnection
3418 * @tunneled: the new state
3420 * Set the HTTP tunneling state of the connection. This must be configured before
3421 * the @conn is connected.
3424 gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
3426 g_return_if_fail (conn != NULL);
3427 g_return_if_fail (conn->read_socket == NULL);
3428 g_return_if_fail (conn->write_socket == NULL);
3430 conn->tunneled = tunneled;
3434 * gst_rtsp_connection_is_tunneled:
3435 * @conn: a #GstRTSPConnection
3437 * Get the tunneling state of the connection.
3439 * Returns: if @conn is using HTTP tunneling.
3442 gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
3444 g_return_val_if_fail (conn != NULL, FALSE);
3446 return conn->tunneled;
3450 * gst_rtsp_connection_get_tunnelid:
3451 * @conn: a #GstRTSPConnection
3453 * Get the tunnel session id the connection.
3455 * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
3458 gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
3460 g_return_val_if_fail (conn != NULL, NULL);
3462 if (!conn->tunneled)
3465 return conn->tunnelid;
3469 * gst_rtsp_connection_set_ignore_x_server_reply:
3470 * @conn: a #GstRTSPConnection
3471 * @ignore: %TRUE to ignore the x-server-ip-address header reply or %FALSE to
3472 * comply with it (%FALSE is the default).
3474 * Set whether to ignore the x-server-ip-address header reply or not. If the
3475 * header is ignored, the original address will be used instead.
3480 gst_rtsp_connection_set_ignore_x_server_reply (GstRTSPConnection * conn,
3483 g_return_if_fail (conn != NULL);
3485 conn->ignore_x_server_reply = ignore;
3489 * gst_rtsp_connection_get_ignore_x_server_reply:
3490 * @conn: a #GstRTSPConnection
3492 * Get the ignore_x_server_reply value.
3494 * Returns: returns %TRUE if the x-server-ip-address header reply will be
3495 * ignored, else returns %FALSE
3500 gst_rtsp_connection_get_ignore_x_server_reply (const GstRTSPConnection * conn)
3502 g_return_val_if_fail (conn != NULL, FALSE);
3504 return conn->ignore_x_server_reply;
3508 * gst_rtsp_connection_do_tunnel:
3509 * @conn: a #GstRTSPConnection
3510 * @conn2: a #GstRTSPConnection or %NULL
3512 * If @conn received the first tunnel connection and @conn2 received
3513 * the second tunnel connection, link the two connections together so that
3514 * @conn manages the tunneled connection.
3516 * After this call, @conn2 cannot be used anymore and must be freed with
3517 * gst_rtsp_connection_free().
3519 * If @conn2 is %NULL then only the base64 decoding context will be setup for
3522 * Returns: return GST_RTSP_OK on success.
3525 gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
3526 GstRTSPConnection * conn2)
3528 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3530 if (conn2 != NULL) {
3531 GstRTSPTunnelState ts1 = conn->tstate;
3532 GstRTSPTunnelState ts2 = conn2->tstate;
3534 g_return_val_if_fail ((ts1 == TUNNEL_STATE_GET && ts2 == TUNNEL_STATE_POST)
3535 || (ts1 == TUNNEL_STATE_POST && ts2 == TUNNEL_STATE_GET),
3537 g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
3538 TUNNELID_LEN), GST_RTSP_EINVAL);
3540 /* both connections have socket0 as the read/write socket */
3541 if (ts1 == TUNNEL_STATE_GET) {
3542 /* conn2 is the HTTP POST channel. take its socket and set it as read
3544 conn->socket1 = conn2->socket0;
3545 conn->stream1 = conn2->stream0;
3546 conn->input_stream = conn2->input_stream;
3547 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3548 conn2->output_stream = NULL;
3550 /* conn2 is the HTTP GET channel. take its socket and set it as write
3552 conn->socket1 = conn->socket0;
3553 conn->stream1 = conn->stream0;
3554 conn->socket0 = conn2->socket0;
3555 conn->stream0 = conn2->stream0;
3556 conn->output_stream = conn2->output_stream;
3557 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3560 /* clean up some of the state of conn2 */
3561 g_cancellable_cancel (conn2->cancellable);
3562 conn2->write_socket = conn2->read_socket = NULL;
3563 conn2->socket0 = NULL;
3564 conn2->stream0 = NULL;
3565 conn2->socket1 = NULL;
3566 conn2->stream1 = NULL;
3567 conn2->input_stream = NULL;
3568 conn2->control_stream = NULL;
3569 g_object_unref (conn2->cancellable);
3570 conn2->cancellable = NULL;
3572 /* We make socket0 the write socket and socket1 the read socket. */
3573 conn->write_socket = conn->socket0;
3574 conn->read_socket = conn->socket1;
3576 conn->tstate = TUNNEL_STATE_COMPLETE;
3578 g_free (conn->initial_buffer);
3579 conn->initial_buffer = conn2->initial_buffer;
3580 conn2->initial_buffer = NULL;
3581 conn->initial_buffer_offset = conn2->initial_buffer_offset;
3584 /* we need base64 decoding for the readfd */
3585 conn->ctx.state = 0;
3588 conn->ctx.coutl = 0;
3589 conn->ctxp = &conn->ctx;
3595 * gst_rtsp_connection_set_remember_session_id:
3596 * @conn: a #GstRTSPConnection
3597 * @remember: %TRUE if the connection should remember the session id
3599 * Sets if the #GstRTSPConnection should remember the session id from the last
3600 * response received and force it onto any further requests.
3602 * The default value is %TRUE
3606 gst_rtsp_connection_set_remember_session_id (GstRTSPConnection * conn,
3609 conn->remember_session_id = remember;
3611 conn->session_id[0] = '\0';
3615 * gst_rtsp_connection_get_remember_session_id:
3616 * @conn: a #GstRTSPConnection
3618 * Returns: %TRUE if the #GstRTSPConnection remembers the session id in the
3619 * last response to set it on any further request.
3623 gst_rtsp_connection_get_remember_session_id (GstRTSPConnection * conn)
3625 return conn->remember_session_id;
3629 #define READ_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3630 #define READ_COND (G_IO_IN | READ_ERR)
3631 #define WRITE_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3632 #define WRITE_COND (G_IO_OUT | WRITE_ERR)
3634 /* async functions */
3635 struct _GstRTSPWatch
3639 GstRTSPConnection *conn;
3641 GstRTSPBuilder builder;
3642 GstRTSPMessage message;
3646 GSource *controlsrc;
3648 gboolean keep_running;
3650 /* queued message for transmission */
3653 GstQueueArray *messages;
3654 gsize messages_bytes;
3655 guint messages_count;
3659 GCond queue_not_full;
3662 GstRTSPWatchFuncs funcs;
3665 GDestroyNotify notify;
3668 #define IS_BACKLOG_FULL(w) (((w)->max_bytes != 0 && (w)->messages_bytes >= (w)->max_bytes) || \
3669 ((w)->max_messages != 0 && (w)->messages_count >= (w)->max_messages))
3672 gst_rtsp_source_prepare (GSource * source, gint * timeout)
3674 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3676 if (watch->conn->initial_buffer != NULL)
3679 *timeout = (watch->conn->timeout * 1000);
3685 gst_rtsp_source_check (GSource * source)
3691 gst_rtsp_source_dispatch_read_get_channel (GPollableInputStream * stream,
3692 GstRTSPWatch * watch)
3695 guint8 buffer[1024];
3696 GError *error = NULL;
3698 /* try to read in order to be able to detect errors, we read 1k in case some
3699 * client actually decides to send data on the GET channel */
3700 count = g_pollable_input_stream_read_nonblocking (stream, buffer, 1024, NULL,
3703 /* other end closed the socket */
3708 GST_DEBUG ("%s", error->message);
3709 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
3710 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
3711 g_clear_error (&error);
3714 g_clear_error (&error);
3718 /* client sent data on the GET channel, ignore it */
3726 if (watch->funcs.closed)
3727 watch->funcs.closed (watch, watch->user_data);
3729 /* the read connection was closed, stop the watch now */
3730 watch->keep_running = FALSE;
3736 if (watch->funcs.error_full)
3737 watch->funcs.error_full (watch, GST_RTSP_ESYS, &watch->message,
3738 0, watch->user_data);
3739 else if (watch->funcs.error)
3740 watch->funcs.error (watch, GST_RTSP_ESYS, watch->user_data);
3747 gst_rtsp_source_dispatch_read (GPollableInputStream * stream,
3748 GstRTSPWatch * watch)
3750 GstRTSPResult res = GST_RTSP_ERROR;
3751 GstRTSPConnection *conn = watch->conn;
3753 /* if this connection was already closed, stop now */
3754 if (G_POLLABLE_INPUT_STREAM (conn->input_stream) != stream)
3757 res = build_next (&watch->builder, &watch->message, conn, FALSE);
3758 if (res == GST_RTSP_EINTR)
3760 else if (G_UNLIKELY (res == GST_RTSP_EEOF)) {
3761 g_mutex_lock (&watch->mutex);
3762 if (watch->readsrc) {
3763 if (!g_source_is_destroyed ((GSource *) watch))
3764 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
3765 g_source_unref (watch->readsrc);
3766 watch->readsrc = NULL;
3769 if (conn->stream1) {
3770 g_object_unref (conn->stream1);
3771 conn->stream1 = NULL;
3772 conn->socket1 = NULL;
3773 conn->input_stream = NULL;
3775 g_mutex_unlock (&watch->mutex);
3777 /* When we are in tunnelled mode, the read socket can be closed and we
3778 * should be prepared for a new POST method to reopen it */
3779 if (conn->tstate == TUNNEL_STATE_COMPLETE) {
3780 /* remove the read connection for the tunnel */
3781 /* we accept a new POST request */
3782 conn->tstate = TUNNEL_STATE_GET;
3783 /* and signal that we lost our tunnel */
3784 if (watch->funcs.tunnel_lost)
3785 res = watch->funcs.tunnel_lost (watch, watch->user_data);
3786 /* we add read source on the write socket able to detect when client closes get channel in tunneled mode */
3787 g_mutex_lock (&watch->mutex);
3788 if (watch->conn->control_stream && !watch->controlsrc) {
3790 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
3791 (watch->conn->control_stream), NULL);
3792 g_source_set_callback (watch->controlsrc,
3793 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
3795 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
3797 g_mutex_unlock (&watch->mutex);
3801 } else if (G_LIKELY (res == GST_RTSP_OK)) {
3802 if (!conn->manual_http &&
3803 watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3804 if (conn->tstate == TUNNEL_STATE_NONE &&
3805 watch->message.type_data.request.method == GST_RTSP_GET) {
3806 GstRTSPMessage *response;
3807 GstRTSPStatusCode code;
3809 conn->tstate = TUNNEL_STATE_GET;
3811 if (watch->funcs.tunnel_start)
3812 code = watch->funcs.tunnel_start (watch, watch->user_data);
3814 code = GST_RTSP_STS_OK;
3816 /* queue the response */
3817 response = gen_tunnel_reply (conn, code, &watch->message);
3818 if (watch->funcs.tunnel_http_response)
3819 watch->funcs.tunnel_http_response (watch, &watch->message, response,
3821 gst_rtsp_watch_send_message (watch, response, NULL);
3822 gst_rtsp_message_free (response);
3824 } else if (conn->tstate == TUNNEL_STATE_NONE &&
3825 watch->message.type_data.request.method == GST_RTSP_POST) {
3826 conn->tstate = TUNNEL_STATE_POST;
3828 /* in the callback the connection should be tunneled with the
3830 if (watch->funcs.tunnel_complete) {
3831 watch->funcs.tunnel_complete (watch, watch->user_data);
3839 if (!conn->manual_http) {
3840 /* if manual HTTP support is not enabled, then restore the message to
3841 * what it would have looked like without the support for parsing HTTP
3842 * messages being present */
3843 if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3844 watch->message.type = GST_RTSP_MESSAGE_REQUEST;
3845 watch->message.type_data.request.method = GST_RTSP_INVALID;
3846 if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
3847 watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
3848 res = GST_RTSP_EPARSE;
3849 } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
3850 watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
3851 if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
3852 watch->message.type_data.response.version = GST_RTSP_VERSION_INVALID;
3853 res = GST_RTSP_EPARSE;
3856 if (G_LIKELY (res != GST_RTSP_OK))
3859 if (watch->funcs.message_received)
3860 watch->funcs.message_received (watch, &watch->message, watch->user_data);
3863 gst_rtsp_message_unset (&watch->message);
3864 build_reset (&watch->builder);
3872 if (watch->funcs.closed)
3873 watch->funcs.closed (watch, watch->user_data);
3875 /* we closed the read connection, stop the watch now */
3876 watch->keep_running = FALSE;
3878 /* always stop when the input returns EOF in non-tunneled mode */
3883 if (watch->funcs.error_full)
3884 watch->funcs.error_full (watch, res, &watch->message,
3885 0, watch->user_data);
3886 else if (watch->funcs.error)
3887 watch->funcs.error (watch, res, watch->user_data);
3894 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
3895 gpointer user_data G_GNUC_UNUSED)
3897 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3898 GstRTSPConnection *conn = watch->conn;
3900 if (conn->initial_buffer != NULL) {
3901 gst_rtsp_source_dispatch_read (G_POLLABLE_INPUT_STREAM (conn->input_stream),
3904 return watch->keep_running;
3908 gst_rtsp_source_dispatch_write (GPollableOutputStream * stream,
3909 GstRTSPWatch * watch)
3911 GstRTSPResult res = GST_RTSP_ERROR;
3912 GstRTSPConnection *conn = watch->conn;
3914 /* if this connection was already closed, stop now */
3915 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
3919 g_mutex_lock (&watch->mutex);
3921 guint n_messages = gst_queue_array_get_length (watch->messages);
3922 GOutputVector *vectors;
3923 GstMapInfo *map_infos;
3925 gsize bytes_to_write, bytes_written;
3926 guint n_vectors, n_memories, n_ids, drop_messages;
3927 gint i, j, l, n_mmap;
3928 GstRTSPSerializedMessage *msg;
3930 /* if this connection was already closed, stop now */
3931 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
3933 g_mutex_unlock (&watch->mutex);
3937 if (n_messages == 0) {
3938 if (watch->writesrc) {
3939 if (!g_source_is_destroyed ((GSource *) watch))
3940 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
3941 g_source_unref (watch->writesrc);
3942 watch->writesrc = NULL;
3943 /* we create and add the write source again when we actually have
3944 * something to write */
3946 /* since write source is now removed we add read source on the write
3947 * socket instead to be able to detect when client closes get channel
3948 * in tunneled mode */
3949 if (watch->conn->control_stream) {
3951 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
3952 (watch->conn->control_stream), NULL);
3953 g_source_set_callback (watch->controlsrc,
3954 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
3956 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
3958 watch->controlsrc = NULL;
3964 for (i = 0, n_vectors = 0, n_memories = 0, n_ids = 0; i < n_messages; i++) {
3965 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
3969 if (msg->data_offset < msg->data_size)
3972 if (msg->body_data && msg->body_offset < msg->body_data_size) {
3974 } else if (msg->body_buffer) {
3978 n = gst_buffer_n_memory (msg->body_buffer);
3979 for (m = 0; m < n; m++) {
3980 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
3982 /* Skip all memories we already wrote */
3983 if (offset + mem->size <= msg->body_offset) {
3984 offset += mem->size;
3987 offset += mem->size;
3995 vectors = g_newa (GOutputVector, n_vectors);
3996 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
3997 ids = n_ids ? g_newa (guint, n_ids + 1) : NULL;
3999 memset (ids, 0, sizeof (guint) * (n_ids + 1));
4001 for (i = 0, j = 0, n_mmap = 0, l = 0, bytes_to_write = 0; i < n_messages;
4003 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4005 if (msg->data_offset < msg->data_size) {
4006 vectors[j].buffer = (msg->data_is_data_header ?
4007 msg->data_header : msg->data) + msg->data_offset;
4008 vectors[j].size = msg->data_size - msg->data_offset;
4009 bytes_to_write += vectors[j].size;
4013 if (msg->body_data) {
4014 if (msg->body_offset < msg->body_data_size) {
4015 vectors[j].buffer = msg->body_data + msg->body_offset;
4016 vectors[j].size = msg->body_data_size - msg->body_offset;
4017 bytes_to_write += vectors[j].size;
4020 } else if (msg->body_buffer) {
4023 n = gst_buffer_n_memory (msg->body_buffer);
4024 for (m = 0; m < n; m++) {
4025 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
4028 /* Skip all memories we already wrote */
4029 if (offset + mem->size <= msg->body_offset) {
4030 offset += mem->size;
4034 if (offset < msg->body_offset)
4035 off = msg->body_offset - offset;
4039 offset += mem->size;
4041 g_assert (off < mem->size);
4043 gst_memory_map (mem, &map_infos[n_mmap], GST_MAP_READ);
4044 vectors[j].buffer = map_infos[n_mmap].data + off;
4045 vectors[j].size = map_infos[n_mmap].size - off;
4046 bytes_to_write += vectors[j].size;
4055 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4056 &bytes_written, FALSE, watch->conn->cancellable);
4057 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4059 /* First unmap all memories here, this simplifies the code below
4060 * as we don't have to skip all memories that were already written
4062 for (i = 0; i < n_mmap; i++) {
4063 gst_memory_unmap (map_infos[i].memory, &map_infos[i]);
4066 if (bytes_written == bytes_to_write) {
4067 /* fast path, just unmap all memories, free memory, drop all messages and notify them */
4069 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4075 gst_rtsp_serialized_message_clear (msg);
4078 g_assert (watch->messages_bytes >= bytes_written);
4079 watch->messages_bytes -= bytes_written;
4080 } else if (bytes_written > 0) {
4081 /* not done, let's skip all messages that were sent already and free them */
4082 for (i = 0, drop_messages = 0; i < n_messages; i++) {
4083 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4085 if (bytes_written >= msg->data_size - msg->data_offset) {
4088 /* all data of this message is sent, check body and otherwise
4089 * skip the whole message for next time */
4090 bytes_written -= (msg->data_size - msg->data_offset);
4091 watch->messages_bytes -= (msg->data_size - msg->data_offset);
4092 msg->data_offset = msg->data_size;
4094 if (msg->body_data) {
4095 body_size = msg->body_data_size;
4096 } else if (msg->body_buffer) {
4097 body_size = gst_buffer_get_size (msg->body_buffer);
4102 if (bytes_written + msg->body_offset >= body_size) {
4103 /* body written, drop this message */
4104 bytes_written -= body_size - msg->body_offset;
4105 watch->messages_bytes -= body_size - msg->body_offset;
4106 msg->body_offset = body_size;
4114 gst_rtsp_serialized_message_clear (msg);
4116 msg->body_offset += bytes_written;
4117 watch->messages_bytes -= bytes_written;
4121 /* Need to continue sending from the data of this message */
4122 msg->data_offset += bytes_written;
4123 watch->messages_bytes -= bytes_written;
4128 while (drop_messages > 0) {
4129 msg = gst_queue_array_pop_head_struct (watch->messages);
4134 g_assert (watch->messages_bytes >= bytes_written);
4135 watch->messages_bytes -= bytes_written;
4138 if (!IS_BACKLOG_FULL (watch))
4139 g_cond_signal (&watch->queue_not_full);
4140 g_mutex_unlock (&watch->mutex);
4142 /* notify all messages that were successfully written */
4145 /* only decrease the counter for messages that have an id. Only
4146 * the last message of a messages chunk is counted */
4147 watch->messages_count--;
4149 if (watch->funcs.message_sent)
4150 watch->funcs.message_sent (watch, *ids, watch->user_data);
4155 if (res == GST_RTSP_EINTR) {
4157 } else if (G_UNLIKELY (res != GST_RTSP_OK)) {
4160 g_mutex_lock (&watch->mutex);
4162 g_mutex_unlock (&watch->mutex);
4174 if (watch->funcs.error_full) {
4175 guint i, n_messages;
4177 n_messages = gst_queue_array_get_length (watch->messages);
4178 for (i = 0; i < n_messages; i++) {
4179 GstRTSPSerializedMessage *msg =
4180 gst_queue_array_peek_nth_struct (watch->messages, i);
4182 watch->funcs.error_full (watch, res, NULL, msg->id, watch->user_data);
4184 } else if (watch->funcs.error) {
4185 watch->funcs.error (watch, res, watch->user_data);
4193 gst_rtsp_source_finalize (GSource * source)
4195 GstRTSPWatch *watch = (GstRTSPWatch *) source;
4196 GstRTSPSerializedMessage *msg;
4199 watch->notify (watch->user_data);
4201 build_reset (&watch->builder);
4202 gst_rtsp_message_unset (&watch->message);
4204 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4205 gst_rtsp_serialized_message_clear (msg);
4207 gst_queue_array_free (watch->messages);
4208 watch->messages = NULL;
4209 watch->messages_bytes = 0;
4210 watch->messages_count = 0;
4212 g_cond_clear (&watch->queue_not_full);
4215 g_source_unref (watch->readsrc);
4216 if (watch->writesrc)
4217 g_source_unref (watch->writesrc);
4218 if (watch->controlsrc)
4219 g_source_unref (watch->controlsrc);
4221 g_mutex_clear (&watch->mutex);
4224 static GSourceFuncs gst_rtsp_source_funcs = {
4225 gst_rtsp_source_prepare,
4226 gst_rtsp_source_check,
4227 gst_rtsp_source_dispatch,
4228 gst_rtsp_source_finalize,
4234 * gst_rtsp_watch_new: (skip)
4235 * @conn: a #GstRTSPConnection
4236 * @funcs: watch functions
4237 * @user_data: user data to pass to @funcs
4238 * @notify: notify when @user_data is not referenced anymore
4240 * Create a watch object for @conn. The functions provided in @funcs will be
4241 * called with @user_data when activity happened on the watch.
4243 * The new watch is usually created so that it can be attached to a
4244 * maincontext with gst_rtsp_watch_attach().
4246 * @conn must exist for the entire lifetime of the watch.
4248 * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
4249 * communication. Free with gst_rtsp_watch_unref () after usage.
4252 gst_rtsp_watch_new (GstRTSPConnection * conn,
4253 GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
4255 GstRTSPWatch *result;
4257 g_return_val_if_fail (conn != NULL, NULL);
4258 g_return_val_if_fail (funcs != NULL, NULL);
4259 g_return_val_if_fail (conn->read_socket != NULL, NULL);
4260 g_return_val_if_fail (conn->write_socket != NULL, NULL);
4262 result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
4263 sizeof (GstRTSPWatch));
4265 result->conn = conn;
4266 result->builder.state = STATE_START;
4268 g_mutex_init (&result->mutex);
4270 gst_queue_array_new_for_struct (sizeof (GstRTSPSerializedMessage), 10);
4271 g_cond_init (&result->queue_not_full);
4273 gst_rtsp_watch_reset (result);
4274 result->keep_running = TRUE;
4275 result->flushing = FALSE;
4277 result->funcs = *funcs;
4278 result->user_data = user_data;
4279 result->notify = notify;
4285 * gst_rtsp_watch_reset:
4286 * @watch: a #GstRTSPWatch
4288 * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
4289 * when the file descriptors of the connection might have changed.
4292 gst_rtsp_watch_reset (GstRTSPWatch * watch)
4294 g_mutex_lock (&watch->mutex);
4295 if (watch->readsrc) {
4296 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
4297 g_source_unref (watch->readsrc);
4299 if (watch->writesrc) {
4300 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
4301 g_source_unref (watch->writesrc);
4302 watch->writesrc = NULL;
4304 if (watch->controlsrc) {
4305 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4306 g_source_unref (watch->controlsrc);
4307 watch->controlsrc = NULL;
4310 if (watch->conn->input_stream) {
4312 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4313 (watch->conn->input_stream), NULL);
4314 g_source_set_callback (watch->readsrc,
4315 (GSourceFunc) gst_rtsp_source_dispatch_read, watch, NULL);
4316 g_source_add_child_source ((GSource *) watch, watch->readsrc);
4318 watch->readsrc = NULL;
4321 /* we create and add the write source when we actually have something to
4324 /* when write source is not added we add read source on the write socket
4325 * instead to be able to detect when client closes get channel in tunneled
4327 if (watch->conn->control_stream) {
4329 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4330 (watch->conn->control_stream), NULL);
4331 g_source_set_callback (watch->controlsrc,
4332 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch, NULL);
4333 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
4335 watch->controlsrc = NULL;
4337 g_mutex_unlock (&watch->mutex);
4341 * gst_rtsp_watch_attach:
4342 * @watch: a #GstRTSPWatch
4343 * @context: a GMainContext (if NULL, the default context will be used)
4345 * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
4347 * Returns: the ID (greater than 0) for the watch within the GMainContext.
4350 gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
4352 g_return_val_if_fail (watch != NULL, 0);
4354 return g_source_attach ((GSource *) watch, context);
4358 * gst_rtsp_watch_unref:
4359 * @watch: a #GstRTSPWatch
4361 * Decreases the reference count of @watch by one. If the resulting reference
4362 * count is zero the watch and associated memory will be destroyed.
4365 gst_rtsp_watch_unref (GstRTSPWatch * watch)
4367 g_return_if_fail (watch != NULL);
4369 g_source_unref ((GSource *) watch);
4373 * gst_rtsp_watch_set_send_backlog:
4374 * @watch: a #GstRTSPWatch
4375 * @bytes: maximum bytes
4376 * @messages: maximum messages
4378 * Set the maximum amount of bytes and messages that will be queued in @watch.
4379 * When the maximum amounts are exceeded, gst_rtsp_watch_write_data() and
4380 * gst_rtsp_watch_send_message() will return #GST_RTSP_ENOMEM.
4382 * A value of 0 for @bytes or @messages means no limits.
4387 gst_rtsp_watch_set_send_backlog (GstRTSPWatch * watch,
4388 gsize bytes, guint messages)
4390 g_return_if_fail (watch != NULL);
4392 g_mutex_lock (&watch->mutex);
4393 watch->max_bytes = bytes;
4394 watch->max_messages = messages;
4395 if (!IS_BACKLOG_FULL (watch))
4396 g_cond_signal (&watch->queue_not_full);
4397 g_mutex_unlock (&watch->mutex);
4399 GST_DEBUG ("set backlog to bytes %" G_GSIZE_FORMAT ", messages %u",
4404 * gst_rtsp_watch_get_send_backlog:
4405 * @watch: a #GstRTSPWatch
4406 * @bytes: (out) (allow-none): maximum bytes
4407 * @messages: (out) (allow-none): maximum messages
4409 * Get the maximum amount of bytes and messages that will be queued in @watch.
4410 * See gst_rtsp_watch_set_send_backlog().
4415 gst_rtsp_watch_get_send_backlog (GstRTSPWatch * watch,
4416 gsize * bytes, guint * messages)
4418 g_return_if_fail (watch != NULL);
4420 g_mutex_lock (&watch->mutex);
4422 *bytes = watch->max_bytes;
4424 *messages = watch->max_messages;
4425 g_mutex_unlock (&watch->mutex);
4428 static GstRTSPResult
4429 gst_rtsp_watch_write_serialized_messages (GstRTSPWatch * watch,
4430 GstRTSPSerializedMessage * messages, guint n_messages, guint * id)
4433 GMainContext *context = NULL;
4436 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4437 g_return_val_if_fail (messages != NULL, GST_RTSP_EINVAL);
4439 g_mutex_lock (&watch->mutex);
4440 if (watch->flushing)
4443 /* try to send the message synchronously first */
4444 if (gst_queue_array_get_length (watch->messages) == 0) {
4446 GOutputVector *vectors;
4447 GstMapInfo *map_infos;
4448 gsize bytes_to_write, bytes_written;
4449 guint n_vectors, n_memories, drop_messages;
4451 for (i = 0, n_vectors = 0, n_memories = 0; i < n_messages; i++) {
4453 if (messages[i].body_data) {
4455 } else if (messages[i].body_buffer) {
4456 n_vectors += gst_buffer_n_memory (messages[i].body_buffer);
4457 n_memories += gst_buffer_n_memory (messages[i].body_buffer);
4461 vectors = g_newa (GOutputVector, n_vectors);
4462 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
4464 for (i = 0, j = 0, k = 0, bytes_to_write = 0; i < n_messages; i++) {
4465 vectors[j].buffer = messages[i].data_is_data_header ?
4466 messages[i].data_header : messages[i].data;
4467 vectors[j].size = messages[i].data_size;
4468 bytes_to_write += vectors[j].size;
4471 if (messages[i].body_data) {
4472 vectors[j].buffer = messages[i].body_data;
4473 vectors[j].size = messages[i].body_data_size;
4474 bytes_to_write += vectors[j].size;
4476 } else if (messages[i].body_buffer) {
4479 n = gst_buffer_n_memory (messages[i].body_buffer);
4480 for (l = 0; l < n; l++) {
4481 GstMemory *mem = gst_buffer_peek_memory (messages[i].body_buffer, l);
4483 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
4484 vectors[j].buffer = map_infos[k].data;
4485 vectors[j].size = map_infos[k].size;
4486 bytes_to_write += vectors[j].size;
4495 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4496 &bytes_written, FALSE, watch->conn->cancellable);
4497 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4499 /* At this point we sent everything we could without blocking or
4500 * error and updated the offsets inside the message accordingly */
4502 /* First of all unmap all memories. This simplifies the code below */
4503 for (k = 0; k < n_memories; k++) {
4504 gst_memory_unmap (map_infos[k].memory, &map_infos[k]);
4507 if (res != GST_RTSP_EINTR) {
4508 /* actual error or done completely */
4512 /* free everything */
4513 for (i = 0, k = 0; i < n_messages; i++) {
4514 gst_rtsp_serialized_message_clear (&messages[i]);
4520 /* not done, let's skip all messages that were sent already and free them */
4521 for (i = 0, k = 0, drop_messages = 0; i < n_messages; i++) {
4522 if (bytes_written >= messages[i].data_size) {
4525 /* all data of this message is sent, check body and otherwise
4526 * skip the whole message for next time */
4527 messages[i].data_offset = messages[i].data_size;
4528 bytes_written -= messages[i].data_size;
4530 if (messages[i].body_data) {
4531 body_size = messages[i].body_data_size;
4533 } else if (messages[i].body_buffer) {
4534 body_size = gst_buffer_get_size (messages[i].body_buffer);
4539 if (bytes_written >= body_size) {
4540 /* body written, drop this message */
4541 messages[i].body_offset = body_size;
4542 bytes_written -= body_size;
4545 gst_rtsp_serialized_message_clear (&messages[i]);
4547 messages[i].body_offset = bytes_written;
4551 /* Need to continue sending from the data of this message */
4552 messages[i].data_offset = bytes_written;
4557 g_assert (n_messages > drop_messages);
4559 messages += drop_messages;
4560 n_messages -= drop_messages;
4564 if (IS_BACKLOG_FULL (watch))
4565 goto too_much_backlog;
4567 for (i = 0; i < n_messages; i++) {
4568 GstRTSPSerializedMessage local_message;
4570 /* make a record with the data and id for sending async */
4571 local_message = messages[i];
4573 /* copy the body data or take an additional reference to the body buffer
4574 * we don't own them here */
4575 if (local_message.body_data) {
4576 local_message.body_data =
4577 g_memdup2 (local_message.body_data, local_message.body_data_size);
4578 } else if (local_message.body_buffer) {
4579 gst_buffer_ref (local_message.body_buffer);
4581 local_message.borrowed = FALSE;
4583 /* set an id for the very last message */
4584 if (i == n_messages - 1) {
4586 /* make sure rec->id is never 0 */
4587 local_message.id = ++watch->id;
4588 } while (G_UNLIKELY (local_message.id == 0));
4591 *id = local_message.id;
4593 local_message.id = 0;
4596 /* add the record to a queue. */
4597 gst_queue_array_push_tail_struct (watch->messages, &local_message);
4598 watch->messages_bytes +=
4599 (local_message.data_size - local_message.data_offset);
4600 if (local_message.body_data)
4601 watch->messages_bytes +=
4602 (local_message.body_data_size - local_message.body_offset);
4603 else if (local_message.body_buffer)
4604 watch->messages_bytes +=
4605 (gst_buffer_get_size (local_message.body_buffer) -
4606 local_message.body_offset);
4608 /* each message chunks is one unit */
4609 watch->messages_count++;
4611 /* make sure the main context will now also check for writability on the
4613 context = ((GSource *) watch)->context;
4614 if (!watch->writesrc) {
4615 /* remove the read source on the write socket, we will be able to detect
4616 * errors while writing */
4617 if (watch->controlsrc) {
4618 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4619 g_source_unref (watch->controlsrc);
4620 watch->controlsrc = NULL;
4624 g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM
4625 (watch->conn->output_stream), NULL);
4626 g_source_set_callback (watch->writesrc,
4627 (GSourceFunc) gst_rtsp_source_dispatch_write, watch, NULL);
4628 g_source_add_child_source ((GSource *) watch, watch->writesrc);
4633 g_mutex_unlock (&watch->mutex);
4636 g_main_context_wakeup (context);
4643 GST_DEBUG ("we are flushing");
4644 g_mutex_unlock (&watch->mutex);
4645 for (i = 0; i < n_messages; i++) {
4646 gst_rtsp_serialized_message_clear (&messages[i]);
4648 return GST_RTSP_EINTR;
4652 GST_WARNING ("too much backlog: max_bytes %" G_GSIZE_FORMAT ", current %"
4653 G_GSIZE_FORMAT ", max_messages %u, current %u", watch->max_bytes,
4654 watch->messages_bytes, watch->max_messages, watch->messages_count);
4655 g_mutex_unlock (&watch->mutex);
4656 for (i = 0; i < n_messages; i++) {
4657 gst_rtsp_serialized_message_clear (&messages[i]);
4659 return GST_RTSP_ENOMEM;
4666 * gst_rtsp_watch_write_data:
4667 * @watch: a #GstRTSPWatch
4668 * @data: (array length=size) (transfer full): the data to queue
4669 * @size: the size of @data
4670 * @id: (out) (allow-none): location for a message ID or %NULL
4672 * Write @data using the connection of the @watch. If it cannot be sent
4673 * immediately, it will be queued for transmission in @watch. The contents of
4674 * @message will then be serialized and transmitted when the connection of the
4675 * @watch becomes writable. In case the @message is queued, the ID returned in
4676 * @id will be non-zero and used as the ID argument in the message_sent
4679 * This function will take ownership of @data and g_free() it after use.
4681 * If the amount of queued data exceeds the limits set with
4682 * gst_rtsp_watch_set_send_backlog(), this function will return
4685 * Returns: #GST_RTSP_OK on success. #GST_RTSP_ENOMEM when the backlog limits
4686 * are reached. #GST_RTSP_EINTR when @watch was flushing.
4688 /* FIXME 2.0: This should've been static! */
4690 gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
4691 guint size, guint * id)
4693 GstRTSPSerializedMessage serialized_message;
4695 memset (&serialized_message, 0, sizeof (serialized_message));
4696 serialized_message.data = (guint8 *) data;
4697 serialized_message.data_size = size;
4699 return gst_rtsp_watch_write_serialized_messages (watch, &serialized_message,
4704 * gst_rtsp_watch_send_message:
4705 * @watch: a #GstRTSPWatch
4706 * @message: a #GstRTSPMessage
4707 * @id: (out) (allow-none): location for a message ID or %NULL
4709 * Send a @message using the connection of the @watch. If it cannot be sent
4710 * immediately, it will be queued for transmission in @watch. The contents of
4711 * @message will then be serialized and transmitted when the connection of the
4712 * @watch becomes writable. In case the @message is queued, the ID returned in
4713 * @id will be non-zero and used as the ID argument in the message_sent
4716 * Returns: #GST_RTSP_OK on success.
4719 gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
4722 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4723 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4725 return gst_rtsp_watch_send_messages (watch, message, 1, id);
4729 * gst_rtsp_watch_send_messages:
4730 * @watch: a #GstRTSPWatch
4731 * @messages: (array length=n_messages): the messages to send
4732 * @n_messages: the number of messages to send
4733 * @id: (out) (allow-none): location for a message ID or %NULL
4735 * Sends @messages using the connection of the @watch. If they cannot be sent
4736 * immediately, they will be queued for transmission in @watch. The contents of
4737 * @messages will then be serialized and transmitted when the connection of the
4738 * @watch becomes writable. In case the @messages are queued, the ID returned in
4739 * @id will be non-zero and used as the ID argument in the message_sent
4740 * callback once the last message is sent. The callback will only be called
4741 * once for the last message.
4743 * Returns: #GST_RTSP_OK on success.
4748 gst_rtsp_watch_send_messages (GstRTSPWatch * watch, GstRTSPMessage * messages,
4749 guint n_messages, guint * id)
4751 GstRTSPSerializedMessage *serialized_messages;
4754 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4755 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
4757 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
4758 memset (serialized_messages, 0,
4759 sizeof (GstRTSPSerializedMessage) * n_messages);
4761 for (i = 0; i < n_messages; i++) {
4762 if (!serialize_message (watch->conn, &messages[i], &serialized_messages[i]))
4766 return gst_rtsp_watch_write_serialized_messages (watch, serialized_messages,
4770 for (i = 0; i < n_messages; i++) {
4771 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
4774 return GST_RTSP_EINVAL;
4778 * gst_rtsp_watch_wait_backlog_usec:
4779 * @watch: a #GstRTSPWatch
4780 * @timeout: a timeout in microseconds
4782 * Wait until there is place in the backlog queue, @timeout is reached
4783 * or @watch is set to flushing.
4785 * If @timeout is 0 this function can block forever. If @timeout
4786 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
4787 * after the timeout expired.
4789 * The typically use of this function is when gst_rtsp_watch_write_data
4790 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
4791 * free space in the backlog queue and try again.
4793 * Returns: %GST_RTSP_OK when if there is room in queue.
4794 * %GST_RTSP_ETIMEOUT when @timeout was reached.
4795 * %GST_RTSP_EINTR when @watch is flushing
4796 * %GST_RTSP_EINVAL when called with invalid parameters.
4801 gst_rtsp_watch_wait_backlog_usec (GstRTSPWatch * watch, gint64 timeout)
4805 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4807 end_time = g_get_monotonic_time () + timeout;
4809 g_mutex_lock (&watch->mutex);
4810 if (watch->flushing)
4813 while (IS_BACKLOG_FULL (watch)) {
4816 res = g_cond_wait_until (&watch->queue_not_full, &watch->mutex, end_time);
4817 if (watch->flushing)
4823 g_mutex_unlock (&watch->mutex);
4830 GST_DEBUG ("we are flushing");
4831 g_mutex_unlock (&watch->mutex);
4832 return GST_RTSP_EINTR;
4836 GST_DEBUG ("we timed out");
4837 g_mutex_unlock (&watch->mutex);
4838 return GST_RTSP_ETIMEOUT;
4843 * gst_rtsp_watch_set_flushing:
4844 * @watch: a #GstRTSPWatch
4845 * @flushing: new flushing state
4847 * When @flushing is %TRUE, abort a call to gst_rtsp_watch_wait_backlog()
4848 * and make sure gst_rtsp_watch_write_data() returns immediately with
4849 * #GST_RTSP_EINTR. And empty the queue.
4854 gst_rtsp_watch_set_flushing (GstRTSPWatch * watch, gboolean flushing)
4856 g_return_if_fail (watch != NULL);
4858 g_mutex_lock (&watch->mutex);
4859 watch->flushing = flushing;
4860 g_cond_signal (&watch->queue_not_full);
4862 GstRTSPSerializedMessage *msg;
4864 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4865 gst_rtsp_serialized_message_clear (msg);
4868 g_mutex_unlock (&watch->mutex);
4872 #ifndef GST_DISABLE_DEPRECATED
4873 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4875 #define TV_TO_USEC(tv) ((tv) ? ((tv)->tv_sec * G_USEC_PER_SEC + (tv)->tv_usec) : 0)
4877 * gst_rtsp_connection_connect:
4878 * @conn: a #GstRTSPConnection
4879 * @timeout: a GTimeVal timeout
4881 * Attempt to connect to the url of @conn made with
4882 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4883 * forever. If @timeout contains a valid timeout, this function will return
4884 * #GST_RTSP_ETIMEOUT after the timeout expired.
4886 * This function can be cancelled with gst_rtsp_connection_flush().
4888 * Returns: #GST_RTSP_OK when a connection could be made.
4893 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
4895 return gst_rtsp_connection_connect_usec (conn, TV_TO_USEC (timeout));
4899 * gst_rtsp_connection_connect_with_response:
4900 * @conn: a #GstRTSPConnection
4901 * @timeout: a GTimeVal timeout
4902 * @response: a #GstRTSPMessage
4904 * Attempt to connect to the url of @conn made with
4905 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4906 * forever. If @timeout contains a valid timeout, this function will return
4907 * #GST_RTSP_ETIMEOUT after the timeout expired. If @conn is set to tunneled,
4908 * @response will contain a response to the tunneling request messages.
4910 * This function can be cancelled with gst_rtsp_connection_flush().
4912 * Returns: #GST_RTSP_OK when a connection could be made.
4918 gst_rtsp_connection_connect_with_response (GstRTSPConnection * conn,
4919 GTimeVal * timeout, GstRTSPMessage * response)
4921 return gst_rtsp_connection_connect_with_response_usec (conn,
4922 TV_TO_USEC (timeout), response);
4926 * gst_rtsp_connection_read:
4927 * @conn: a #GstRTSPConnection
4928 * @data: the data to read
4929 * @size: the size of @data
4930 * @timeout: a timeout value or %NULL
4932 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
4933 * the specified @timeout. @timeout can be %NULL, in which case this function
4934 * might block forever.
4936 * This function can be cancelled with gst_rtsp_connection_flush().
4938 * Returns: #GST_RTSP_OK on success.
4943 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
4946 return gst_rtsp_connection_read_usec (conn, data, size, TV_TO_USEC (timeout));
4950 * gst_rtsp_connection_write:
4951 * @conn: a #GstRTSPConnection
4952 * @data: the data to write
4953 * @size: the size of @data
4954 * @timeout: a timeout value or %NULL
4956 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
4957 * the specified @timeout. @timeout can be %NULL, in which case this function
4958 * might block forever.
4960 * This function can be cancelled with gst_rtsp_connection_flush().
4962 * Returns: #GST_RTSP_OK on success.
4967 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
4968 guint size, GTimeVal * timeout)
4970 return gst_rtsp_connection_write_usec (conn, data, size,
4971 TV_TO_USEC (timeout));
4975 * gst_rtsp_connection_send:
4976 * @conn: a #GstRTSPConnection
4977 * @message: the message to send
4978 * @timeout: a timeout value or %NULL
4980 * Attempt to send @message to the connected @conn, blocking up to
4981 * the specified @timeout. @timeout can be %NULL, in which case this function
4982 * might block forever.
4984 * This function can be cancelled with gst_rtsp_connection_flush().
4986 * Returns: #GST_RTSP_OK on success.
4991 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
4994 return gst_rtsp_connection_send_usec (conn, message, TV_TO_USEC (timeout));
4998 * gst_rtsp_connection_send_messages:
4999 * @conn: a #GstRTSPConnection
5000 * @messages: (array length=n_messages): the messages to send
5001 * @n_messages: the number of messages to send
5002 * @timeout: a timeout value or %NULL
5004 * Attempt to send @messages to the connected @conn, blocking up to
5005 * the specified @timeout. @timeout can be %NULL, in which case this function
5006 * might block forever.
5008 * This function can be cancelled with gst_rtsp_connection_flush().
5010 * Returns: #GST_RTSP_OK on success.
5016 gst_rtsp_connection_send_messages (GstRTSPConnection * conn,
5017 GstRTSPMessage * messages, guint n_messages, GTimeVal * timeout)
5019 return gst_rtsp_connection_send_messages_usec (conn, messages, n_messages,
5020 TV_TO_USEC (timeout));
5024 * gst_rtsp_connection_receive:
5025 * @conn: a #GstRTSPConnection
5026 * @message: the message to read
5027 * @timeout: a timeout value or %NULL
5029 * Attempt to read into @message from the connected @conn, blocking up to
5030 * the specified @timeout. @timeout can be %NULL, in which case this function
5031 * might block forever.
5033 * This function can be cancelled with gst_rtsp_connection_flush().
5035 * Returns: #GST_RTSP_OK on success.
5040 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
5043 return gst_rtsp_connection_receive_usec (conn, message, TV_TO_USEC (timeout));
5047 * gst_rtsp_connection_poll:
5048 * @conn: a #GstRTSPConnection
5049 * @events: a bitmask of #GstRTSPEvent flags to check
5050 * @revents: location for result flags
5051 * @timeout: a timeout
5053 * Wait up to the specified @timeout for the connection to become available for
5054 * at least one of the operations specified in @events. When the function returns
5055 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
5058 * @timeout can be %NULL, in which case this function might block forever.
5060 * This function can be cancelled with gst_rtsp_connection_flush().
5062 * Returns: #GST_RTSP_OK on success.
5067 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
5068 GstRTSPEvent * revents, GTimeVal * timeout)
5070 return gst_rtsp_connection_poll_usec (conn, events, revents,
5071 TV_TO_USEC (timeout));
5075 * gst_rtsp_connection_next_timeout:
5076 * @conn: a #GstRTSPConnection
5077 * @timeout: a timeout
5079 * Calculate the next timeout for @conn, storing the result in @timeout.
5081 * Returns: #GST_RTSP_OK.
5086 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
5088 gint64 tmptimeout = 0;
5090 g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
5092 tmptimeout = gst_rtsp_connection_next_timeout_usec (conn);
5094 timeout->tv_sec = tmptimeout / G_USEC_PER_SEC;
5095 timeout->tv_usec = tmptimeout % G_USEC_PER_SEC;
5102 * gst_rtsp_watch_wait_backlog:
5103 * @watch: a #GstRTSPWatch
5104 * @timeout: a GTimeVal timeout
5106 * Wait until there is place in the backlog queue, @timeout is reached
5107 * or @watch is set to flushing.
5109 * If @timeout is %NULL this function can block forever. If @timeout
5110 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
5111 * after the timeout expired.
5113 * The typically use of this function is when gst_rtsp_watch_write_data
5114 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
5115 * free space in the backlog queue and try again.
5117 * Returns: %GST_RTSP_OK when if there is room in queue.
5118 * %GST_RTSP_ETIMEOUT when @timeout was reached.
5119 * %GST_RTSP_EINTR when @watch is flushing
5120 * %GST_RTSP_EINVAL when called with invalid parameters.
5126 gst_rtsp_watch_wait_backlog (GstRTSPWatch * watch, GTimeVal * timeout)
5128 return gst_rtsp_watch_wait_backlog_usec (watch, TV_TO_USEC (timeout));
5131 G_GNUC_END_IGNORE_DEPRECATIONS
5132 #endif /* GST_DISABLE_DEPRECATED */