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 read_socket_used;
171 gboolean write_socket_used;
172 GMutex socket_use_mutex;
173 gboolean manual_http;
175 GCancellable *cancellable;
177 gchar tunnelid[TUNNELID_LEN];
179 gboolean ignore_x_server_reply;
180 GstRTSPTunnelState tstate;
182 /* the remote and local ip */
188 gchar *initial_buffer;
189 gsize initial_buffer_offset;
191 gboolean remember_session_id; /* remember the session id or not */
194 gint cseq; /* sequence number */
195 gchar session_id[512]; /* session id */
196 gint timeout; /* session timeout in seconds */
197 GTimer *timer; /* timeout timer */
200 GstRTSPAuthMethod auth_method;
203 GHashTable *auth_params;
205 guint content_length_limit;
208 GTlsDatabase *tls_database;
209 GTlsInteraction *tls_interaction;
211 GstRTSPConnectionAcceptCertificateFunc accept_certificate_func;
212 GDestroyNotify accept_certificate_destroy_notify;
213 gpointer accept_certificate_user_data;
234 READ_AHEAD_EOH = -1, /* end of headers */
235 READ_AHEAD_CRLF = -2,
236 READ_AHEAD_CRLFCR = -3
239 /* a structure for constructing RTSPMessages */
243 GstRTSPResult status;
252 /* function prototypes */
253 static void add_auth_header (GstRTSPConnection * conn,
254 GstRTSPMessage * message);
257 build_reset (GstRTSPBuilder * builder)
259 g_free (builder->body_data);
260 memset (builder, 0, sizeof (GstRTSPBuilder));
264 gst_rtsp_result_from_g_io_error (GError * error, GstRTSPResult default_res)
269 if (error->domain != G_IO_ERROR)
272 switch (error->code) {
273 case G_IO_ERROR_TIMED_OUT:
274 return GST_RTSP_ETIMEOUT;
275 case G_IO_ERROR_INVALID_ARGUMENT:
276 return GST_RTSP_EINVAL;
277 case G_IO_ERROR_CANCELLED:
278 case G_IO_ERROR_WOULD_BLOCK:
279 return GST_RTSP_EINTR;
286 tls_accept_certificate (GTlsConnection * conn, GTlsCertificate * peer_cert,
287 GTlsCertificateFlags errors, GstRTSPConnection * rtspconn)
289 GError *error = NULL;
290 gboolean accept = FALSE;
292 if (rtspconn->tls_database) {
293 GSocketConnectable *peer_identity;
294 GTlsCertificateFlags validation_flags;
296 GST_DEBUG ("TLS peer certificate not accepted, checking user database...");
299 g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION
303 g_tls_database_verify_chain (rtspconn->tls_database, peer_cert,
304 G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER, peer_identity,
305 g_tls_connection_get_interaction (conn), G_TLS_DATABASE_VERIFY_NONE,
311 validation_flags = gst_rtsp_connection_get_tls_validation_flags (rtspconn);
313 accept = ((errors & validation_flags) == 0);
315 GST_DEBUG ("Peer certificate accepted");
317 GST_DEBUG ("Peer certificate not accepted (errors: 0x%08X)", errors);
320 if (!accept && rtspconn->accept_certificate_func) {
322 rtspconn->accept_certificate_func (conn, peer_cert, errors,
323 rtspconn->accept_certificate_user_data);
324 GST_DEBUG ("Peer certificate %saccepted by accept-certificate function",
325 accept ? "" : "not ");
333 GST_ERROR ("An error occurred while verifying the peer certificate: %s",
335 g_clear_error (&error);
341 socket_client_event (GSocketClient * client, GSocketClientEvent event,
342 GSocketConnectable * connectable, GTlsConnection * connection,
343 GstRTSPConnection * rtspconn)
345 if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) {
346 GST_DEBUG ("TLS handshaking about to start...");
348 g_signal_connect (connection, "accept-certificate",
349 (GCallback) tls_accept_certificate, rtspconn);
351 g_tls_connection_set_interaction (connection, rtspconn->tls_interaction);
356 * gst_rtsp_connection_create:
357 * @url: a #GstRTSPUrl
358 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
360 * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
361 * The connection will not yet attempt to connect to @url, use
362 * gst_rtsp_connection_connect().
364 * A copy of @url will be made.
366 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
369 gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
371 GstRTSPConnection *newconn;
373 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
374 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
376 newconn = g_new0 (GstRTSPConnection, 1);
378 newconn->may_cancel = TRUE;
379 newconn->cancellable = g_cancellable_new ();
380 newconn->client = g_socket_client_new ();
382 if (url->transports & GST_RTSP_LOWER_TRANS_TLS)
383 g_socket_client_set_tls (newconn->client, TRUE);
385 g_signal_connect (newconn->client, "event", (GCallback) socket_client_event,
388 newconn->url = gst_rtsp_url_copy (url);
389 newconn->timer = g_timer_new ();
390 newconn->timeout = 60;
391 newconn->cseq = 1; /* RFC 7826: "it is RECOMMENDED to start at 0.",
392 but some servers don't copy values <1 due to bugs. */
394 newconn->remember_session_id = TRUE;
396 newconn->auth_method = GST_RTSP_AUTH_NONE;
397 newconn->username = NULL;
398 newconn->passwd = NULL;
399 newconn->auth_params = NULL;
400 newconn->version = 0;
402 newconn->content_length_limit = G_MAXUINT;
410 collect_addresses (GSocket * socket, gchar ** ip, guint16 * port,
411 gboolean remote, GError ** error)
413 GSocketAddress *addr;
416 addr = g_socket_get_remote_address (socket, error);
418 addr = g_socket_get_local_address (socket, error);
423 *ip = g_inet_address_to_string (g_inet_socket_address_get_address
424 (G_INET_SOCKET_ADDRESS (addr)));
426 *port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
428 g_object_unref (addr);
435 * gst_rtsp_connection_create_from_socket:
436 * @socket: a #GSocket
437 * @ip: the IP address of the other end
438 * @port: the port used by the other end
439 * @initial_buffer: data already read from @fd
440 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
442 * Create a new #GstRTSPConnection for handling communication on the existing
443 * socket @socket. The @initial_buffer contains zero terminated data already
444 * read from @socket which should be used before starting to read new data.
446 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
448 /* FIXME 2.0 We don't need the ip and port since they can be got from the
451 gst_rtsp_connection_create_from_socket (GSocket * socket, const gchar * ip,
452 guint16 port, const gchar * initial_buffer, GstRTSPConnection ** conn)
454 GstRTSPConnection *newconn = NULL;
461 g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
462 g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL);
463 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
465 if (!collect_addresses (socket, &local_ip, NULL, FALSE, &err))
466 goto getnameinfo_failed;
468 /* create a url for the client address */
469 url = g_new0 (GstRTSPUrl, 1);
470 url->host = g_strdup (ip);
473 /* now create the connection object */
474 GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
475 gst_rtsp_url_free (url);
477 stream = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
479 /* both read and write initially */
480 newconn->server = TRUE;
481 newconn->socket0 = socket;
482 newconn->stream0 = stream;
483 newconn->write_socket = newconn->read_socket = newconn->socket0;
484 newconn->read_socket_used = FALSE;
485 newconn->write_socket_used = FALSE;
486 g_mutex_init (&newconn->socket_use_mutex);
487 newconn->input_stream = g_io_stream_get_input_stream (stream);
488 newconn->output_stream = g_io_stream_get_output_stream (stream);
489 newconn->control_stream = NULL;
490 newconn->remote_ip = g_strdup (ip);
491 newconn->local_ip = local_ip;
492 newconn->initial_buffer = g_strdup (initial_buffer);
501 GST_ERROR ("failed to get local address: %s", err->message);
502 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ERROR);
503 g_clear_error (&err);
508 GST_ERROR ("failed to make connection");
510 gst_rtsp_url_free (url);
516 * gst_rtsp_connection_accept:
518 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
519 * @cancellable: a #GCancellable to cancel the operation
521 * Accept a new connection on @socket and create a new #GstRTSPConnection for
522 * handling communication on new socket.
524 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
527 gst_rtsp_connection_accept (GSocket * socket, GstRTSPConnection ** conn,
528 GCancellable * cancellable)
533 GSocket *client_sock;
536 g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
537 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
539 client_sock = g_socket_accept (socket, cancellable, &err);
543 /* get the remote ip address and port */
544 if (!collect_addresses (client_sock, &ip, &port, TRUE, &err))
545 goto getnameinfo_failed;
548 gst_rtsp_connection_create_from_socket (client_sock, ip, port, NULL,
550 g_object_unref (client_sock);
558 GST_DEBUG ("Accepting client failed: %s", err->message);
559 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
560 g_clear_error (&err);
565 GST_DEBUG ("getnameinfo failed: %s", err->message);
566 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ERROR);
567 g_clear_error (&err);
568 if (!g_socket_close (client_sock, &err)) {
569 GST_DEBUG ("Closing socket failed: %s", err->message);
570 g_clear_error (&err);
572 g_object_unref (client_sock);
578 * gst_rtsp_connection_get_tls:
579 * @conn: a #GstRTSPConnection
580 * @error: #GError for error reporting, or NULL to ignore.
582 * Get the TLS connection of @conn.
584 * For client side this will return the #GTlsClientConnection when connected
587 * For server side connections, this function will create a GTlsServerConnection
588 * when called the first time and will return that same connection on subsequent
589 * calls. The server is then responsible for configuring the TLS connection.
591 * Returns: (transfer none): the TLS connection for @conn.
596 gst_rtsp_connection_get_tls (GstRTSPConnection * conn, GError ** error)
598 GTlsConnection *result;
600 if (G_IS_TLS_CONNECTION (conn->stream0)) {
601 /* we already had one, return it */
602 result = G_TLS_CONNECTION (conn->stream0);
603 } else if (conn->server) {
604 /* no TLS connection but we are server, make one */
605 result = (GTlsConnection *)
606 g_tls_server_connection_new (conn->stream0, NULL, error);
608 g_object_unref (conn->stream0);
609 conn->stream0 = G_IO_STREAM (result);
610 conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
611 conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
616 g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
617 "client not connected with TLS");
623 * gst_rtsp_connection_set_tls_validation_flags:
624 * @conn: a #GstRTSPConnection
625 * @flags: the validation flags.
627 * Sets the TLS validation flags to be used to verify the peer
628 * certificate when a TLS connection is established.
630 * Returns: TRUE if the validation flags are set correctly, or FALSE if
631 * @conn is NULL or is not a TLS connection.
636 gst_rtsp_connection_set_tls_validation_flags (GstRTSPConnection * conn,
637 GTlsCertificateFlags flags)
639 gboolean res = FALSE;
641 g_return_val_if_fail (conn != NULL, FALSE);
643 res = g_socket_client_get_tls (conn->client);
645 g_socket_client_set_tls_validation_flags (conn->client, flags);
651 * gst_rtsp_connection_get_tls_validation_flags:
652 * @conn: a #GstRTSPConnection
654 * Gets the TLS validation flags used to verify the peer certificate
655 * when a TLS connection is established.
657 * Returns: the validationg flags.
662 gst_rtsp_connection_get_tls_validation_flags (GstRTSPConnection * conn)
664 g_return_val_if_fail (conn != NULL, 0);
666 return g_socket_client_get_tls_validation_flags (conn->client);
670 * gst_rtsp_connection_set_tls_database:
671 * @conn: a #GstRTSPConnection
672 * @database: a #GTlsDatabase
674 * Sets the anchor certificate authorities database. This certificate
675 * database will be used to verify the server's certificate in case it
676 * can't be verified with the default certificate database first.
681 gst_rtsp_connection_set_tls_database (GstRTSPConnection * conn,
682 GTlsDatabase * database)
684 GTlsDatabase *old_db;
686 g_return_if_fail (conn != NULL);
689 g_object_ref (database);
691 old_db = conn->tls_database;
692 conn->tls_database = database;
695 g_object_unref (old_db);
699 * gst_rtsp_connection_get_tls_database:
700 * @conn: a #GstRTSPConnection
702 * Gets the anchor certificate authorities database that will be used
703 * after a server certificate can't be verified with the default
704 * certificate database.
706 * Returns: (transfer full): the anchor certificate authorities database, or NULL if no
707 * database has been previously set. Use g_object_unref() to release the
708 * certificate database.
713 gst_rtsp_connection_get_tls_database (GstRTSPConnection * conn)
715 GTlsDatabase *result;
717 g_return_val_if_fail (conn != NULL, NULL);
719 if ((result = conn->tls_database))
720 g_object_ref (result);
726 * gst_rtsp_connection_set_tls_interaction:
727 * @conn: a #GstRTSPConnection
728 * @interaction: a #GTlsInteraction
730 * Sets a #GTlsInteraction object to be used when the connection or certificate
731 * database need to interact with the user. This will be used to prompt the
732 * user for passwords where necessary.
737 gst_rtsp_connection_set_tls_interaction (GstRTSPConnection * conn,
738 GTlsInteraction * interaction)
740 GTlsInteraction *old_interaction;
742 g_return_if_fail (conn != NULL);
745 g_object_ref (interaction);
747 old_interaction = conn->tls_interaction;
748 conn->tls_interaction = interaction;
751 g_object_unref (old_interaction);
755 * gst_rtsp_connection_get_tls_interaction:
756 * @conn: a #GstRTSPConnection
758 * Gets a #GTlsInteraction object to be used when the connection or certificate
759 * database need to interact with the user. This will be used to prompt the
760 * user for passwords where necessary.
762 * Returns: (transfer full): a reference on the #GTlsInteraction. Use
763 * g_object_unref() to release.
768 gst_rtsp_connection_get_tls_interaction (GstRTSPConnection * conn)
770 GTlsInteraction *result;
772 g_return_val_if_fail (conn != NULL, NULL);
774 if ((result = conn->tls_interaction))
775 g_object_ref (result);
781 * gst_rtsp_connection_set_accept_certificate_func:
782 * @conn: a #GstRTSPConnection
783 * @func: a #GstRTSPConnectionAcceptCertificateFunc to check certificates
784 * @destroy_notify: #GDestroyNotify for @user_data
785 * @user_data: User data passed to @func
787 * Sets a custom accept-certificate function for checking certificates for
788 * validity. This will directly map to #GTlsConnection 's "accept-certificate"
789 * signal and be performed after the default checks of #GstRTSPConnection
790 * (checking against the #GTlsDatabase with the given #GTlsCertificateFlags)
791 * have failed. If no #GTlsDatabase is set on this connection, only @func will
797 gst_rtsp_connection_set_accept_certificate_func (GstRTSPConnection * conn,
798 GstRTSPConnectionAcceptCertificateFunc func,
799 gpointer user_data, GDestroyNotify destroy_notify)
801 if (conn->accept_certificate_destroy_notify)
803 accept_certificate_destroy_notify (conn->accept_certificate_user_data);
804 conn->accept_certificate_func = func;
805 conn->accept_certificate_user_data = user_data;
806 conn->accept_certificate_destroy_notify = destroy_notify;
810 get_tunneled_connection_uri_strdup (GstRTSPUrl * url, guint16 port)
812 const gchar *pre_host = "";
813 const gchar *post_host = "";
815 if (url->family == GST_RTSP_FAM_INET6) {
820 return g_strdup_printf ("http://%s%s%s:%d%s%s%s", pre_host, url->host,
821 post_host, port, url->abspath, url->query ? "?" : "",
822 url->query ? url->query : "");
826 setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
827 GstRTSPMessage * response)
836 GError *error = NULL;
837 GSocketConnection *connection;
839 gchar *connection_uri = NULL;
840 gchar *request_uri = NULL;
845 gst_rtsp_url_get_port (url, &url_port);
846 host = g_strdup_printf ("%s:%d", url->host, url_port);
848 /* create a random sessionid */
849 for (i = 0; i < TUNNELID_LEN; i++)
850 conn->tunnelid[i] = g_random_int_range ('a', 'z');
851 conn->tunnelid[TUNNELID_LEN - 1] = '\0';
853 /* create the GET request for the read connection */
854 GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
856 msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
858 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
860 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
861 "application/x-rtsp-tunnelled");
862 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
863 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
864 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, host);
866 /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
867 * request from being base64 encoded */
868 conn->tunneled = FALSE;
869 GST_RTSP_CHECK (gst_rtsp_connection_send_usec (conn, msg, timeout),
871 gst_rtsp_message_free (msg);
872 conn->tunneled = TRUE;
874 /* receive the response to the GET request */
875 /* we need to temporarily set manual_http to TRUE since
876 * gst_rtsp_connection_receive() will treat the HTTP response as a parsing
877 * failure otherwise */
878 old_http = conn->manual_http;
879 conn->manual_http = TRUE;
880 GST_RTSP_CHECK (gst_rtsp_connection_receive_usec (conn, response, timeout),
882 conn->manual_http = old_http;
884 if (response->type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
885 response->type_data.response.code != GST_RTSP_STS_OK)
888 if (!conn->ignore_x_server_reply &&
889 gst_rtsp_message_get_header (response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
890 &value, 0) == GST_RTSP_OK) {
892 url->host = g_strdup (value);
893 g_free (conn->remote_ip);
894 conn->remote_ip = g_strdup (value);
897 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
899 /* connect to the host/port */
900 if (conn->proxy_host) {
901 connection = g_socket_client_connect_to_host (conn->client,
902 conn->proxy_host, conn->proxy_port, conn->cancellable, &error);
903 request_uri = g_strdup (connection_uri);
905 connection = g_socket_client_connect_to_uri (conn->client,
906 connection_uri, 0, conn->cancellable, &error);
908 g_strdup_printf ("%s%s%s", url->abspath,
909 url->query ? "?" : "", url->query ? url->query : "");
911 if (connection == NULL)
914 socket = g_socket_connection_get_socket (connection);
916 /* get remote address */
917 g_free (conn->remote_ip);
918 conn->remote_ip = NULL;
920 if (!collect_addresses (socket, &conn->remote_ip, NULL, TRUE, &error))
921 goto remote_address_failed;
923 /* this is now our writing socket */
924 conn->stream1 = G_IO_STREAM (connection);
925 conn->socket1 = socket;
926 conn->write_socket = conn->socket1;
927 conn->output_stream = g_io_stream_get_output_stream (conn->stream1);
928 conn->control_stream = NULL;
930 /* create the POST request for the write connection */
931 GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST,
932 request_uri), no_message);
933 msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
935 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
937 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
938 "application/x-rtsp-tunnelled");
939 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
940 "application/x-rtsp-tunnelled");
941 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
942 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
943 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES,
944 "Sun, 9 Jan 1972 00:00:00 GMT");
945 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767");
946 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, host);
948 /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
949 * request from being base64 encoded */
950 conn->tunneled = FALSE;
951 GST_RTSP_CHECK (gst_rtsp_connection_send_usec (conn, msg, timeout),
953 gst_rtsp_message_free (msg);
954 conn->tunneled = TRUE;
957 g_free (connection_uri);
958 g_free (request_uri);
966 GST_ERROR ("failed to create request (%d)", res);
971 GST_ERROR ("write failed (%d)", res);
972 gst_rtsp_message_free (msg);
973 conn->tunneled = TRUE;
978 GST_ERROR ("read failed (%d)", res);
979 conn->manual_http = FALSE;
984 GST_ERROR ("got failure response %d %s",
985 response->type_data.response.code, response->type_data.response.reason);
986 res = GST_RTSP_ERROR;
991 GST_ERROR ("failed to connect: %s", error->message);
992 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
993 g_clear_error (&error);
996 remote_address_failed:
998 GST_ERROR ("failed to resolve address: %s", error->message);
999 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
1000 g_object_unref (connection);
1001 g_clear_error (&error);
1007 * gst_rtsp_connection_connect_with_response_usec:
1008 * @conn: a #GstRTSPConnection
1009 * @timeout: a timeout in microseconds
1010 * @response: a #GstRTSPMessage
1012 * Attempt to connect to the url of @conn made with
1013 * gst_rtsp_connection_create(). If @timeout is 0 this function can block
1014 * forever. If @timeout contains a valid timeout, this function will return
1015 * #GST_RTSP_ETIMEOUT after the timeout expired. If @conn is set to tunneled,
1016 * @response will contain a response to the tunneling request messages.
1018 * This function can be cancelled with gst_rtsp_connection_flush().
1020 * Returns: #GST_RTSP_OK when a connection could be made.
1025 gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
1026 gint64 timeout, GstRTSPMessage * response)
1029 GSocketConnection *connection;
1031 GError *error = NULL;
1032 gchar *connection_uri, *request_uri, *remote_ip;
1037 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1038 g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
1039 g_return_val_if_fail (conn->stream0 == NULL, GST_RTSP_EINVAL);
1041 to = timeout * 1000;
1042 g_socket_client_set_timeout (conn->client,
1043 (to + GST_SECOND - 1) / GST_SECOND);
1047 gst_rtsp_url_get_port (url, &url_port);
1049 if (conn->tunneled) {
1050 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
1052 connection_uri = gst_rtsp_url_get_request_uri (url);
1055 if (conn->proxy_host) {
1056 connection = g_socket_client_connect_to_host (conn->client,
1057 conn->proxy_host, conn->proxy_port, conn->cancellable, &error);
1058 request_uri = g_strdup (connection_uri);
1060 connection = g_socket_client_connect_to_uri (conn->client,
1061 connection_uri, url_port, conn->cancellable, &error);
1063 /* use the relative component of the uri for non-proxy connections */
1064 request_uri = g_strdup_printf ("%s%s%s", url->abspath,
1065 url->query ? "?" : "", url->query ? url->query : "");
1067 if (connection == NULL)
1068 goto connect_failed;
1070 /* get remote address */
1071 socket = g_socket_connection_get_socket (connection);
1073 if (!collect_addresses (socket, &remote_ip, NULL, TRUE, &error))
1074 goto remote_address_failed;
1076 g_free (conn->remote_ip);
1077 conn->remote_ip = remote_ip;
1078 conn->stream0 = G_IO_STREAM (connection);
1079 conn->socket0 = socket;
1080 /* this is our read socket */
1081 conn->read_socket = conn->socket0;
1082 conn->write_socket = conn->socket0;
1083 conn->read_socket_used = FALSE;
1084 conn->write_socket_used = FALSE;
1085 conn->input_stream = g_io_stream_get_input_stream (conn->stream0);
1086 conn->output_stream = g_io_stream_get_output_stream (conn->stream0);
1087 conn->control_stream = NULL;
1089 if (conn->tunneled) {
1090 res = setup_tunneling (conn, timeout, request_uri, response);
1091 if (res != GST_RTSP_OK)
1092 goto tunneling_failed;
1094 g_free (connection_uri);
1095 g_free (request_uri);
1102 GST_ERROR ("failed to connect: %s", error->message);
1103 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
1104 g_clear_error (&error);
1105 g_free (connection_uri);
1106 g_free (request_uri);
1109 remote_address_failed:
1111 GST_ERROR ("failed to connect: %s", error->message);
1112 res = gst_rtsp_result_from_g_io_error (error, GST_RTSP_ERROR);
1113 g_object_unref (connection);
1114 g_clear_error (&error);
1115 g_free (connection_uri);
1116 g_free (request_uri);
1121 GST_ERROR ("failed to setup tunneling");
1122 g_free (connection_uri);
1123 g_free (request_uri);
1129 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
1131 switch (conn->auth_method) {
1132 case GST_RTSP_AUTH_BASIC:{
1137 if (conn->username == NULL || conn->passwd == NULL)
1140 user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
1141 user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
1142 auth_string = g_strdup_printf ("Basic %s", user_pass64);
1144 gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
1148 g_free (user_pass64);
1151 case GST_RTSP_AUTH_DIGEST:{
1153 gchar *auth_string, *auth_string2;
1158 const gchar *method;
1160 /* we need to have some params set */
1161 if (conn->auth_params == NULL || conn->username == NULL ||
1162 conn->passwd == NULL)
1165 /* we need the realm and nonce */
1166 realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
1167 nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
1168 if (realm == NULL || nonce == NULL)
1171 method = gst_rtsp_method_as_text (message->type_data.request.method);
1172 uri = message->type_data.request.uri;
1175 gst_rtsp_generate_digest_auth_response (NULL, method, realm,
1176 conn->username, conn->passwd, uri, nonce);
1178 g_strdup_printf ("Digest username=\"%s\", "
1179 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
1180 conn->username, realm, nonce, uri, response);
1183 opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
1185 auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
1187 g_free (auth_string);
1188 auth_string = auth_string2;
1190 /* Do not keep any old Authorization headers */
1191 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_AUTHORIZATION, -1);
1192 gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
1203 * gst_rtsp_connection_connect_usec:
1204 * @conn: a #GstRTSPConnection
1205 * @timeout: a timeout in microseconds
1207 * Attempt to connect to the url of @conn made with
1208 * gst_rtsp_connection_create(). If @timeout is 0 this function can block
1209 * forever. If @timeout contains a valid timeout, this function will return
1210 * #GST_RTSP_ETIMEOUT after the timeout expired.
1212 * This function can be cancelled with gst_rtsp_connection_flush().
1214 * Returns: #GST_RTSP_OK when a connection could be made.
1219 gst_rtsp_connection_connect_usec (GstRTSPConnection * conn, gint64 timeout)
1221 GstRTSPResult result;
1222 GstRTSPMessage response;
1224 memset (&response, 0, sizeof (response));
1225 gst_rtsp_message_init (&response);
1227 result = gst_rtsp_connection_connect_with_response_usec (conn, timeout,
1230 gst_rtsp_message_unset (&response);
1236 gen_date_string (gchar * date_string, guint len)
1238 static const char wkdays[7][4] =
1239 { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
1240 static const char months[12][4] =
1241 { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
1249 #ifdef HAVE_GMTIME_R
1255 g_snprintf (date_string, len, "%s, %02d %s %04d %02d:%02d:%02d GMT",
1256 wkdays[tm.tm_wday], tm.tm_mday, months[tm.tm_mon], tm.tm_year + 1900,
1257 tm.tm_hour, tm.tm_min, tm.tm_sec);
1260 static GstRTSPResult
1261 write_bytes (GOutputStream * stream, const guint8 * buffer, guint * idx,
1262 guint size, gboolean block, GCancellable * cancellable)
1269 if (G_UNLIKELY (*idx > size))
1270 return GST_RTSP_ERROR;
1276 r = g_output_stream_write (stream, (gchar *) & buffer[*idx], left,
1279 r = g_pollable_output_stream_write_nonblocking (G_POLLABLE_OUTPUT_STREAM
1280 (stream), (gchar *) & buffer[*idx], left, cancellable, &err);
1281 if (G_UNLIKELY (r < 0))
1292 if (G_UNLIKELY (r == 0))
1293 return GST_RTSP_EEOF;
1295 if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1296 GST_WARNING ("%s", err->message);
1298 GST_DEBUG ("%s", err->message);
1300 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1301 g_clear_error (&err);
1306 /* NOTE: This changes the values of vectors if multiple iterations are needed! */
1307 static GstRTSPResult
1308 writev_bytes (GOutputStream * stream, GOutputVector * vectors, gint n_vectors,
1309 gsize * bytes_written, gboolean block, GCancellable * cancellable)
1311 gsize _bytes_written = 0;
1315 GPollableReturn res = G_POLLABLE_RETURN_OK;
1317 while (n_vectors > 0) {
1319 if (G_UNLIKELY (!g_output_stream_writev (stream, vectors, n_vectors,
1320 &written, cancellable, &err))) {
1321 /* This will never return G_IO_ERROR_WOULD_BLOCK */
1322 res = G_POLLABLE_RETURN_FAILED;
1327 g_pollable_output_stream_writev_nonblocking (G_POLLABLE_OUTPUT_STREAM
1328 (stream), vectors, n_vectors, &written, cancellable, &err);
1330 if (res != G_POLLABLE_RETURN_OK) {
1331 g_assert (written == 0);
1335 _bytes_written += written;
1337 /* skip vectors that have been written in full */
1338 while (written > 0 && written >= vectors[0].size) {
1339 written -= vectors[0].size;
1344 /* skip partially written vector data */
1346 vectors[0].size -= written;
1347 vectors[0].buffer = ((guint8 *) vectors[0].buffer) + written;
1351 *bytes_written = _bytes_written;
1358 *bytes_written = _bytes_written;
1361 GST_WARNING ("%s", err->message);
1362 if (res == G_POLLABLE_RETURN_WOULD_BLOCK) {
1364 return GST_RTSP_EINTR;
1365 } else if (G_UNLIKELY (written == 0)) {
1366 g_clear_error (&err);
1367 return GST_RTSP_EEOF;
1370 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1371 g_clear_error (&err);
1377 fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1378 gboolean block, GError ** err)
1382 if (G_UNLIKELY (conn->initial_buffer != NULL)) {
1383 gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
1385 out = MIN (left, size);
1386 memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
1388 if (left == (gsize) out) {
1389 g_free (conn->initial_buffer);
1390 conn->initial_buffer = NULL;
1391 conn->initial_buffer_offset = 0;
1393 conn->initial_buffer_offset += out;
1396 if (G_LIKELY (size > (guint) out)) {
1398 gsize count = size - out;
1400 r = g_input_stream_read (conn->input_stream, (gchar *) & buffer[out],
1401 count, conn->may_cancel ? conn->cancellable : NULL, err);
1403 r = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM
1404 (conn->input_stream), (gchar *) & buffer[out], count,
1405 conn->may_cancel ? conn->cancellable : NULL, err);
1407 if (G_UNLIKELY (r < 0)) {
1409 /* propagate the error */
1412 /* we have some data ignore error */
1413 g_clear_error (err);
1423 fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1424 gboolean block, GError ** err)
1426 DecodeCtx *ctx = conn->ctxp;
1431 guint8 in[sizeof (ctx->out) * 4 / 3];
1434 while (size > 0 && ctx->cout < ctx->coutl) {
1435 /* we have some leftover bytes */
1436 *buffer++ = ctx->out[ctx->cout++];
1441 /* got what we needed? */
1445 /* try to read more bytes */
1446 r = fill_raw_bytes (conn, in, sizeof (in), block, err);
1451 /* we have some data ignore error */
1452 g_clear_error (err);
1459 g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
1463 out = fill_raw_bytes (conn, buffer, size, block, err);
1469 static GstRTSPResult
1470 read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1478 if (G_UNLIKELY (*idx > size))
1479 return GST_RTSP_ERROR;
1484 r = fill_bytes (conn, &buffer[*idx], left, block, &err);
1485 if (G_UNLIKELY (r <= 0))
1496 if (G_UNLIKELY (r == 0))
1497 return GST_RTSP_EEOF;
1499 GST_DEBUG ("%s", err->message);
1500 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1501 g_clear_error (&err);
1506 /* The code below tries to handle clients using \r, \n or \r\n to indicate the
1507 * end of a line. It even does its best to handle clients which mix them (even
1508 * though this is a really stupid idea (tm).) It also handles Line White Space
1509 * (LWS), where a line end followed by whitespace is considered LWS. This is
1510 * the method used in RTSP (and HTTP) to break long lines.
1512 static GstRTSPResult
1513 read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1522 if (conn->read_ahead == READ_AHEAD_EOH) {
1523 /* the last call to read_line() already determined that we have reached
1524 * the end of the headers, so convey that information now */
1525 conn->read_ahead = 0;
1527 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1528 /* the last call to read_line() left off after having read \r\n */
1530 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1531 /* the last call to read_line() left off after having read \r\n\r */
1533 } else if (conn->read_ahead != 0) {
1534 /* the last call to read_line() left us with a character to start with */
1535 c = (guint8) conn->read_ahead;
1536 conn->read_ahead = 0;
1538 /* read the next character */
1540 res = read_bytes (conn, &c, &i, 1, block);
1541 if (G_UNLIKELY (res != GST_RTSP_OK))
1545 /* special treatment of line endings */
1546 if (c == '\r' || c == '\n') {
1550 /* need to read ahead one more character to know what to do... */
1552 res = read_bytes (conn, &read_ahead, &i, 1, block);
1553 if (G_UNLIKELY (res != GST_RTSP_OK))
1556 if (read_ahead == ' ' || read_ahead == '\t') {
1557 if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1558 /* got \r\n\r followed by whitespace, treat it as a normal line
1559 * followed by one starting with LWS */
1560 conn->read_ahead = read_ahead;
1563 /* got LWS, change the line ending to a space and continue */
1565 conn->read_ahead = read_ahead;
1567 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1568 if (read_ahead == '\r' || read_ahead == '\n') {
1569 /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
1570 conn->read_ahead = READ_AHEAD_EOH;
1573 /* got \r\n\r followed by something else, this is not really
1574 * supported since we have probably just eaten the first character
1575 * of the body or the next message, so just ignore the second \r
1576 * and live with it... */
1577 conn->read_ahead = read_ahead;
1580 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1581 if (read_ahead == '\r') {
1582 /* got \r\n\r so far, need one more character... */
1583 conn->read_ahead = READ_AHEAD_CRLFCR;
1585 } else if (read_ahead == '\n') {
1586 /* got \r\n\n, treat it as the end of the headers */
1587 conn->read_ahead = READ_AHEAD_EOH;
1590 /* found the end of a line, keep read_ahead for the next line */
1591 conn->read_ahead = read_ahead;
1594 } else if (c == read_ahead) {
1595 /* got double \r or \n, treat it as the end of the headers */
1596 conn->read_ahead = READ_AHEAD_EOH;
1598 } else if (c == '\r' && read_ahead == '\n') {
1599 /* got \r\n so far, still need more to know what to do... */
1600 conn->read_ahead = READ_AHEAD_CRLF;
1603 /* found the end of a line, keep read_ahead for the next line */
1604 conn->read_ahead = read_ahead;
1609 if (G_LIKELY (*idx < size - 1))
1610 buffer[(*idx)++] = c;
1612 buffer[*idx] = '\0';
1618 set_read_socket_timeout (GstRTSPConnection * conn, gint64 timeout)
1620 GstClockTime to_nsecs;
1623 g_mutex_lock (&conn->socket_use_mutex);
1625 g_assert (!conn->read_socket_used);
1626 conn->read_socket_used = TRUE;
1628 to_nsecs = timeout * 1000;
1629 to_secs = (to_nsecs + GST_SECOND - 1) / GST_SECOND;
1631 if (to_secs > g_socket_get_timeout (conn->read_socket)) {
1632 g_socket_set_timeout (conn->read_socket, to_secs);
1635 g_mutex_unlock (&conn->socket_use_mutex);
1639 set_write_socket_timeout (GstRTSPConnection * conn, gint64 timeout)
1641 GstClockTime to_nsecs;
1644 g_mutex_lock (&conn->socket_use_mutex);
1646 g_assert (!conn->write_socket_used);
1647 conn->write_socket_used = TRUE;
1649 to_nsecs = timeout * 1000;
1650 to_secs = (to_nsecs + GST_SECOND - 1) / GST_SECOND;
1652 if (to_secs > g_socket_get_timeout (conn->write_socket)) {
1653 g_socket_set_timeout (conn->write_socket, to_secs);
1656 g_mutex_unlock (&conn->socket_use_mutex);
1660 clear_read_socket_timeout (GstRTSPConnection * conn)
1662 g_mutex_lock (&conn->socket_use_mutex);
1664 conn->read_socket_used = FALSE;
1665 if (conn->read_socket != conn->write_socket || !conn->write_socket_used) {
1666 g_socket_set_timeout (conn->read_socket, 0);
1669 g_mutex_unlock (&conn->socket_use_mutex);
1673 clear_write_socket_timeout (GstRTSPConnection * conn)
1675 g_mutex_lock (&conn->socket_use_mutex);
1677 conn->write_socket_used = FALSE;
1678 if (conn->write_socket != conn->read_socket || !conn->read_socket_used) {
1679 g_socket_set_timeout (conn->write_socket, 0);
1682 g_mutex_unlock (&conn->socket_use_mutex);
1686 * gst_rtsp_connection_write_usec:
1687 * @conn: a #GstRTSPConnection
1688 * @data: the data to write
1689 * @size: the size of @data
1690 * @timeout: a timeout value or 0
1692 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
1693 * the specified @timeout. @timeout can be 0, in which case this function
1694 * might block forever.
1696 * This function can be cancelled with gst_rtsp_connection_flush().
1698 * Returns: #GST_RTSP_OK on success.
1702 /* FIXME 2.0: This should've been static! */
1704 gst_rtsp_connection_write_usec (GstRTSPConnection * conn, const guint8 * data,
1705 guint size, gint64 timeout)
1710 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1711 g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
1712 g_return_val_if_fail (conn->output_stream != NULL, GST_RTSP_EINVAL);
1716 set_write_socket_timeout (conn, timeout);
1719 write_bytes (conn->output_stream, data, &offset, size, TRUE,
1722 clear_write_socket_timeout (conn);
1728 serialize_message (GstRTSPConnection * conn, GstRTSPMessage * message,
1729 GstRTSPSerializedMessage * serialized_message)
1731 GString *str = NULL;
1733 memset (serialized_message, 0, sizeof (*serialized_message));
1735 /* Initially we borrow the body_data / body_buffer fields from
1737 serialized_message->borrowed = TRUE;
1739 switch (message->type) {
1740 case GST_RTSP_MESSAGE_REQUEST:
1741 str = g_string_new ("");
1743 /* create request string, add CSeq */
1744 g_string_append_printf (str, "%s %s RTSP/%s\r\n"
1746 gst_rtsp_method_as_text (message->type_data.request.method),
1747 message->type_data.request.uri,
1748 gst_rtsp_version_as_text (message->type_data.request.version),
1750 /* add session id if we have one */
1751 if (conn->session_id[0] != '\0') {
1752 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
1753 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
1756 /* add any authentication headers */
1757 add_auth_header (conn, message);
1759 case GST_RTSP_MESSAGE_RESPONSE:
1760 str = g_string_new ("");
1762 /* create response string */
1763 g_string_append_printf (str, "RTSP/%s %d %s\r\n",
1764 gst_rtsp_version_as_text (message->type_data.response.version),
1765 message->type_data.response.code, message->type_data.response.reason);
1767 case GST_RTSP_MESSAGE_HTTP_REQUEST:
1768 str = g_string_new ("");
1770 /* create request string */
1771 g_string_append_printf (str, "%s %s HTTP/%s\r\n",
1772 gst_rtsp_method_as_text (message->type_data.request.method),
1773 message->type_data.request.uri,
1774 gst_rtsp_version_as_text (message->type_data.request.version));
1775 /* add any authentication headers */
1776 add_auth_header (conn, message);
1778 case GST_RTSP_MESSAGE_HTTP_RESPONSE:
1779 str = g_string_new ("");
1781 /* create response string */
1782 g_string_append_printf (str, "HTTP/%s %d %s\r\n",
1783 gst_rtsp_version_as_text (message->type_data.request.version),
1784 message->type_data.response.code, message->type_data.response.reason);
1786 case GST_RTSP_MESSAGE_DATA:
1788 guint8 *data_header = serialized_message->data_header;
1790 /* prepare data header */
1791 data_header[0] = '$';
1792 data_header[1] = message->type_data.data.channel;
1793 data_header[2] = (message->body_size >> 8) & 0xff;
1794 data_header[3] = message->body_size & 0xff;
1796 /* create serialized message with header and data */
1797 serialized_message->data_is_data_header = TRUE;
1798 serialized_message->data_size = 4;
1800 if (message->body) {
1801 serialized_message->body_data = message->body;
1802 serialized_message->body_data_size = message->body_size;
1804 g_assert (message->body_buffer != NULL);
1805 serialized_message->body_buffer = message->body_buffer;
1810 g_string_free (str, TRUE);
1811 g_return_val_if_reached (FALSE);
1815 /* append headers and body */
1816 if (message->type != GST_RTSP_MESSAGE_DATA) {
1817 gchar date_string[100];
1819 g_assert (str != NULL);
1821 gen_date_string (date_string, sizeof (date_string));
1823 /* add date header */
1824 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
1825 gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
1827 /* append headers */
1828 gst_rtsp_message_append_headers (message, str);
1830 /* append Content-Length and body if needed */
1831 if (message->body_size > 0) {
1834 len = g_strdup_printf ("%d", message->body_size);
1835 g_string_append_printf (str, "%s: %s\r\n",
1836 gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
1838 /* header ends here */
1839 g_string_append (str, "\r\n");
1841 if (message->body) {
1842 serialized_message->body_data = message->body;
1843 serialized_message->body_data_size = message->body_size;
1845 g_assert (message->body_buffer != NULL);
1846 serialized_message->body_buffer = message->body_buffer;
1849 /* just end headers */
1850 g_string_append (str, "\r\n");
1853 serialized_message->data_size = str->len;
1854 serialized_message->data = (guint8 *) g_string_free (str, FALSE);
1861 * gst_rtsp_connection_send_usec:
1862 * @conn: a #GstRTSPConnection
1863 * @message: the message to send
1864 * @timeout: a timeout value in microseconds
1866 * Attempt to send @message to the connected @conn, blocking up to
1867 * the specified @timeout. @timeout can be 0, in which case this function
1868 * might block forever.
1870 * This function can be cancelled with gst_rtsp_connection_flush().
1872 * Returns: #GST_RTSP_OK on success.
1877 gst_rtsp_connection_send_usec (GstRTSPConnection * conn,
1878 GstRTSPMessage * message, gint64 timeout)
1880 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1881 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1883 return gst_rtsp_connection_send_messages_usec (conn, message, 1, timeout);
1887 * gst_rtsp_connection_send_messages_usec:
1888 * @conn: a #GstRTSPConnection
1889 * @messages: (array length=n_messages): the messages to send
1890 * @n_messages: the number of messages to send
1891 * @timeout: a timeout value in microseconds
1893 * Attempt to send @messages to the connected @conn, blocking up to
1894 * the specified @timeout. @timeout can be 0, in which case this function
1895 * might block forever.
1897 * This function can be cancelled with gst_rtsp_connection_flush().
1899 * Returns: #GST_RTSP_OK on Since.
1904 gst_rtsp_connection_send_messages_usec (GstRTSPConnection * conn,
1905 GstRTSPMessage * messages, guint n_messages, gint64 timeout)
1908 GstRTSPSerializedMessage *serialized_messages;
1909 GOutputVector *vectors;
1910 GstMapInfo *map_infos;
1911 guint n_vectors, n_memories;
1913 gsize bytes_to_write, bytes_written;
1915 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1916 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
1918 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
1919 memset (serialized_messages, 0,
1920 sizeof (GstRTSPSerializedMessage) * n_messages);
1922 for (i = 0, n_vectors = 0, n_memories = 0, bytes_to_write = 0; i < n_messages;
1924 if (G_UNLIKELY (!serialize_message (conn, &messages[i],
1925 &serialized_messages[i])))
1928 if (conn->tunneled) {
1929 gint state = 0, save = 0;
1930 gchar *base64_buffer, *out_buffer;
1934 in_length = serialized_messages[i].data_size;
1935 if (serialized_messages[i].body_data)
1936 in_length += serialized_messages[i].body_data_size;
1937 else if (serialized_messages[i].body_buffer)
1938 in_length += gst_buffer_get_size (serialized_messages[i].body_buffer);
1940 in_length = (in_length / 3 + 1) * 4 + 4 + 1;
1941 base64_buffer = out_buffer = g_malloc0 (in_length);
1944 g_base64_encode_step (serialized_messages[i].data_is_data_header ?
1945 serialized_messages[i].data_header : serialized_messages[i].data,
1946 serialized_messages[i].data_size, FALSE, out_buffer, &state, &save);
1947 out_buffer += written;
1949 if (serialized_messages[i].body_data) {
1951 g_base64_encode_step (serialized_messages[i].body_data,
1952 serialized_messages[i].body_data_size, FALSE, out_buffer, &state,
1954 out_buffer += written;
1955 } else if (serialized_messages[i].body_buffer) {
1956 guint j, n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
1958 for (j = 0; j < n; j++) {
1960 gst_buffer_peek_memory (serialized_messages[i].body_buffer, j);
1963 gst_memory_map (mem, &map, GST_MAP_READ);
1965 written = g_base64_encode_step (map.data, map.size,
1966 FALSE, out_buffer, &state, &save);
1967 out_buffer += written;
1969 gst_memory_unmap (mem, &map);
1973 written = g_base64_encode_close (FALSE, out_buffer, &state, &save);
1974 out_buffer += written;
1976 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
1977 memset (&serialized_messages[i], 0, sizeof (serialized_messages[i]));
1979 serialized_messages[i].data = (guint8 *) base64_buffer;
1980 serialized_messages[i].data_size = (out_buffer - base64_buffer);
1984 if (serialized_messages[i].body_data) {
1986 } else if (serialized_messages[i].body_buffer) {
1987 n_vectors += gst_buffer_n_memory (serialized_messages[i].body_buffer);
1988 n_memories += gst_buffer_n_memory (serialized_messages[i].body_buffer);
1993 vectors = g_newa (GOutputVector, n_vectors);
1994 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
1996 for (i = 0, j = 0, k = 0; i < n_messages; i++) {
1997 vectors[j].buffer = serialized_messages[i].data_is_data_header ?
1998 serialized_messages[i].data_header : serialized_messages[i].data;
1999 vectors[j].size = serialized_messages[i].data_size;
2000 bytes_to_write += vectors[j].size;
2003 if (serialized_messages[i].body_data) {
2004 vectors[j].buffer = serialized_messages[i].body_data;
2005 vectors[j].size = serialized_messages[i].body_data_size;
2006 bytes_to_write += vectors[j].size;
2008 } else if (serialized_messages[i].body_buffer) {
2011 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
2012 for (l = 0; l < n; l++) {
2014 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
2016 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
2017 vectors[j].buffer = map_infos[k].data;
2018 vectors[j].size = map_infos[k].size;
2019 bytes_to_write += vectors[j].size;
2027 /* write request: this is synchronous */
2028 set_write_socket_timeout (conn, timeout);
2031 writev_bytes (conn->output_stream, vectors, n_vectors, &bytes_written,
2032 TRUE, conn->cancellable);
2034 clear_write_socket_timeout (conn);
2036 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
2038 /* free everything */
2039 for (i = 0, k = 0; i < n_messages; i++) {
2040 if (serialized_messages[i].body_buffer) {
2043 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
2044 for (l = 0; l < n; l++) {
2046 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
2048 gst_memory_unmap (mem, &map_infos[k]);
2053 g_free (serialized_messages[i].data);
2060 for (i = 0; i < n_messages; i++) {
2061 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
2063 g_warning ("Wrong message");
2064 return GST_RTSP_EINVAL;
2068 static GstRTSPResult
2069 parse_string (gchar * dest, gint size, gchar ** src)
2071 GstRTSPResult res = GST_RTSP_OK;
2076 while (g_ascii_isspace (**src))
2079 while (!g_ascii_isspace (**src) && **src != '\0') {
2081 dest[idx++] = **src;
2083 res = GST_RTSP_EPARSE;
2092 static GstRTSPResult
2093 parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
2094 GstRTSPVersion * version)
2096 GstRTSPVersion rversion;
2097 GstRTSPResult res = GST_RTSP_OK;
2100 if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
2107 /* the version number must be formatted as X.Y with nothing following */
2108 if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
2109 res = GST_RTSP_EPARSE;
2111 rversion = major * 0x10 + minor;
2112 if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
2114 if (rversion != GST_RTSP_VERSION_1_0 && rversion != GST_RTSP_VERSION_2_0) {
2115 *version = GST_RTSP_VERSION_INVALID;
2116 res = GST_RTSP_ERROR;
2118 } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
2119 if (*type == GST_RTSP_MESSAGE_REQUEST)
2120 *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
2121 else if (*type == GST_RTSP_MESSAGE_RESPONSE)
2122 *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
2124 if (rversion != GST_RTSP_VERSION_1_0 &&
2125 rversion != GST_RTSP_VERSION_1_1 && rversion != GST_RTSP_VERSION_2_0)
2126 res = GST_RTSP_ERROR;
2128 res = GST_RTSP_EPARSE;
2130 res = GST_RTSP_EPARSE;
2132 if (res == GST_RTSP_OK)
2133 *version = rversion;
2138 static GstRTSPResult
2139 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
2141 GstRTSPResult res = GST_RTSP_OK;
2143 gchar versionstr[20];
2148 bptr = (gchar *) buffer;
2150 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2151 res = GST_RTSP_EPARSE;
2153 if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
2154 res = GST_RTSP_EPARSE;
2155 code = atoi (codestr);
2156 if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
2157 res = GST_RTSP_EPARSE;
2159 while (g_ascii_isspace (*bptr))
2162 if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
2163 NULL) != GST_RTSP_OK))
2164 res = GST_RTSP_EPARSE;
2166 res2 = parse_protocol_version (versionstr, &msg->type,
2167 &msg->type_data.response.version);
2168 if (G_LIKELY (res == GST_RTSP_OK))
2174 static GstRTSPResult
2175 parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
2177 GstRTSPResult res = GST_RTSP_OK;
2179 gchar versionstr[20];
2180 gchar methodstr[20];
2183 GstRTSPMethod method;
2185 bptr = (gchar *) buffer;
2187 if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
2188 res = GST_RTSP_EPARSE;
2189 method = gst_rtsp_find_method (methodstr);
2191 if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
2192 res = GST_RTSP_EPARSE;
2193 if (G_UNLIKELY (*urlstr == '\0'))
2194 res = GST_RTSP_EPARSE;
2196 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2197 res = GST_RTSP_EPARSE;
2199 if (G_UNLIKELY (*bptr != '\0'))
2200 res = GST_RTSP_EPARSE;
2202 if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
2203 urlstr) != GST_RTSP_OK))
2204 res = GST_RTSP_EPARSE;
2206 res2 = parse_protocol_version (versionstr, &msg->type,
2207 &msg->type_data.request.version);
2208 if (G_LIKELY (res == GST_RTSP_OK))
2211 if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
2212 /* GET and POST are not allowed as RTSP methods */
2213 if (msg->type_data.request.method == GST_RTSP_GET ||
2214 msg->type_data.request.method == GST_RTSP_POST) {
2215 msg->type_data.request.method = GST_RTSP_INVALID;
2216 if (res == GST_RTSP_OK)
2217 res = GST_RTSP_ERROR;
2219 } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2220 /* only GET and POST are allowed as HTTP methods */
2221 if (msg->type_data.request.method != GST_RTSP_GET &&
2222 msg->type_data.request.method != GST_RTSP_POST) {
2223 msg->type_data.request.method = GST_RTSP_INVALID;
2224 if (res == GST_RTSP_OK)
2225 res = GST_RTSP_ERROR;
2232 /* parsing lines means reading a Key: Value pair */
2233 static GstRTSPResult
2234 parse_line (guint8 * buffer, GstRTSPMessage * msg)
2236 GstRTSPHeaderField field;
2237 gchar *line = (gchar *) buffer;
2238 gchar *field_name = NULL;
2241 if ((value = strchr (line, ':')) == NULL || value == line)
2244 /* trim space before the colon */
2245 if (value[-1] == ' ')
2248 /* replace the colon with a NUL */
2251 /* find the header */
2252 field = gst_rtsp_find_header_field (line);
2253 /* custom header not present in the list of pre-defined headers */
2254 if (field == GST_RTSP_HDR_INVALID)
2257 /* split up the value in multiple key:value pairs if it contains comma(s) */
2258 while (*value != '\0') {
2260 gchar *comma = NULL;
2261 gboolean quoted = FALSE;
2264 /* trim leading space */
2268 /* for headers which may not appear multiple times, and thus may not
2269 * contain multiple values on the same line, we can short-circuit the loop
2270 * below and the entire value results in just one key:value pair*/
2271 if (!gst_rtsp_header_allow_multiple (field))
2272 next_value = value + strlen (value);
2276 /* find the next value, taking special care of quotes and comments */
2277 while (*next_value != '\0') {
2278 if ((quoted || comment != 0) && *next_value == '\\' &&
2279 next_value[1] != '\0')
2281 else if (comment == 0 && *next_value == '"')
2283 else if (!quoted && *next_value == '(')
2285 else if (comment != 0 && *next_value == ')')
2287 else if (!quoted && comment == 0) {
2288 /* To quote RFC 2068: "User agents MUST take special care in parsing
2289 * the WWW-Authenticate field value if it contains more than one
2290 * challenge, or if more than one WWW-Authenticate header field is
2291 * provided, since the contents of a challenge may itself contain a
2292 * comma-separated list of authentication parameters."
2294 * What this means is that we cannot just look for an unquoted comma
2295 * when looking for multiple values in Proxy-Authenticate and
2296 * WWW-Authenticate headers. Instead we need to look for the sequence
2297 * "comma [space] token space token" before we can split after the
2300 if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
2301 field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
2302 if (*next_value == ',') {
2303 if (next_value[1] == ' ') {
2304 /* skip any space following the comma so we do not mistake it for
2305 * separating between two tokens */
2309 } else if (*next_value == ' ' && next_value[1] != ',' &&
2310 next_value[1] != '=' && comma != NULL) {
2315 } else if (*next_value == ',')
2322 if (msg->type == GST_RTSP_MESSAGE_REQUEST && field == GST_RTSP_HDR_SESSION) {
2323 /* The timeout parameter is only allowed in a session response header
2324 * but some clients send it as part of the session request header.
2325 * Ignore everything from the semicolon to the end of the line. */
2327 while (*next_value != '\0') {
2328 if (*next_value == ';') {
2336 if (value != next_value && next_value[-1] == ' ')
2337 next_value[-1] = '\0';
2339 if (*next_value != '\0')
2340 *next_value++ = '\0';
2342 /* add the key:value pair */
2343 if (*value != '\0') {
2344 if (field != GST_RTSP_HDR_INVALID)
2345 gst_rtsp_message_add_header (msg, field, value);
2347 gst_rtsp_message_add_header_by_name (msg, field_name, value);
2358 return GST_RTSP_EPARSE;
2362 /* convert all consecutive whitespace to a single space */
2364 normalize_line (guint8 * buffer)
2367 if (g_ascii_isspace (*buffer)) {
2371 for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
2374 memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
2382 cseq_validation (GstRTSPConnection * conn, GstRTSPMessage * message)
2388 if (message->type == GST_RTSP_MESSAGE_RESPONSE ||
2389 message->type == GST_RTSP_MESSAGE_REQUEST) {
2390 if ((res = gst_rtsp_message_get_header (message, GST_RTSP_HDR_CSEQ,
2391 &cseq_header, 0)) != GST_RTSP_OK) {
2392 /* rfc2326 This field MUST be present in all RTSP req and resp */
2393 goto invalid_format;
2397 cseq = g_ascii_strtoll (cseq_header, NULL, 10);
2398 if (errno != 0 || cseq < 0) {
2399 /* CSeq has no valid value */
2400 goto invalid_format;
2403 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2404 (conn->cseq == 0 || conn->cseq < cseq)) {
2405 /* Response CSeq can't be higher than the number of outgoing requests
2406 * neither is a response valid if no request has been made */
2407 goto invalid_format;
2414 return GST_RTSP_EPARSE;
2419 * GST_RTSP_OK when a complete message was read.
2420 * GST_RTSP_EEOF: when the read socket is closed
2421 * GST_RTSP_EINTR: when more data is needed.
2422 * GST_RTSP_..: some other error occurred.
2424 static GstRTSPResult
2425 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
2426 GstRTSPConnection * conn, gboolean block)
2431 switch (builder->state) {
2436 builder->offset = 0;
2438 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1,
2440 if (res != GST_RTSP_OK)
2443 c = builder->buffer[0];
2445 /* we have 1 bytes now and we can see if this is a data message or
2448 /* data message, prepare for the header */
2449 builder->state = STATE_DATA_HEADER;
2450 conn->may_cancel = FALSE;
2451 } else if (c == '\n' || c == '\r') {
2452 /* skip \n and \r */
2453 builder->offset = 0;
2456 builder->state = STATE_READ_LINES;
2457 conn->may_cancel = FALSE;
2461 case STATE_DATA_HEADER:
2464 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4,
2466 if (res != GST_RTSP_OK)
2469 gst_rtsp_message_init_data (message, builder->buffer[1]);
2471 builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
2472 builder->body_data = g_malloc (builder->body_len + 1);
2473 builder->body_data[builder->body_len] = '\0';
2474 builder->offset = 0;
2475 builder->state = STATE_DATA_BODY;
2478 case STATE_DATA_BODY:
2481 read_bytes (conn, builder->body_data, &builder->offset,
2482 builder->body_len, block);
2483 if (res != GST_RTSP_OK)
2486 /* we have the complete body now, store in the message adjusting the
2487 * length to include the trailing '\0' */
2488 gst_rtsp_message_take_body (message,
2489 (guint8 *) builder->body_data, builder->body_len + 1);
2490 builder->body_data = NULL;
2491 builder->body_len = 0;
2493 builder->state = STATE_END;
2496 case STATE_READ_LINES:
2498 res = read_line (conn, builder->buffer, &builder->offset,
2499 sizeof (builder->buffer), block);
2500 if (res != GST_RTSP_OK)
2503 /* we have a regular response */
2504 if (builder->buffer[0] == '\0') {
2506 gint64 content_length_parsed = 0;
2508 /* empty line, end of message header */
2509 /* see if there is a Content-Length header, but ignore it if this
2510 * is a POST request with an x-sessioncookie header */
2511 if (gst_rtsp_message_get_header (message,
2512 GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
2513 (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
2514 message->type_data.request.method != GST_RTSP_POST ||
2515 gst_rtsp_message_get_header (message,
2516 GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
2517 /* there is, prepare to read the body */
2519 content_length_parsed = g_ascii_strtoll (hdrval, NULL, 10);
2520 if (errno != 0 || content_length_parsed < 0) {
2521 res = GST_RTSP_EPARSE;
2522 goto invalid_body_len;
2523 } else if (content_length_parsed > conn->content_length_limit) {
2524 res = GST_RTSP_ENOMEM;
2525 goto invalid_body_len;
2527 builder->body_len = content_length_parsed;
2528 builder->body_data = g_try_malloc (builder->body_len + 1);
2529 /* we can't do much here, we need the length to know how many bytes
2530 * we need to read next and when allocation fails, we can't read the payload. */
2531 if (builder->body_data == NULL) {
2532 res = GST_RTSP_ENOMEM;
2533 goto invalid_body_len;
2536 builder->body_data[builder->body_len] = '\0';
2537 builder->offset = 0;
2538 builder->state = STATE_DATA_BODY;
2540 builder->state = STATE_END;
2545 /* we have a line */
2546 normalize_line (builder->buffer);
2547 if (builder->line == 0) {
2548 /* first line, check for response status */
2549 if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
2550 memcmp (builder->buffer, "HTTP", 4) == 0) {
2551 builder->status = parse_response_status (builder->buffer, message);
2553 builder->status = parse_request_line (builder->buffer, message);
2556 /* else just parse the line */
2557 res = parse_line (builder->buffer, message);
2558 if (res != GST_RTSP_OK)
2559 builder->status = res;
2561 if (builder->status != GST_RTSP_OK) {
2562 res = builder->status;
2563 goto invalid_format;
2567 builder->offset = 0;
2572 gchar *session_cookie;
2575 conn->may_cancel = TRUE;
2577 if ((res = cseq_validation (conn, message)) != GST_RTSP_OK) {
2578 /* message don't comply with rfc2326 regarding CSeq */
2579 goto invalid_format;
2582 if (message->type == GST_RTSP_MESSAGE_DATA) {
2583 /* data messages don't have headers */
2588 /* save the tunnel session in the connection */
2589 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
2590 !conn->manual_http &&
2591 conn->tstate == TUNNEL_STATE_NONE &&
2592 gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
2593 &session_cookie, 0) == GST_RTSP_OK) {
2594 strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
2595 conn->tunnelid[TUNNELID_LEN - 1] = '\0';
2596 conn->tunneled = TRUE;
2599 /* save session id in the connection for further use */
2600 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2601 gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
2602 &session_id, 0) == GST_RTSP_OK) {
2605 maxlen = sizeof (conn->session_id) - 1;
2606 /* the sessionid can have attributes marked with ;
2607 * Make sure we strip them */
2608 for (i = 0; i < maxlen && session_id[i] != '\0'; i++) {
2609 if (session_id[i] == ';') {
2614 } while (g_ascii_isspace (session_id[i]));
2615 if (g_str_has_prefix (&session_id[i], "timeout=")) {
2618 /* if we parsed something valid, configure */
2619 if ((to = atoi (&session_id[i + 8])) > 0)
2626 /* make sure to not overflow */
2627 if (conn->remember_session_id) {
2628 strncpy (conn->session_id, session_id, maxlen);
2629 conn->session_id[maxlen] = '\0';
2632 res = builder->status;
2636 res = GST_RTSP_ERROR;
2641 conn->may_cancel = TRUE;
2647 conn->may_cancel = TRUE;
2648 GST_DEBUG ("could not allocate body");
2653 conn->may_cancel = TRUE;
2654 GST_DEBUG ("could not parse");
2660 * gst_rtsp_connection_read_usec:
2661 * @conn: a #GstRTSPConnection
2662 * @data: the data to read
2663 * @size: the size of @data
2664 * @timeout: a timeout value in microseconds
2666 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
2667 * the specified @timeout. @timeout can be 0, in which case this function
2668 * might block forever.
2670 * This function can be cancelled with gst_rtsp_connection_flush().
2672 * Returns: #GST_RTSP_OK on success.
2677 gst_rtsp_connection_read_usec (GstRTSPConnection * conn, guint8 * data,
2678 guint size, gint64 timeout)
2683 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2684 g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
2685 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2687 if (G_UNLIKELY (size == 0))
2692 /* configure timeout if any */
2693 set_read_socket_timeout (conn, timeout);
2695 res = read_bytes (conn, data, &offset, size, TRUE);
2697 clear_read_socket_timeout (conn);
2702 static GstRTSPMessage *
2703 gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
2704 const GstRTSPMessage * request)
2706 GstRTSPMessage *msg;
2709 if (gst_rtsp_status_as_text (code) == NULL)
2710 code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
2712 GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
2715 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
2716 "GStreamer RTSP Server");
2717 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
2718 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
2719 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
2721 if (code == GST_RTSP_STS_OK) {
2722 /* add the local ip address to the tunnel reply, this is where the client
2723 * should send the POST request to */
2725 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
2727 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
2728 "application/x-rtsp-tunnelled");
2741 * gst_rtsp_connection_receive_usec:
2742 * @conn: a #GstRTSPConnection
2743 * @message: the message to read
2744 * @timeout: a timeout value or 0
2746 * Attempt to read into @message from the connected @conn, blocking up to
2747 * the specified @timeout. @timeout can be 0, in which case this function
2748 * might block forever.
2750 * This function can be cancelled with gst_rtsp_connection_flush().
2752 * Returns: #GST_RTSP_OK on success.
2757 gst_rtsp_connection_receive_usec (GstRTSPConnection * conn,
2758 GstRTSPMessage * message, gint64 timeout)
2761 GstRTSPBuilder builder;
2763 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2764 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2765 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2767 /* configure timeout if any */
2768 set_read_socket_timeout (conn, timeout);
2770 memset (&builder, 0, sizeof (GstRTSPBuilder));
2771 res = build_next (&builder, message, conn, TRUE);
2773 clear_read_socket_timeout (conn);
2775 if (G_UNLIKELY (res != GST_RTSP_OK))
2778 if (!conn->manual_http) {
2779 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2780 if (conn->tstate == TUNNEL_STATE_NONE &&
2781 message->type_data.request.method == GST_RTSP_GET) {
2782 GstRTSPMessage *response;
2784 conn->tstate = TUNNEL_STATE_GET;
2786 /* tunnel GET request, we can reply now */
2787 response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
2788 res = gst_rtsp_connection_send_usec (conn, response, timeout);
2789 gst_rtsp_message_free (response);
2790 if (res == GST_RTSP_OK)
2791 res = GST_RTSP_ETGET;
2793 } else if (conn->tstate == TUNNEL_STATE_NONE &&
2794 message->type_data.request.method == GST_RTSP_POST) {
2795 conn->tstate = TUNNEL_STATE_POST;
2797 /* tunnel POST request, the caller now has to link the two
2799 res = GST_RTSP_ETPOST;
2802 res = GST_RTSP_EPARSE;
2805 } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
2806 res = GST_RTSP_EPARSE;
2811 /* we have a message here */
2812 build_reset (&builder);
2820 build_reset (&builder);
2821 gst_rtsp_message_unset (message);
2827 * gst_rtsp_connection_close:
2828 * @conn: a #GstRTSPConnection
2830 * Close the connected @conn. After this call, the connection is in the same
2831 * state as when it was first created.
2833 * Returns: #GST_RTSP_OK on success.
2836 gst_rtsp_connection_close (GstRTSPConnection * conn)
2838 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2840 /* last unref closes the connection we don't want to explicitly close here
2841 * because these sockets might have been provided at construction */
2842 if (conn->stream0) {
2843 g_object_unref (conn->stream0);
2844 conn->stream0 = NULL;
2845 conn->socket0 = NULL;
2847 if (conn->stream1) {
2848 g_object_unref (conn->stream1);
2849 conn->stream1 = NULL;
2850 conn->socket1 = NULL;
2853 /* these were owned by the stream */
2854 conn->input_stream = NULL;
2855 conn->output_stream = NULL;
2856 conn->control_stream = NULL;
2858 g_free (conn->remote_ip);
2859 conn->remote_ip = NULL;
2860 g_free (conn->local_ip);
2861 conn->local_ip = NULL;
2863 conn->read_ahead = 0;
2865 g_free (conn->initial_buffer);
2866 conn->initial_buffer = NULL;
2867 conn->initial_buffer_offset = 0;
2869 conn->write_socket = NULL;
2870 conn->read_socket = NULL;
2871 conn->write_socket_used = FALSE;
2872 conn->read_socket_used = FALSE;
2873 conn->tunneled = FALSE;
2874 conn->tstate = TUNNEL_STATE_NONE;
2876 g_free (conn->username);
2877 conn->username = NULL;
2878 g_free (conn->passwd);
2879 conn->passwd = NULL;
2880 gst_rtsp_connection_clear_auth_params (conn);
2883 conn->session_id[0] = '\0';
2889 * gst_rtsp_connection_free:
2890 * @conn: a #GstRTSPConnection
2892 * Close and free @conn.
2894 * Returns: #GST_RTSP_OK on success.
2897 gst_rtsp_connection_free (GstRTSPConnection * conn)
2901 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2903 res = gst_rtsp_connection_close (conn);
2905 if (conn->cancellable)
2906 g_object_unref (conn->cancellable);
2908 g_object_unref (conn->client);
2909 if (conn->tls_database)
2910 g_object_unref (conn->tls_database);
2911 if (conn->tls_interaction)
2912 g_object_unref (conn->tls_interaction);
2913 if (conn->accept_certificate_destroy_notify)
2915 accept_certificate_destroy_notify (conn->accept_certificate_user_data);
2917 g_timer_destroy (conn->timer);
2918 gst_rtsp_url_free (conn->url);
2919 g_free (conn->proxy_host);
2926 * gst_rtsp_connection_poll_usec:
2927 * @conn: a #GstRTSPConnection
2928 * @events: a bitmask of #GstRTSPEvent flags to check
2929 * @revents: location for result flags
2930 * @timeout: a timeout in microseconds
2932 * Wait up to the specified @timeout for the connection to become available for
2933 * at least one of the operations specified in @events. When the function returns
2934 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
2937 * @timeout can be 0, in which case this function might block forever.
2939 * This function can be cancelled with gst_rtsp_connection_flush().
2941 * Returns: #GST_RTSP_OK on success.
2946 gst_rtsp_connection_poll_usec (GstRTSPConnection * conn, GstRTSPEvent events,
2947 GstRTSPEvent * revents, gint64 timeout)
2950 GSource *rs, *ws, *ts;
2951 GIOCondition condition;
2953 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2954 g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
2955 g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
2956 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2957 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
2959 ctx = g_main_context_new ();
2961 /* configure timeout if any */
2963 ts = g_timeout_source_new (timeout / 1000);
2964 g_source_set_dummy_callback (ts);
2965 g_source_attach (ts, ctx);
2966 g_source_unref (ts);
2969 if (events & GST_RTSP_EV_READ) {
2970 rs = g_socket_create_source (conn->read_socket, G_IO_IN | G_IO_PRI,
2972 g_source_set_dummy_callback (rs);
2973 g_source_attach (rs, ctx);
2974 g_source_unref (rs);
2977 if (events & GST_RTSP_EV_WRITE) {
2978 ws = g_socket_create_source (conn->write_socket, G_IO_OUT,
2980 g_source_set_dummy_callback (ws);
2981 g_source_attach (ws, ctx);
2982 g_source_unref (ws);
2985 /* Returns after handling all pending events */
2986 while (!g_main_context_iteration (ctx, TRUE));
2988 g_main_context_unref (ctx);
2991 if (events & GST_RTSP_EV_READ) {
2992 condition = g_socket_condition_check (conn->read_socket,
2993 G_IO_IN | G_IO_PRI);
2994 if ((condition & G_IO_IN) || (condition & G_IO_PRI))
2995 *revents |= GST_RTSP_EV_READ;
2997 if (events & GST_RTSP_EV_WRITE) {
2998 condition = g_socket_condition_check (conn->write_socket, G_IO_OUT);
2999 if ((condition & G_IO_OUT))
3000 *revents |= GST_RTSP_EV_WRITE;
3004 return GST_RTSP_ETIMEOUT;
3010 * gst_rtsp_connection_next_timeout_usec:
3011 * @conn: a #GstRTSPConnection
3013 * Calculate the next timeout for @conn
3015 * Returns: #the next timeout in microseconds
3020 gst_rtsp_connection_next_timeout_usec (GstRTSPConnection * conn)
3027 g_return_val_if_fail (conn != NULL, 1);
3029 ctimeout = conn->timeout;
3030 if (ctimeout >= 20) {
3031 /* Because we should act before the timeout we timeout 5
3032 * seconds in advance. */
3034 } else if (ctimeout >= 5) {
3035 /* else timeout 20% earlier */
3036 ctimeout -= ctimeout / 5;
3037 } else if (ctimeout >= 1) {
3038 /* else timeout 1 second earlier */
3042 elapsed = g_timer_elapsed (conn->timer, &usec);
3043 if (elapsed >= ctimeout) {
3046 gint64 sec = ctimeout - elapsed;
3047 if (usec <= G_USEC_PER_SEC)
3048 usec = G_USEC_PER_SEC - usec;
3051 timeout = usec + sec * G_USEC_PER_SEC;
3058 * gst_rtsp_connection_reset_timeout:
3059 * @conn: a #GstRTSPConnection
3061 * Reset the timeout of @conn.
3063 * Returns: #GST_RTSP_OK.
3066 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
3068 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3070 g_timer_start (conn->timer);
3076 * gst_rtsp_connection_flush:
3077 * @conn: a #GstRTSPConnection
3078 * @flush: start or stop the flush
3080 * Start or stop the flushing action on @conn. When flushing, all current
3081 * and future actions on @conn will return #GST_RTSP_EINTR until the connection
3082 * is set to non-flushing mode again.
3084 * Returns: #GST_RTSP_OK.
3087 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
3089 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3092 g_cancellable_cancel (conn->cancellable);
3094 g_object_unref (conn->cancellable);
3095 conn->cancellable = g_cancellable_new ();
3102 * gst_rtsp_connection_set_proxy:
3103 * @conn: a #GstRTSPConnection
3104 * @host: the proxy host
3105 * @port: the proxy port
3107 * Set the proxy host and port.
3109 * Returns: #GST_RTSP_OK.
3112 gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
3113 const gchar * host, guint port)
3115 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3117 g_free (conn->proxy_host);
3118 conn->proxy_host = g_strdup (host);
3119 conn->proxy_port = port;
3125 * gst_rtsp_connection_set_auth:
3126 * @conn: a #GstRTSPConnection
3127 * @method: authentication method
3129 * @pass: the password
3131 * Configure @conn for authentication mode @method with @user and @pass as the
3132 * user and password respectively.
3134 * Returns: #GST_RTSP_OK.
3137 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
3138 GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
3140 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3142 if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
3143 || g_strrstr (user, ":") != NULL))
3144 return GST_RTSP_EINVAL;
3146 /* Make sure the username and passwd are being set for authentication */
3147 if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
3148 return GST_RTSP_EINVAL;
3150 /* ":" chars are not allowed in usernames for basic auth */
3151 if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
3152 return GST_RTSP_EINVAL;
3154 g_free (conn->username);
3155 g_free (conn->passwd);
3157 conn->auth_method = method;
3158 conn->username = g_strdup (user);
3159 conn->passwd = g_strdup (pass);
3166 * @key: ASCII string to hash
3168 * Hashes @key in a case-insensitive manner.
3170 * Returns: the hash code.
3173 str_case_hash (gconstpointer key)
3175 const char *p = key;
3176 guint h = g_ascii_toupper (*p);
3179 for (p += 1; *p != '\0'; p++)
3180 h = (h << 5) - h + g_ascii_toupper (*p);
3187 * @v1: an ASCII string
3188 * @v2: another ASCII string
3190 * Compares @v1 and @v2 in a case-insensitive manner
3192 * Returns: %TRUE if they are equal (modulo case)
3195 str_case_equal (gconstpointer v1, gconstpointer v2)
3197 const char *string1 = v1;
3198 const char *string2 = v2;
3200 return g_ascii_strcasecmp (string1, string2) == 0;
3204 * gst_rtsp_connection_set_auth_param:
3205 * @conn: a #GstRTSPConnection
3206 * @param: authentication directive
3209 * Setup @conn with authentication directives. This is not necessary for
3210 * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
3211 * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
3212 * in the WWW-Authenticate response header and can include realm, domain,
3213 * nonce, opaque, stale, algorithm, qop as per RFC2617.
3216 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
3217 const gchar * param, const gchar * value)
3219 g_return_if_fail (conn != NULL);
3220 g_return_if_fail (param != NULL);
3222 if (conn->auth_params == NULL) {
3224 g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
3226 g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
3230 * gst_rtsp_connection_clear_auth_params:
3231 * @conn: a #GstRTSPConnection
3233 * Clear the list of authentication directives stored in @conn.
3236 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
3238 g_return_if_fail (conn != NULL);
3240 if (conn->auth_params != NULL) {
3241 g_hash_table_destroy (conn->auth_params);
3242 conn->auth_params = NULL;
3246 static GstRTSPResult
3247 set_qos_dscp (GSocket * socket, guint qos_dscp)
3250 GST_FIXME ("IP_TOS socket option is not defined, not setting dscp");
3254 union gst_sockaddr sa;
3255 socklen_t slen = sizeof (sa);
3262 fd = g_socket_get_fd (socket);
3263 if (getsockname (fd, &sa.sa, &slen) < 0)
3264 goto no_getsockname;
3266 af = sa.sa.sa_family;
3268 /* if this is an IPv4-mapped address then do IPv4 QoS */
3269 if (af == AF_INET6) {
3270 if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
3274 /* extract and shift 6 bits of the DSCP */
3275 tos = (qos_dscp & 0x3f) << 2;
3278 # define SETSOCKOPT_ARG4_TYPE const char *
3280 # define SETSOCKOPT_ARG4_TYPE const void *
3285 if (setsockopt (fd, IPPROTO_IP, IP_TOS, (SETSOCKOPT_ARG4_TYPE) & tos,
3291 if (setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS,
3292 (SETSOCKOPT_ARG4_TYPE) & tos, sizeof (tos)) < 0)
3306 return GST_RTSP_ESYS;
3310 return GST_RTSP_ERROR;
3316 * gst_rtsp_connection_set_qos_dscp:
3317 * @conn: a #GstRTSPConnection
3318 * @qos_dscp: DSCP value
3320 * Configure @conn to use the specified DSCP value.
3322 * Returns: #GST_RTSP_OK on success.
3325 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
3329 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3330 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
3331 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
3333 res = set_qos_dscp (conn->socket0, qos_dscp);
3334 if (res == GST_RTSP_OK)
3335 res = set_qos_dscp (conn->socket1, qos_dscp);
3341 * gst_rtsp_connection_set_content_length_limit:
3342 * @conn: a #GstRTSPConnection
3343 * @limit: Content-Length limit
3345 * Configure @conn to use the specified Content-Length limit.
3346 * Both requests and responses are validated. If content-length is
3347 * exceeded, ENOMEM error will be returned.
3352 gst_rtsp_connection_set_content_length_limit (GstRTSPConnection * conn,
3355 g_return_if_fail (conn != NULL);
3357 conn->content_length_limit = limit;
3361 * gst_rtsp_connection_get_url:
3362 * @conn: a #GstRTSPConnection
3364 * Retrieve the URL of the other end of @conn.
3366 * Returns: The URL. This value remains valid until the
3367 * connection is freed.
3370 gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
3372 g_return_val_if_fail (conn != NULL, NULL);
3378 * gst_rtsp_connection_get_ip:
3379 * @conn: a #GstRTSPConnection
3381 * Retrieve the IP address of the other end of @conn.
3383 * Returns: The IP address as a string. this value remains valid until the
3384 * connection is closed.
3387 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
3389 g_return_val_if_fail (conn != NULL, NULL);
3391 return conn->remote_ip;
3395 * gst_rtsp_connection_set_ip:
3396 * @conn: a #GstRTSPConnection
3397 * @ip: an ip address
3399 * Set the IP address of the server.
3402 gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
3404 g_return_if_fail (conn != NULL);
3406 g_free (conn->remote_ip);
3407 conn->remote_ip = g_strdup (ip);
3411 * gst_rtsp_connection_get_read_socket:
3412 * @conn: a #GstRTSPConnection
3414 * Get the file descriptor for reading.
3416 * Returns: (transfer none): the file descriptor used for reading or %NULL on
3417 * error. The file descriptor remains valid until the connection is closed.
3420 gst_rtsp_connection_get_read_socket (const GstRTSPConnection * conn)
3422 g_return_val_if_fail (conn != NULL, NULL);
3423 g_return_val_if_fail (conn->read_socket != NULL, NULL);
3425 return conn->read_socket;
3429 * gst_rtsp_connection_get_write_socket:
3430 * @conn: a #GstRTSPConnection
3432 * Get the file descriptor for writing.
3434 * Returns: (transfer none): the file descriptor used for writing or NULL on
3435 * error. The file descriptor remains valid until the connection is closed.
3438 gst_rtsp_connection_get_write_socket (const GstRTSPConnection * conn)
3440 g_return_val_if_fail (conn != NULL, NULL);
3441 g_return_val_if_fail (conn->write_socket != NULL, NULL);
3443 return conn->write_socket;
3447 * gst_rtsp_connection_set_http_mode:
3448 * @conn: a #GstRTSPConnection
3449 * @enable: %TRUE to enable manual HTTP mode
3451 * By setting the HTTP mode to %TRUE the message parsing will support HTTP
3452 * messages in addition to the RTSP messages. It will also disable the
3453 * automatic handling of setting up an HTTP tunnel.
3456 gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
3458 g_return_if_fail (conn != NULL);
3460 conn->manual_http = enable;
3464 * gst_rtsp_connection_set_tunneled:
3465 * @conn: a #GstRTSPConnection
3466 * @tunneled: the new state
3468 * Set the HTTP tunneling state of the connection. This must be configured before
3469 * the @conn is connected.
3472 gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
3474 g_return_if_fail (conn != NULL);
3475 g_return_if_fail (conn->read_socket == NULL);
3476 g_return_if_fail (conn->write_socket == NULL);
3478 conn->tunneled = tunneled;
3482 * gst_rtsp_connection_is_tunneled:
3483 * @conn: a #GstRTSPConnection
3485 * Get the tunneling state of the connection.
3487 * Returns: if @conn is using HTTP tunneling.
3490 gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
3492 g_return_val_if_fail (conn != NULL, FALSE);
3494 return conn->tunneled;
3498 * gst_rtsp_connection_get_tunnelid:
3499 * @conn: a #GstRTSPConnection
3501 * Get the tunnel session id the connection.
3503 * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
3506 gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
3508 g_return_val_if_fail (conn != NULL, NULL);
3510 if (!conn->tunneled)
3513 return conn->tunnelid;
3517 * gst_rtsp_connection_set_ignore_x_server_reply:
3518 * @conn: a #GstRTSPConnection
3519 * @ignore: %TRUE to ignore the x-server-ip-address header reply or %FALSE to
3520 * comply with it (%FALSE is the default).
3522 * Set whether to ignore the x-server-ip-address header reply or not. If the
3523 * header is ignored, the original address will be used instead.
3528 gst_rtsp_connection_set_ignore_x_server_reply (GstRTSPConnection * conn,
3531 g_return_if_fail (conn != NULL);
3533 conn->ignore_x_server_reply = ignore;
3537 * gst_rtsp_connection_get_ignore_x_server_reply:
3538 * @conn: a #GstRTSPConnection
3540 * Get the ignore_x_server_reply value.
3542 * Returns: returns %TRUE if the x-server-ip-address header reply will be
3543 * ignored, else returns %FALSE
3548 gst_rtsp_connection_get_ignore_x_server_reply (const GstRTSPConnection * conn)
3550 g_return_val_if_fail (conn != NULL, FALSE);
3552 return conn->ignore_x_server_reply;
3556 * gst_rtsp_connection_do_tunnel:
3557 * @conn: a #GstRTSPConnection
3558 * @conn2: a #GstRTSPConnection or %NULL
3560 * If @conn received the first tunnel connection and @conn2 received
3561 * the second tunnel connection, link the two connections together so that
3562 * @conn manages the tunneled connection.
3564 * After this call, @conn2 cannot be used anymore and must be freed with
3565 * gst_rtsp_connection_free().
3567 * If @conn2 is %NULL then only the base64 decoding context will be setup for
3570 * Returns: return GST_RTSP_OK on success.
3573 gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
3574 GstRTSPConnection * conn2)
3576 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3578 if (conn2 != NULL) {
3579 GstRTSPTunnelState ts1 = conn->tstate;
3580 GstRTSPTunnelState ts2 = conn2->tstate;
3582 g_return_val_if_fail ((ts1 == TUNNEL_STATE_GET && ts2 == TUNNEL_STATE_POST)
3583 || (ts1 == TUNNEL_STATE_POST && ts2 == TUNNEL_STATE_GET),
3585 g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
3586 TUNNELID_LEN), GST_RTSP_EINVAL);
3588 /* both connections have socket0 as the read/write socket */
3589 if (ts1 == TUNNEL_STATE_GET) {
3590 /* conn2 is the HTTP POST channel. take its socket and set it as read
3592 conn->socket1 = conn2->socket0;
3593 conn->stream1 = conn2->stream0;
3594 conn->input_stream = conn2->input_stream;
3595 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3596 conn2->output_stream = NULL;
3598 /* conn2 is the HTTP GET channel. take its socket and set it as write
3600 conn->socket1 = conn->socket0;
3601 conn->stream1 = conn->stream0;
3602 conn->socket0 = conn2->socket0;
3603 conn->stream0 = conn2->stream0;
3604 conn->output_stream = conn2->output_stream;
3605 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3608 /* clean up some of the state of conn2 */
3609 g_cancellable_cancel (conn2->cancellable);
3610 conn2->write_socket = conn2->read_socket = NULL;
3611 conn2->socket0 = NULL;
3612 conn2->stream0 = NULL;
3613 conn2->socket1 = NULL;
3614 conn2->stream1 = NULL;
3615 conn2->input_stream = NULL;
3616 conn2->control_stream = NULL;
3617 g_object_unref (conn2->cancellable);
3618 conn2->cancellable = NULL;
3620 /* We make socket0 the write socket and socket1 the read socket. */
3621 conn->write_socket = conn->socket0;
3622 conn->read_socket = conn->socket1;
3624 conn->tstate = TUNNEL_STATE_COMPLETE;
3626 g_free (conn->initial_buffer);
3627 conn->initial_buffer = conn2->initial_buffer;
3628 conn2->initial_buffer = NULL;
3629 conn->initial_buffer_offset = conn2->initial_buffer_offset;
3632 /* we need base64 decoding for the readfd */
3633 conn->ctx.state = 0;
3636 conn->ctx.coutl = 0;
3637 conn->ctxp = &conn->ctx;
3643 * gst_rtsp_connection_set_remember_session_id:
3644 * @conn: a #GstRTSPConnection
3645 * @remember: %TRUE if the connection should remember the session id
3647 * Sets if the #GstRTSPConnection should remember the session id from the last
3648 * response received and force it onto any further requests.
3650 * The default value is %TRUE
3654 gst_rtsp_connection_set_remember_session_id (GstRTSPConnection * conn,
3657 conn->remember_session_id = remember;
3659 conn->session_id[0] = '\0';
3663 * gst_rtsp_connection_get_remember_session_id:
3664 * @conn: a #GstRTSPConnection
3666 * Returns: %TRUE if the #GstRTSPConnection remembers the session id in the
3667 * last response to set it on any further request.
3671 gst_rtsp_connection_get_remember_session_id (GstRTSPConnection * conn)
3673 return conn->remember_session_id;
3677 #define READ_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3678 #define READ_COND (G_IO_IN | READ_ERR)
3679 #define WRITE_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3680 #define WRITE_COND (G_IO_OUT | WRITE_ERR)
3682 /* async functions */
3683 struct _GstRTSPWatch
3687 GstRTSPConnection *conn;
3689 GstRTSPBuilder builder;
3690 GstRTSPMessage message;
3694 GSource *controlsrc;
3696 gboolean keep_running;
3698 /* queued message for transmission */
3701 GstQueueArray *messages;
3702 gsize messages_bytes;
3703 guint messages_count;
3707 GCond queue_not_full;
3710 GstRTSPWatchFuncs funcs;
3713 GDestroyNotify notify;
3716 #define IS_BACKLOG_FULL(w) (((w)->max_bytes != 0 && (w)->messages_bytes >= (w)->max_bytes) || \
3717 ((w)->max_messages != 0 && (w)->messages_count >= (w)->max_messages))
3720 gst_rtsp_source_prepare (GSource * source, gint * timeout)
3722 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3724 if (watch->conn->initial_buffer != NULL)
3727 *timeout = (watch->conn->timeout * 1000);
3733 gst_rtsp_source_check (GSource * source)
3739 gst_rtsp_source_dispatch_read_get_channel (GPollableInputStream * stream,
3740 GstRTSPWatch * watch)
3743 guint8 buffer[1024];
3744 GError *error = NULL;
3746 /* try to read in order to be able to detect errors, we read 1k in case some
3747 * client actually decides to send data on the GET channel */
3748 count = g_pollable_input_stream_read_nonblocking (stream, buffer, 1024, NULL,
3751 /* other end closed the socket */
3756 GST_DEBUG ("%s", error->message);
3757 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
3758 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
3759 g_clear_error (&error);
3762 g_clear_error (&error);
3766 /* client sent data on the GET channel, ignore it */
3774 if (watch->funcs.closed)
3775 watch->funcs.closed (watch, watch->user_data);
3777 /* the read connection was closed, stop the watch now */
3778 watch->keep_running = FALSE;
3784 if (watch->funcs.error_full)
3785 watch->funcs.error_full (watch, GST_RTSP_ESYS, &watch->message,
3786 0, watch->user_data);
3787 else if (watch->funcs.error)
3788 watch->funcs.error (watch, GST_RTSP_ESYS, watch->user_data);
3795 gst_rtsp_source_dispatch_read (GPollableInputStream * stream,
3796 GstRTSPWatch * watch)
3798 GstRTSPResult res = GST_RTSP_ERROR;
3799 GstRTSPConnection *conn = watch->conn;
3801 /* if this connection was already closed, stop now */
3802 if (G_POLLABLE_INPUT_STREAM (conn->input_stream) != stream)
3805 res = build_next (&watch->builder, &watch->message, conn, FALSE);
3806 if (res == GST_RTSP_EINTR)
3808 else if (G_UNLIKELY (res == GST_RTSP_EEOF)) {
3809 g_mutex_lock (&watch->mutex);
3810 if (watch->readsrc) {
3811 if (!g_source_is_destroyed ((GSource *) watch))
3812 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
3813 g_source_unref (watch->readsrc);
3814 watch->readsrc = NULL;
3817 if (conn->stream1) {
3818 g_object_unref (conn->stream1);
3819 conn->stream1 = NULL;
3820 conn->socket1 = NULL;
3821 conn->input_stream = NULL;
3823 g_mutex_unlock (&watch->mutex);
3825 /* When we are in tunnelled mode, the read socket can be closed and we
3826 * should be prepared for a new POST method to reopen it */
3827 if (conn->tstate == TUNNEL_STATE_COMPLETE) {
3828 /* remove the read connection for the tunnel */
3829 /* we accept a new POST request */
3830 conn->tstate = TUNNEL_STATE_GET;
3831 /* and signal that we lost our tunnel */
3832 if (watch->funcs.tunnel_lost)
3833 res = watch->funcs.tunnel_lost (watch, watch->user_data);
3834 /* we add read source on the write socket able to detect when client closes get channel in tunneled mode */
3835 g_mutex_lock (&watch->mutex);
3836 if (watch->conn->control_stream && !watch->controlsrc) {
3838 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
3839 (watch->conn->control_stream), NULL);
3840 g_source_set_callback (watch->controlsrc,
3841 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
3843 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
3845 g_mutex_unlock (&watch->mutex);
3849 } else if (G_LIKELY (res == GST_RTSP_OK)) {
3850 if (!conn->manual_http &&
3851 watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3852 if (conn->tstate == TUNNEL_STATE_NONE &&
3853 watch->message.type_data.request.method == GST_RTSP_GET) {
3854 GstRTSPMessage *response;
3855 GstRTSPStatusCode code;
3857 conn->tstate = TUNNEL_STATE_GET;
3859 if (watch->funcs.tunnel_start)
3860 code = watch->funcs.tunnel_start (watch, watch->user_data);
3862 code = GST_RTSP_STS_OK;
3864 /* queue the response */
3865 response = gen_tunnel_reply (conn, code, &watch->message);
3866 if (watch->funcs.tunnel_http_response)
3867 watch->funcs.tunnel_http_response (watch, &watch->message, response,
3869 gst_rtsp_watch_send_message (watch, response, NULL);
3870 gst_rtsp_message_free (response);
3872 } else if (conn->tstate == TUNNEL_STATE_NONE &&
3873 watch->message.type_data.request.method == GST_RTSP_POST) {
3874 conn->tstate = TUNNEL_STATE_POST;
3876 /* in the callback the connection should be tunneled with the
3878 if (watch->funcs.tunnel_complete) {
3879 watch->funcs.tunnel_complete (watch, watch->user_data);
3887 if (!conn->manual_http) {
3888 /* if manual HTTP support is not enabled, then restore the message to
3889 * what it would have looked like without the support for parsing HTTP
3890 * messages being present */
3891 if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3892 watch->message.type = GST_RTSP_MESSAGE_REQUEST;
3893 watch->message.type_data.request.method = GST_RTSP_INVALID;
3894 if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
3895 watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
3896 res = GST_RTSP_EPARSE;
3897 } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
3898 watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
3899 if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
3900 watch->message.type_data.response.version = GST_RTSP_VERSION_INVALID;
3901 res = GST_RTSP_EPARSE;
3904 if (G_LIKELY (res != GST_RTSP_OK))
3907 if (watch->funcs.message_received)
3908 watch->funcs.message_received (watch, &watch->message, watch->user_data);
3911 gst_rtsp_message_unset (&watch->message);
3912 build_reset (&watch->builder);
3920 if (watch->funcs.closed)
3921 watch->funcs.closed (watch, watch->user_data);
3923 /* we closed the read connection, stop the watch now */
3924 watch->keep_running = FALSE;
3926 /* always stop when the input returns EOF in non-tunneled mode */
3931 if (watch->funcs.error_full)
3932 watch->funcs.error_full (watch, res, &watch->message,
3933 0, watch->user_data);
3934 else if (watch->funcs.error)
3935 watch->funcs.error (watch, res, watch->user_data);
3942 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
3943 gpointer user_data G_GNUC_UNUSED)
3945 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3946 GstRTSPConnection *conn = watch->conn;
3948 if (conn->initial_buffer != NULL) {
3949 gst_rtsp_source_dispatch_read (G_POLLABLE_INPUT_STREAM (conn->input_stream),
3952 return watch->keep_running;
3956 gst_rtsp_source_dispatch_write (GPollableOutputStream * stream,
3957 GstRTSPWatch * watch)
3959 GstRTSPResult res = GST_RTSP_ERROR;
3960 GstRTSPConnection *conn = watch->conn;
3962 /* if this connection was already closed, stop now */
3963 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
3967 g_mutex_lock (&watch->mutex);
3969 guint n_messages = gst_queue_array_get_length (watch->messages);
3970 GOutputVector *vectors;
3971 GstMapInfo *map_infos;
3973 gsize bytes_to_write, bytes_written;
3974 guint n_vectors, n_memories, n_ids, drop_messages;
3975 gint i, j, l, n_mmap;
3976 GstRTSPSerializedMessage *msg;
3978 /* if this connection was already closed, stop now */
3979 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
3981 g_mutex_unlock (&watch->mutex);
3985 if (n_messages == 0) {
3986 if (watch->writesrc) {
3987 if (!g_source_is_destroyed ((GSource *) watch))
3988 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
3989 g_source_unref (watch->writesrc);
3990 watch->writesrc = NULL;
3991 /* we create and add the write source again when we actually have
3992 * something to write */
3994 /* since write source is now removed we add read source on the write
3995 * socket instead to be able to detect when client closes get channel
3996 * in tunneled mode */
3997 if (watch->conn->control_stream) {
3999 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4000 (watch->conn->control_stream), NULL);
4001 g_source_set_callback (watch->controlsrc,
4002 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
4004 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
4006 watch->controlsrc = NULL;
4012 for (i = 0, n_vectors = 0, n_memories = 0, n_ids = 0; i < n_messages; i++) {
4013 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4017 if (msg->data_offset < msg->data_size)
4020 if (msg->body_data && msg->body_offset < msg->body_data_size) {
4022 } else if (msg->body_buffer) {
4026 n = gst_buffer_n_memory (msg->body_buffer);
4027 for (m = 0; m < n; m++) {
4028 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
4030 /* Skip all memories we already wrote */
4031 if (offset + mem->size <= msg->body_offset) {
4032 offset += mem->size;
4035 offset += mem->size;
4043 vectors = g_newa (GOutputVector, n_vectors);
4044 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
4045 ids = n_ids ? g_newa (guint, n_ids + 1) : NULL;
4047 memset (ids, 0, sizeof (guint) * (n_ids + 1));
4049 for (i = 0, j = 0, n_mmap = 0, l = 0, bytes_to_write = 0; i < n_messages;
4051 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4053 if (msg->data_offset < msg->data_size) {
4054 vectors[j].buffer = (msg->data_is_data_header ?
4055 msg->data_header : msg->data) + msg->data_offset;
4056 vectors[j].size = msg->data_size - msg->data_offset;
4057 bytes_to_write += vectors[j].size;
4061 if (msg->body_data) {
4062 if (msg->body_offset < msg->body_data_size) {
4063 vectors[j].buffer = msg->body_data + msg->body_offset;
4064 vectors[j].size = msg->body_data_size - msg->body_offset;
4065 bytes_to_write += vectors[j].size;
4068 } else if (msg->body_buffer) {
4071 n = gst_buffer_n_memory (msg->body_buffer);
4072 for (m = 0; m < n; m++) {
4073 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
4076 /* Skip all memories we already wrote */
4077 if (offset + mem->size <= msg->body_offset) {
4078 offset += mem->size;
4082 if (offset < msg->body_offset)
4083 off = msg->body_offset - offset;
4087 offset += mem->size;
4089 g_assert (off < mem->size);
4091 gst_memory_map (mem, &map_infos[n_mmap], GST_MAP_READ);
4092 vectors[j].buffer = map_infos[n_mmap].data + off;
4093 vectors[j].size = map_infos[n_mmap].size - off;
4094 bytes_to_write += vectors[j].size;
4103 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4104 &bytes_written, FALSE, watch->conn->cancellable);
4105 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4107 /* First unmap all memories here, this simplifies the code below
4108 * as we don't have to skip all memories that were already written
4110 for (i = 0; i < n_mmap; i++) {
4111 gst_memory_unmap (map_infos[i].memory, &map_infos[i]);
4114 if (bytes_written == bytes_to_write) {
4115 /* fast path, just unmap all memories, free memory, drop all messages and notify them */
4117 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4123 gst_rtsp_serialized_message_clear (msg);
4126 g_assert (watch->messages_bytes >= bytes_written);
4127 watch->messages_bytes -= bytes_written;
4128 } else if (bytes_written > 0) {
4129 /* not done, let's skip all messages that were sent already and free them */
4130 for (i = 0, drop_messages = 0; i < n_messages; i++) {
4131 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4133 if (bytes_written >= msg->data_size - msg->data_offset) {
4136 /* all data of this message is sent, check body and otherwise
4137 * skip the whole message for next time */
4138 bytes_written -= (msg->data_size - msg->data_offset);
4139 watch->messages_bytes -= (msg->data_size - msg->data_offset);
4140 msg->data_offset = msg->data_size;
4142 if (msg->body_data) {
4143 body_size = msg->body_data_size;
4144 } else if (msg->body_buffer) {
4145 body_size = gst_buffer_get_size (msg->body_buffer);
4150 if (bytes_written + msg->body_offset >= body_size) {
4151 /* body written, drop this message */
4152 bytes_written -= body_size - msg->body_offset;
4153 watch->messages_bytes -= body_size - msg->body_offset;
4154 msg->body_offset = body_size;
4162 gst_rtsp_serialized_message_clear (msg);
4164 msg->body_offset += bytes_written;
4165 watch->messages_bytes -= bytes_written;
4169 /* Need to continue sending from the data of this message */
4170 msg->data_offset += bytes_written;
4171 watch->messages_bytes -= bytes_written;
4176 while (drop_messages > 0) {
4177 msg = gst_queue_array_pop_head_struct (watch->messages);
4182 g_assert (watch->messages_bytes >= bytes_written);
4183 watch->messages_bytes -= bytes_written;
4186 if (!IS_BACKLOG_FULL (watch))
4187 g_cond_signal (&watch->queue_not_full);
4188 g_mutex_unlock (&watch->mutex);
4190 /* notify all messages that were successfully written */
4193 /* only decrease the counter for messages that have an id. Only
4194 * the last message of a messages chunk is counted */
4195 watch->messages_count--;
4197 if (watch->funcs.message_sent)
4198 watch->funcs.message_sent (watch, *ids, watch->user_data);
4203 if (res == GST_RTSP_EINTR) {
4205 } else if (G_UNLIKELY (res != GST_RTSP_OK)) {
4208 g_mutex_lock (&watch->mutex);
4210 g_mutex_unlock (&watch->mutex);
4222 if (watch->funcs.error_full) {
4223 guint i, n_messages;
4225 n_messages = gst_queue_array_get_length (watch->messages);
4226 for (i = 0; i < n_messages; i++) {
4227 GstRTSPSerializedMessage *msg =
4228 gst_queue_array_peek_nth_struct (watch->messages, i);
4230 watch->funcs.error_full (watch, res, NULL, msg->id, watch->user_data);
4232 } else if (watch->funcs.error) {
4233 watch->funcs.error (watch, res, watch->user_data);
4241 gst_rtsp_source_finalize (GSource * source)
4243 GstRTSPWatch *watch = (GstRTSPWatch *) source;
4244 GstRTSPSerializedMessage *msg;
4247 watch->notify (watch->user_data);
4249 build_reset (&watch->builder);
4250 gst_rtsp_message_unset (&watch->message);
4252 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4253 gst_rtsp_serialized_message_clear (msg);
4255 gst_queue_array_free (watch->messages);
4256 watch->messages = NULL;
4257 watch->messages_bytes = 0;
4258 watch->messages_count = 0;
4260 g_cond_clear (&watch->queue_not_full);
4263 g_source_unref (watch->readsrc);
4264 if (watch->writesrc)
4265 g_source_unref (watch->writesrc);
4266 if (watch->controlsrc)
4267 g_source_unref (watch->controlsrc);
4269 g_mutex_clear (&watch->mutex);
4272 static GSourceFuncs gst_rtsp_source_funcs = {
4273 gst_rtsp_source_prepare,
4274 gst_rtsp_source_check,
4275 gst_rtsp_source_dispatch,
4276 gst_rtsp_source_finalize,
4282 * gst_rtsp_watch_new: (skip)
4283 * @conn: a #GstRTSPConnection
4284 * @funcs: watch functions
4285 * @user_data: user data to pass to @funcs
4286 * @notify: notify when @user_data is not referenced anymore
4288 * Create a watch object for @conn. The functions provided in @funcs will be
4289 * called with @user_data when activity happened on the watch.
4291 * The new watch is usually created so that it can be attached to a
4292 * maincontext with gst_rtsp_watch_attach().
4294 * @conn must exist for the entire lifetime of the watch.
4296 * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
4297 * communication. Free with gst_rtsp_watch_unref () after usage.
4300 gst_rtsp_watch_new (GstRTSPConnection * conn,
4301 GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
4303 GstRTSPWatch *result;
4305 g_return_val_if_fail (conn != NULL, NULL);
4306 g_return_val_if_fail (funcs != NULL, NULL);
4307 g_return_val_if_fail (conn->read_socket != NULL, NULL);
4308 g_return_val_if_fail (conn->write_socket != NULL, NULL);
4310 result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
4311 sizeof (GstRTSPWatch));
4313 result->conn = conn;
4314 result->builder.state = STATE_START;
4316 g_mutex_init (&result->mutex);
4318 gst_queue_array_new_for_struct (sizeof (GstRTSPSerializedMessage), 10);
4319 g_cond_init (&result->queue_not_full);
4321 gst_rtsp_watch_reset (result);
4322 result->keep_running = TRUE;
4323 result->flushing = FALSE;
4325 result->funcs = *funcs;
4326 result->user_data = user_data;
4327 result->notify = notify;
4333 * gst_rtsp_watch_reset:
4334 * @watch: a #GstRTSPWatch
4336 * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
4337 * when the file descriptors of the connection might have changed.
4340 gst_rtsp_watch_reset (GstRTSPWatch * watch)
4342 g_mutex_lock (&watch->mutex);
4343 if (watch->readsrc) {
4344 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
4345 g_source_unref (watch->readsrc);
4347 if (watch->writesrc) {
4348 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
4349 g_source_unref (watch->writesrc);
4350 watch->writesrc = NULL;
4352 if (watch->controlsrc) {
4353 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4354 g_source_unref (watch->controlsrc);
4355 watch->controlsrc = NULL;
4358 if (watch->conn->input_stream) {
4360 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4361 (watch->conn->input_stream), NULL);
4362 g_source_set_callback (watch->readsrc,
4363 (GSourceFunc) gst_rtsp_source_dispatch_read, watch, NULL);
4364 g_source_add_child_source ((GSource *) watch, watch->readsrc);
4366 watch->readsrc = NULL;
4369 /* we create and add the write source when we actually have something to
4372 /* when write source is not added we add read source on the write socket
4373 * instead to be able to detect when client closes get channel in tunneled
4375 if (watch->conn->control_stream) {
4377 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4378 (watch->conn->control_stream), NULL);
4379 g_source_set_callback (watch->controlsrc,
4380 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch, NULL);
4381 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
4383 watch->controlsrc = NULL;
4385 g_mutex_unlock (&watch->mutex);
4389 * gst_rtsp_watch_attach:
4390 * @watch: a #GstRTSPWatch
4391 * @context: a GMainContext (if NULL, the default context will be used)
4393 * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
4395 * Returns: the ID (greater than 0) for the watch within the GMainContext.
4398 gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
4400 g_return_val_if_fail (watch != NULL, 0);
4402 return g_source_attach ((GSource *) watch, context);
4406 * gst_rtsp_watch_unref:
4407 * @watch: a #GstRTSPWatch
4409 * Decreases the reference count of @watch by one. If the resulting reference
4410 * count is zero the watch and associated memory will be destroyed.
4413 gst_rtsp_watch_unref (GstRTSPWatch * watch)
4415 g_return_if_fail (watch != NULL);
4417 g_source_unref ((GSource *) watch);
4421 * gst_rtsp_watch_set_send_backlog:
4422 * @watch: a #GstRTSPWatch
4423 * @bytes: maximum bytes
4424 * @messages: maximum messages
4426 * Set the maximum amount of bytes and messages that will be queued in @watch.
4427 * When the maximum amounts are exceeded, gst_rtsp_watch_write_data() and
4428 * gst_rtsp_watch_send_message() will return #GST_RTSP_ENOMEM.
4430 * A value of 0 for @bytes or @messages means no limits.
4435 gst_rtsp_watch_set_send_backlog (GstRTSPWatch * watch,
4436 gsize bytes, guint messages)
4438 g_return_if_fail (watch != NULL);
4440 g_mutex_lock (&watch->mutex);
4441 watch->max_bytes = bytes;
4442 watch->max_messages = messages;
4443 if (!IS_BACKLOG_FULL (watch))
4444 g_cond_signal (&watch->queue_not_full);
4445 g_mutex_unlock (&watch->mutex);
4447 GST_DEBUG ("set backlog to bytes %" G_GSIZE_FORMAT ", messages %u",
4452 * gst_rtsp_watch_get_send_backlog:
4453 * @watch: a #GstRTSPWatch
4454 * @bytes: (out) (allow-none): maximum bytes
4455 * @messages: (out) (allow-none): maximum messages
4457 * Get the maximum amount of bytes and messages that will be queued in @watch.
4458 * See gst_rtsp_watch_set_send_backlog().
4463 gst_rtsp_watch_get_send_backlog (GstRTSPWatch * watch,
4464 gsize * bytes, guint * messages)
4466 g_return_if_fail (watch != NULL);
4468 g_mutex_lock (&watch->mutex);
4470 *bytes = watch->max_bytes;
4472 *messages = watch->max_messages;
4473 g_mutex_unlock (&watch->mutex);
4476 static GstRTSPResult
4477 gst_rtsp_watch_write_serialized_messages (GstRTSPWatch * watch,
4478 GstRTSPSerializedMessage * messages, guint n_messages, guint * id)
4481 GMainContext *context = NULL;
4484 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4485 g_return_val_if_fail (messages != NULL, GST_RTSP_EINVAL);
4487 g_mutex_lock (&watch->mutex);
4488 if (watch->flushing)
4491 /* try to send the message synchronously first */
4492 if (gst_queue_array_get_length (watch->messages) == 0) {
4494 GOutputVector *vectors;
4495 GstMapInfo *map_infos;
4496 gsize bytes_to_write, bytes_written;
4497 guint n_vectors, n_memories, drop_messages;
4499 for (i = 0, n_vectors = 0, n_memories = 0; i < n_messages; i++) {
4501 if (messages[i].body_data) {
4503 } else if (messages[i].body_buffer) {
4504 n_vectors += gst_buffer_n_memory (messages[i].body_buffer);
4505 n_memories += gst_buffer_n_memory (messages[i].body_buffer);
4509 vectors = g_newa (GOutputVector, n_vectors);
4510 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
4512 for (i = 0, j = 0, k = 0, bytes_to_write = 0; i < n_messages; i++) {
4513 vectors[j].buffer = messages[i].data_is_data_header ?
4514 messages[i].data_header : messages[i].data;
4515 vectors[j].size = messages[i].data_size;
4516 bytes_to_write += vectors[j].size;
4519 if (messages[i].body_data) {
4520 vectors[j].buffer = messages[i].body_data;
4521 vectors[j].size = messages[i].body_data_size;
4522 bytes_to_write += vectors[j].size;
4524 } else if (messages[i].body_buffer) {
4527 n = gst_buffer_n_memory (messages[i].body_buffer);
4528 for (l = 0; l < n; l++) {
4529 GstMemory *mem = gst_buffer_peek_memory (messages[i].body_buffer, l);
4531 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
4532 vectors[j].buffer = map_infos[k].data;
4533 vectors[j].size = map_infos[k].size;
4534 bytes_to_write += vectors[j].size;
4543 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4544 &bytes_written, FALSE, watch->conn->cancellable);
4545 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4547 /* At this point we sent everything we could without blocking or
4548 * error and updated the offsets inside the message accordingly */
4550 /* First of all unmap all memories. This simplifies the code below */
4551 for (k = 0; k < n_memories; k++) {
4552 gst_memory_unmap (map_infos[k].memory, &map_infos[k]);
4555 if (res != GST_RTSP_EINTR) {
4556 /* actual error or done completely */
4560 /* free everything */
4561 for (i = 0, k = 0; i < n_messages; i++) {
4562 gst_rtsp_serialized_message_clear (&messages[i]);
4568 /* not done, let's skip all messages that were sent already and free them */
4569 for (i = 0, k = 0, drop_messages = 0; i < n_messages; i++) {
4570 if (bytes_written >= messages[i].data_size) {
4573 /* all data of this message is sent, check body and otherwise
4574 * skip the whole message for next time */
4575 messages[i].data_offset = messages[i].data_size;
4576 bytes_written -= messages[i].data_size;
4578 if (messages[i].body_data) {
4579 body_size = messages[i].body_data_size;
4581 } else if (messages[i].body_buffer) {
4582 body_size = gst_buffer_get_size (messages[i].body_buffer);
4587 if (bytes_written >= body_size) {
4588 /* body written, drop this message */
4589 messages[i].body_offset = body_size;
4590 bytes_written -= body_size;
4593 gst_rtsp_serialized_message_clear (&messages[i]);
4595 messages[i].body_offset = bytes_written;
4599 /* Need to continue sending from the data of this message */
4600 messages[i].data_offset = bytes_written;
4605 g_assert (n_messages > drop_messages);
4607 messages += drop_messages;
4608 n_messages -= drop_messages;
4612 if (IS_BACKLOG_FULL (watch))
4613 goto too_much_backlog;
4615 for (i = 0; i < n_messages; i++) {
4616 GstRTSPSerializedMessage local_message;
4618 /* make a record with the data and id for sending async */
4619 local_message = messages[i];
4621 /* copy the body data or take an additional reference to the body buffer
4622 * we don't own them here */
4623 if (local_message.body_data) {
4624 local_message.body_data =
4625 g_memdup2 (local_message.body_data, local_message.body_data_size);
4626 } else if (local_message.body_buffer) {
4627 gst_buffer_ref (local_message.body_buffer);
4629 local_message.borrowed = FALSE;
4631 /* set an id for the very last message */
4632 if (i == n_messages - 1) {
4634 /* make sure rec->id is never 0 */
4635 local_message.id = ++watch->id;
4636 } while (G_UNLIKELY (local_message.id == 0));
4639 *id = local_message.id;
4641 local_message.id = 0;
4644 /* add the record to a queue. */
4645 gst_queue_array_push_tail_struct (watch->messages, &local_message);
4646 watch->messages_bytes +=
4647 (local_message.data_size - local_message.data_offset);
4648 if (local_message.body_data)
4649 watch->messages_bytes +=
4650 (local_message.body_data_size - local_message.body_offset);
4651 else if (local_message.body_buffer)
4652 watch->messages_bytes +=
4653 (gst_buffer_get_size (local_message.body_buffer) -
4654 local_message.body_offset);
4656 /* each message chunks is one unit */
4657 watch->messages_count++;
4659 /* make sure the main context will now also check for writability on the
4661 context = ((GSource *) watch)->context;
4662 if (!watch->writesrc) {
4663 /* remove the read source on the write socket, we will be able to detect
4664 * errors while writing */
4665 if (watch->controlsrc) {
4666 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4667 g_source_unref (watch->controlsrc);
4668 watch->controlsrc = NULL;
4672 g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM
4673 (watch->conn->output_stream), NULL);
4674 g_source_set_callback (watch->writesrc,
4675 (GSourceFunc) gst_rtsp_source_dispatch_write, watch, NULL);
4676 g_source_add_child_source ((GSource *) watch, watch->writesrc);
4681 g_mutex_unlock (&watch->mutex);
4684 g_main_context_wakeup (context);
4691 GST_DEBUG ("we are flushing");
4692 g_mutex_unlock (&watch->mutex);
4693 for (i = 0; i < n_messages; i++) {
4694 gst_rtsp_serialized_message_clear (&messages[i]);
4696 return GST_RTSP_EINTR;
4700 GST_WARNING ("too much backlog: max_bytes %" G_GSIZE_FORMAT ", current %"
4701 G_GSIZE_FORMAT ", max_messages %u, current %u", watch->max_bytes,
4702 watch->messages_bytes, watch->max_messages, watch->messages_count);
4703 g_mutex_unlock (&watch->mutex);
4704 for (i = 0; i < n_messages; i++) {
4705 gst_rtsp_serialized_message_clear (&messages[i]);
4707 return GST_RTSP_ENOMEM;
4714 * gst_rtsp_watch_write_data:
4715 * @watch: a #GstRTSPWatch
4716 * @data: (array length=size) (transfer full): the data to queue
4717 * @size: the size of @data
4718 * @id: (out) (allow-none): location for a message ID or %NULL
4720 * Write @data using the connection of the @watch. If it cannot be sent
4721 * immediately, it will be queued for transmission in @watch. The contents of
4722 * @message will then be serialized and transmitted when the connection of the
4723 * @watch becomes writable. In case the @message is queued, the ID returned in
4724 * @id will be non-zero and used as the ID argument in the message_sent
4727 * This function will take ownership of @data and g_free() it after use.
4729 * If the amount of queued data exceeds the limits set with
4730 * gst_rtsp_watch_set_send_backlog(), this function will return
4733 * Returns: #GST_RTSP_OK on success. #GST_RTSP_ENOMEM when the backlog limits
4734 * are reached. #GST_RTSP_EINTR when @watch was flushing.
4736 /* FIXME 2.0: This should've been static! */
4738 gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
4739 guint size, guint * id)
4741 GstRTSPSerializedMessage serialized_message;
4743 memset (&serialized_message, 0, sizeof (serialized_message));
4744 serialized_message.data = (guint8 *) data;
4745 serialized_message.data_size = size;
4747 return gst_rtsp_watch_write_serialized_messages (watch, &serialized_message,
4752 * gst_rtsp_watch_send_message:
4753 * @watch: a #GstRTSPWatch
4754 * @message: a #GstRTSPMessage
4755 * @id: (out) (allow-none): location for a message ID or %NULL
4757 * Send a @message using the connection of the @watch. If it cannot be sent
4758 * immediately, it will be queued for transmission in @watch. The contents of
4759 * @message will then be serialized and transmitted when the connection of the
4760 * @watch becomes writable. In case the @message is queued, the ID returned in
4761 * @id will be non-zero and used as the ID argument in the message_sent
4764 * Returns: #GST_RTSP_OK on success.
4767 gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
4770 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4771 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4773 return gst_rtsp_watch_send_messages (watch, message, 1, id);
4777 * gst_rtsp_watch_send_messages:
4778 * @watch: a #GstRTSPWatch
4779 * @messages: (array length=n_messages): the messages to send
4780 * @n_messages: the number of messages to send
4781 * @id: (out) (allow-none): location for a message ID or %NULL
4783 * Sends @messages using the connection of the @watch. If they cannot be sent
4784 * immediately, they will be queued for transmission in @watch. The contents of
4785 * @messages will then be serialized and transmitted when the connection of the
4786 * @watch becomes writable. In case the @messages are queued, the ID returned in
4787 * @id will be non-zero and used as the ID argument in the message_sent
4788 * callback once the last message is sent. The callback will only be called
4789 * once for the last message.
4791 * Returns: #GST_RTSP_OK on success.
4796 gst_rtsp_watch_send_messages (GstRTSPWatch * watch, GstRTSPMessage * messages,
4797 guint n_messages, guint * id)
4799 GstRTSPSerializedMessage *serialized_messages;
4802 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4803 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
4805 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
4806 memset (serialized_messages, 0,
4807 sizeof (GstRTSPSerializedMessage) * n_messages);
4809 for (i = 0; i < n_messages; i++) {
4810 if (!serialize_message (watch->conn, &messages[i], &serialized_messages[i]))
4814 return gst_rtsp_watch_write_serialized_messages (watch, serialized_messages,
4818 for (i = 0; i < n_messages; i++) {
4819 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
4822 return GST_RTSP_EINVAL;
4826 * gst_rtsp_watch_wait_backlog_usec:
4827 * @watch: a #GstRTSPWatch
4828 * @timeout: a timeout in microseconds
4830 * Wait until there is place in the backlog queue, @timeout is reached
4831 * or @watch is set to flushing.
4833 * If @timeout is 0 this function can block forever. If @timeout
4834 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
4835 * after the timeout expired.
4837 * The typically use of this function is when gst_rtsp_watch_write_data
4838 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
4839 * free space in the backlog queue and try again.
4841 * Returns: %GST_RTSP_OK when if there is room in queue.
4842 * %GST_RTSP_ETIMEOUT when @timeout was reached.
4843 * %GST_RTSP_EINTR when @watch is flushing
4844 * %GST_RTSP_EINVAL when called with invalid parameters.
4849 gst_rtsp_watch_wait_backlog_usec (GstRTSPWatch * watch, gint64 timeout)
4853 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4855 end_time = g_get_monotonic_time () + timeout;
4857 g_mutex_lock (&watch->mutex);
4858 if (watch->flushing)
4861 while (IS_BACKLOG_FULL (watch)) {
4864 res = g_cond_wait_until (&watch->queue_not_full, &watch->mutex, end_time);
4865 if (watch->flushing)
4871 g_mutex_unlock (&watch->mutex);
4878 GST_DEBUG ("we are flushing");
4879 g_mutex_unlock (&watch->mutex);
4880 return GST_RTSP_EINTR;
4884 GST_DEBUG ("we timed out");
4885 g_mutex_unlock (&watch->mutex);
4886 return GST_RTSP_ETIMEOUT;
4891 * gst_rtsp_watch_set_flushing:
4892 * @watch: a #GstRTSPWatch
4893 * @flushing: new flushing state
4895 * When @flushing is %TRUE, abort a call to gst_rtsp_watch_wait_backlog()
4896 * and make sure gst_rtsp_watch_write_data() returns immediately with
4897 * #GST_RTSP_EINTR. And empty the queue.
4902 gst_rtsp_watch_set_flushing (GstRTSPWatch * watch, gboolean flushing)
4904 g_return_if_fail (watch != NULL);
4906 g_mutex_lock (&watch->mutex);
4907 watch->flushing = flushing;
4908 g_cond_signal (&watch->queue_not_full);
4910 GstRTSPSerializedMessage *msg;
4912 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4913 gst_rtsp_serialized_message_clear (msg);
4916 g_mutex_unlock (&watch->mutex);
4920 #ifndef GST_DISABLE_DEPRECATED
4921 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4923 #define TV_TO_USEC(tv) ((tv) ? ((tv)->tv_sec * G_USEC_PER_SEC + (tv)->tv_usec) : 0)
4925 * gst_rtsp_connection_connect:
4926 * @conn: a #GstRTSPConnection
4927 * @timeout: a GTimeVal timeout
4929 * Attempt to connect to the url of @conn made with
4930 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4931 * forever. If @timeout contains a valid timeout, this function will return
4932 * #GST_RTSP_ETIMEOUT after the timeout expired.
4934 * This function can be cancelled with gst_rtsp_connection_flush().
4936 * Returns: #GST_RTSP_OK when a connection could be made.
4941 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
4943 return gst_rtsp_connection_connect_usec (conn, TV_TO_USEC (timeout));
4947 * gst_rtsp_connection_connect_with_response:
4948 * @conn: a #GstRTSPConnection
4949 * @timeout: a GTimeVal timeout
4950 * @response: a #GstRTSPMessage
4952 * Attempt to connect to the url of @conn made with
4953 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4954 * forever. If @timeout contains a valid timeout, this function will return
4955 * #GST_RTSP_ETIMEOUT after the timeout expired. If @conn is set to tunneled,
4956 * @response will contain a response to the tunneling request messages.
4958 * This function can be cancelled with gst_rtsp_connection_flush().
4960 * Returns: #GST_RTSP_OK when a connection could be made.
4966 gst_rtsp_connection_connect_with_response (GstRTSPConnection * conn,
4967 GTimeVal * timeout, GstRTSPMessage * response)
4969 return gst_rtsp_connection_connect_with_response_usec (conn,
4970 TV_TO_USEC (timeout), response);
4974 * gst_rtsp_connection_read:
4975 * @conn: a #GstRTSPConnection
4976 * @data: the data to read
4977 * @size: the size of @data
4978 * @timeout: a timeout value or %NULL
4980 * Attempt to read @size bytes into @data from 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_read (GstRTSPConnection * conn, guint8 * data, guint size,
4994 return gst_rtsp_connection_read_usec (conn, data, size, TV_TO_USEC (timeout));
4998 * gst_rtsp_connection_write:
4999 * @conn: a #GstRTSPConnection
5000 * @data: the data to write
5001 * @size: the size of @data
5002 * @timeout: a timeout value or %NULL
5004 * Attempt to write @size bytes of @data 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.
5015 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
5016 guint size, GTimeVal * timeout)
5018 return gst_rtsp_connection_write_usec (conn, data, size,
5019 TV_TO_USEC (timeout));
5023 * gst_rtsp_connection_send:
5024 * @conn: a #GstRTSPConnection
5025 * @message: the message to send
5026 * @timeout: a timeout value or %NULL
5028 * Attempt to send @message to the connected @conn, blocking up to
5029 * the specified @timeout. @timeout can be %NULL, in which case this function
5030 * might block forever.
5032 * This function can be cancelled with gst_rtsp_connection_flush().
5034 * Returns: #GST_RTSP_OK on success.
5039 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
5042 return gst_rtsp_connection_send_usec (conn, message, TV_TO_USEC (timeout));
5046 * gst_rtsp_connection_send_messages:
5047 * @conn: a #GstRTSPConnection
5048 * @messages: (array length=n_messages): the messages to send
5049 * @n_messages: the number of messages to send
5050 * @timeout: a timeout value or %NULL
5052 * Attempt to send @messages to the connected @conn, blocking up to
5053 * the specified @timeout. @timeout can be %NULL, in which case this function
5054 * might block forever.
5056 * This function can be cancelled with gst_rtsp_connection_flush().
5058 * Returns: #GST_RTSP_OK on success.
5064 gst_rtsp_connection_send_messages (GstRTSPConnection * conn,
5065 GstRTSPMessage * messages, guint n_messages, GTimeVal * timeout)
5067 return gst_rtsp_connection_send_messages_usec (conn, messages, n_messages,
5068 TV_TO_USEC (timeout));
5072 * gst_rtsp_connection_receive:
5073 * @conn: a #GstRTSPConnection
5074 * @message: the message to read
5075 * @timeout: a timeout value or %NULL
5077 * Attempt to read into @message from the connected @conn, blocking up to
5078 * the specified @timeout. @timeout can be %NULL, in which case this function
5079 * might block forever.
5081 * This function can be cancelled with gst_rtsp_connection_flush().
5083 * Returns: #GST_RTSP_OK on success.
5088 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
5091 return gst_rtsp_connection_receive_usec (conn, message, TV_TO_USEC (timeout));
5095 * gst_rtsp_connection_poll:
5096 * @conn: a #GstRTSPConnection
5097 * @events: a bitmask of #GstRTSPEvent flags to check
5098 * @revents: location for result flags
5099 * @timeout: a timeout
5101 * Wait up to the specified @timeout for the connection to become available for
5102 * at least one of the operations specified in @events. When the function returns
5103 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
5106 * @timeout can be %NULL, in which case this function might block forever.
5108 * This function can be cancelled with gst_rtsp_connection_flush().
5110 * Returns: #GST_RTSP_OK on success.
5115 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
5116 GstRTSPEvent * revents, GTimeVal * timeout)
5118 return gst_rtsp_connection_poll_usec (conn, events, revents,
5119 TV_TO_USEC (timeout));
5123 * gst_rtsp_connection_next_timeout:
5124 * @conn: a #GstRTSPConnection
5125 * @timeout: a timeout
5127 * Calculate the next timeout for @conn, storing the result in @timeout.
5129 * Returns: #GST_RTSP_OK.
5134 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
5136 gint64 tmptimeout = 0;
5138 g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
5140 tmptimeout = gst_rtsp_connection_next_timeout_usec (conn);
5142 timeout->tv_sec = tmptimeout / G_USEC_PER_SEC;
5143 timeout->tv_usec = tmptimeout % G_USEC_PER_SEC;
5150 * gst_rtsp_watch_wait_backlog:
5151 * @watch: a #GstRTSPWatch
5152 * @timeout: a GTimeVal timeout
5154 * Wait until there is place in the backlog queue, @timeout is reached
5155 * or @watch is set to flushing.
5157 * If @timeout is %NULL this function can block forever. If @timeout
5158 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
5159 * after the timeout expired.
5161 * The typically use of this function is when gst_rtsp_watch_write_data
5162 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
5163 * free space in the backlog queue and try again.
5165 * Returns: %GST_RTSP_OK when if there is room in queue.
5166 * %GST_RTSP_ETIMEOUT when @timeout was reached.
5167 * %GST_RTSP_EINTR when @watch is flushing
5168 * %GST_RTSP_EINVAL when called with invalid parameters.
5174 gst_rtsp_watch_wait_backlog (GstRTSPWatch * watch, GTimeVal * timeout)
5176 return gst_rtsp_watch_wait_backlog_usec (watch, TV_TO_USEC (timeout));
5179 G_GNUC_END_IGNORE_DEPRECATIONS
5180 #endif /* GST_DISABLE_DEPRECATED */