1 /* GStreamer
2 * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.com>
3 *
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.
8 *
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.
13 *
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.
18 */
19 /*
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
22 * LICENSE).
23 *
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:
30 *
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
33 *
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
40 * SOFTWARE.
41 */
42
43 /**
44 * SECTION:gstrtspconnection
45 * @title: GstRTSPConnection
46 * @short_description: manage RTSP connections
47 * @see_also: gstrtspurl
48 *
49 * This object manages the RTSP connection to the server. It provides function
50 * to receive and send bytes and messages.
51 */
52
53 #ifdef HAVE_CONFIG_H
54 # include <config.h>
55 #endif
56
57 #include <stdio.h>
58 #include <errno.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <time.h>
62
63 /* we include this here to get the G_OS_* defines */
64 #include <glib.h>
65 #include <gst/gst.h>
66 #include <gst/base/base.h>
67
68 /* necessary for IP_TOS define */
69 #include <gio/gnetworking.h>
70
71 #include "gstrtspconnection.h"
72
73 #ifdef IP_TOS
74 union gst_sockaddr
75 {
76 struct sockaddr sa;
77 struct sockaddr_in sa_in;
78 struct sockaddr_in6 sa_in6;
79 struct sockaddr_storage sa_stor;
80 };
81 #endif
82
83 typedef struct
84 {
85 gint state;
86 guint save;
87 guchar out[3]; /* the size must be evenly divisible by 3 */
88 guint cout;
89 guint coutl;
90 } DecodeCtx;
91
92 typedef struct
93 {
94 /* If %TRUE we only own data and none of the
95 * other fields
96 */
97 gboolean borrowed;
98
99 /* Header or full message */
100 guint8 *data;
101 guint data_size;
102 gboolean data_is_data_header;
103
104 /* Payload following data, if any */
105 guint8 *body_data;
106 guint body_data_size;
107 /* or */
108 GstBuffer *body_buffer;
109
110 /* DATA packet header statically allocated for above */
111 guint8 data_header[4];
112
113 /* all below only for async writing */
114
115 guint data_offset; /* == data_size when done */
116 guint body_offset; /* into body_data or the buffer */
117
118 /* ID of the message for notification */
119 guint id;
120 } GstRTSPSerializedMessage;
121
122 static void
gst_rtsp_serialized_message_clear(GstRTSPSerializedMessage * msg)123 gst_rtsp_serialized_message_clear (GstRTSPSerializedMessage * msg)
124 {
125 if (!msg->borrowed) {
126 g_free (msg->body_data);
127 gst_buffer_replace (&msg->body_buffer, NULL);
128 }
129 g_free (msg->data);
130 }
131
132 #ifdef MSG_NOSIGNAL
133 #define SEND_FLAGS MSG_NOSIGNAL
134 #else
135 #define SEND_FLAGS 0
136 #endif
137
138 typedef enum
139 {
140 TUNNEL_STATE_NONE,
141 TUNNEL_STATE_GET,
142 TUNNEL_STATE_POST,
143 TUNNEL_STATE_COMPLETE
144 } GstRTSPTunnelState;
145
146 #define TUNNELID_LEN 24
147
148 struct _GstRTSPConnection
149 {
150 /*< private > */
151 /* URL for the remote connection */
152 GstRTSPUrl *url;
153 GstRTSPVersion version;
154
155 gboolean server;
156 GSocketClient *client;
157 GIOStream *stream0;
158 GIOStream *stream1;
159
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;
165
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;
174 gboolean may_cancel;
175 GCancellable *cancellable;
176
177 gchar tunnelid[TUNNELID_LEN];
178 gboolean tunneled;
179 gboolean ignore_x_server_reply;
180 GstRTSPTunnelState tstate;
181
182 /* the remote and local ip */
183 gchar *remote_ip;
184 gchar *local_ip;
185
186 gint read_ahead;
187
188 gchar *initial_buffer;
189 gsize initial_buffer_offset;
190
191 gboolean remember_session_id; /* remember the session id or not */
192
193 /* Session state */
194 gint cseq; /* sequence number */
195 gchar session_id[512]; /* session id */
196 gint timeout; /* session timeout in seconds */
197 GTimer *timer; /* timeout timer */
198
199 /* Authentication */
200 GstRTSPAuthMethod auth_method;
201 gchar *username;
202 gchar *passwd;
203 GHashTable *auth_params;
204
205 guint content_length_limit;
206
207 /* TLS */
208 GTlsDatabase *tls_database;
209 GTlsInteraction *tls_interaction;
210
211 GstRTSPConnectionAcceptCertificateFunc accept_certificate_func;
212 GDestroyNotify accept_certificate_destroy_notify;
213 gpointer accept_certificate_user_data;
214
215 DecodeCtx ctx;
216 DecodeCtx *ctxp;
217
218 gchar *proxy_host;
219 guint proxy_port;
220 };
221
222 enum
223 {
224 STATE_START = 0,
225 STATE_DATA_HEADER,
226 STATE_DATA_BODY,
227 STATE_READ_LINES,
228 STATE_END,
229 STATE_LAST
230 };
231
232 enum
233 {
234 READ_AHEAD_EOH = -1, /* end of headers */
235 READ_AHEAD_CRLF = -2,
236 READ_AHEAD_CRLFCR = -3
237 };
238
239 /* a structure for constructing RTSPMessages */
240 typedef struct
241 {
242 gint state;
243 GstRTSPResult status;
244 guint8 buffer[4096];
245 guint offset;
246
247 guint line;
248 guint8 *body_data;
249 guint body_len;
250 } GstRTSPBuilder;
251
252 /* function prototypes */
253 static void add_auth_header (GstRTSPConnection * conn,
254 GstRTSPMessage * message);
255
256 static void
build_reset(GstRTSPBuilder * builder)257 build_reset (GstRTSPBuilder * builder)
258 {
259 g_free (builder->body_data);
260 memset (builder, 0, sizeof (GstRTSPBuilder));
261 }
262
263 static GstRTSPResult
gst_rtsp_result_from_g_io_error(GError * error,GstRTSPResult default_res)264 gst_rtsp_result_from_g_io_error (GError * error, GstRTSPResult default_res)
265 {
266 if (error == NULL)
267 return GST_RTSP_OK;
268
269 if (error->domain != G_IO_ERROR)
270 return default_res;
271
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;
280 default:
281 return default_res;
282 }
283 }
284
285 static gboolean
tls_accept_certificate(GTlsConnection * conn,GTlsCertificate * peer_cert,GTlsCertificateFlags errors,GstRTSPConnection * rtspconn)286 tls_accept_certificate (GTlsConnection * conn, GTlsCertificate * peer_cert,
287 GTlsCertificateFlags errors, GstRTSPConnection * rtspconn)
288 {
289 GError *error = NULL;
290 gboolean accept = FALSE;
291
292 if (rtspconn->tls_database) {
293 GSocketConnectable *peer_identity;
294 GTlsCertificateFlags validation_flags;
295
296 GST_DEBUG ("TLS peer certificate not accepted, checking user database...");
297
298 peer_identity =
299 g_tls_client_connection_get_server_identity (G_TLS_CLIENT_CONNECTION
300 (conn));
301
302 errors =
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,
306 NULL, &error);
307
308 if (error)
309 goto verify_error;
310
311 validation_flags = gst_rtsp_connection_get_tls_validation_flags (rtspconn);
312
313 accept = ((errors & validation_flags) == 0);
314 if (accept)
315 GST_DEBUG ("Peer certificate accepted");
316 else
317 GST_DEBUG ("Peer certificate not accepted (errors: 0x%08X)", errors);
318 }
319
320 if (!accept && rtspconn->accept_certificate_func) {
321 accept =
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 ");
326 }
327
328 return accept;
329
330 /* ERRORS */
331 verify_error:
332 {
333 GST_ERROR ("An error occurred while verifying the peer certificate: %s",
334 error->message);
335 g_clear_error (&error);
336 return FALSE;
337 }
338 }
339
340 static void
socket_client_event(GSocketClient * client,GSocketClientEvent event,GSocketConnectable * connectable,GTlsConnection * connection,GstRTSPConnection * rtspconn)341 socket_client_event (GSocketClient * client, GSocketClientEvent event,
342 GSocketConnectable * connectable, GTlsConnection * connection,
343 GstRTSPConnection * rtspconn)
344 {
345 if (event == G_SOCKET_CLIENT_TLS_HANDSHAKING) {
346 GST_DEBUG ("TLS handshaking about to start...");
347
348 g_signal_connect (connection, "accept-certificate",
349 (GCallback) tls_accept_certificate, rtspconn);
350
351 g_tls_connection_set_interaction (connection, rtspconn->tls_interaction);
352 }
353 }
354
355 /**
356 * gst_rtsp_connection_create:
357 * @url: a #GstRTSPUrl
358 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
359 *
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().
363 *
364 * A copy of @url will be made.
365 *
366 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
367 */
368 GstRTSPResult
gst_rtsp_connection_create(const GstRTSPUrl * url,GstRTSPConnection ** conn)369 gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
370 {
371 GstRTSPConnection *newconn;
372
373 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
374 g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
375
376 newconn = g_new0 (GstRTSPConnection, 1);
377
378 newconn->may_cancel = TRUE;
379 newconn->cancellable = g_cancellable_new ();
380 newconn->client = g_socket_client_new ();
381
382 if (url->transports & GST_RTSP_LOWER_TRANS_TLS)
383 g_socket_client_set_tls (newconn->client, TRUE);
384
385 g_signal_connect (newconn->client, "event", (GCallback) socket_client_event,
386 newconn);
387
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. */
393
394 newconn->remember_session_id = TRUE;
395
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;
401
402 newconn->content_length_limit = G_MAXUINT;
403
404 *conn = newconn;
405
406 return GST_RTSP_OK;
407 }
408
409 static gboolean
collect_addresses(GSocket * socket,gchar ** ip,guint16 * port,gboolean remote,GError ** error)410 collect_addresses (GSocket * socket, gchar ** ip, guint16 * port,
411 gboolean remote, GError ** error)
412 {
413 GSocketAddress *addr;
414
415 if (remote)
416 addr = g_socket_get_remote_address (socket, error);
417 else
418 addr = g_socket_get_local_address (socket, error);
419 if (!addr)
420 return FALSE;
421
422 if (ip)
423 *ip = g_inet_address_to_string (g_inet_socket_address_get_address
424 (G_INET_SOCKET_ADDRESS (addr)));
425 if (port)
426 *port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
427
428 g_object_unref (addr);
429
430 return TRUE;
431 }
432
433
434 /**
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
441 *
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.
445 *
446 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
447 */
448 /* FIXME 2.0 We don't need the ip and port since they can be got from the
449 * GSocket */
450 GstRTSPResult
gst_rtsp_connection_create_from_socket(GSocket * socket,const gchar * ip,guint16 port,const gchar * initial_buffer,GstRTSPConnection ** conn)451 gst_rtsp_connection_create_from_socket (GSocket * socket, const gchar * ip,
452 guint16 port, const gchar * initial_buffer, GstRTSPConnection ** conn)
453 {
454 GstRTSPConnection *newconn = NULL;
455 GstRTSPUrl *url;
456 GstRTSPResult res;
457 GError *err = NULL;
458 gchar *local_ip;
459 GIOStream *stream;
460
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);
464
465 if (!collect_addresses (socket, &local_ip, NULL, FALSE, &err))
466 goto getnameinfo_failed;
467
468 /* create a url for the client address */
469 url = g_new0 (GstRTSPUrl, 1);
470 url->host = g_strdup (ip);
471 url->port = port;
472
473 /* now create the connection object */
474 GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
475 gst_rtsp_url_free (url);
476
477 stream = G_IO_STREAM (g_socket_connection_factory_create_connection (socket));
478
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);
493
494 *conn = newconn;
495
496 return GST_RTSP_OK;
497
498 /* ERRORS */
499 getnameinfo_failed:
500 {
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);
504 return res;
505 }
506 newconn_failed:
507 {
508 GST_ERROR ("failed to make connection");
509 g_free (local_ip);
510 gst_rtsp_url_free (url);
511 return res;
512 }
513 }
514
515 /**
516 * gst_rtsp_connection_accept:
517 * @socket: a socket
518 * @conn: (out) (transfer full): storage for a #GstRTSPConnection
519 * @cancellable: a #GCancellable to cancel the operation
520 *
521 * Accept a new connection on @socket and create a new #GstRTSPConnection for
522 * handling communication on new socket.
523 *
524 * Returns: #GST_RTSP_OK when @conn contains a valid connection.
525 */
526 GstRTSPResult
gst_rtsp_connection_accept(GSocket * socket,GstRTSPConnection ** conn,GCancellable * cancellable)527 gst_rtsp_connection_accept (GSocket * socket, GstRTSPConnection ** conn,
528 GCancellable * cancellable)
529 {
530 GError *err = NULL;
531 gchar *ip;
532 guint16 port;
533 GSocket *client_sock;
534 GstRTSPResult ret;
535
536 g_return_val_if_fail (G_IS_SOCKET (socket), GST_RTSP_EINVAL);
537 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
538
539 client_sock = g_socket_accept (socket, cancellable, &err);
540 if (!client_sock)
541 goto accept_failed;
542
543 /* get the remote ip address and port */
544 if (!collect_addresses (client_sock, &ip, &port, TRUE, &err))
545 goto getnameinfo_failed;
546
547 ret =
548 gst_rtsp_connection_create_from_socket (client_sock, ip, port, NULL,
549 conn);
550 g_object_unref (client_sock);
551 g_free (ip);
552
553 return ret;
554
555 /* ERRORS */
556 accept_failed:
557 {
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);
561 return ret;
562 }
563 getnameinfo_failed:
564 {
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);
571 }
572 g_object_unref (client_sock);
573 return ret;
574 }
575 }
576
577 /**
578 * gst_rtsp_connection_get_tls:
579 * @conn: a #GstRTSPConnection
580 * @error: #GError for error reporting, or NULL to ignore.
581 *
582 * Get the TLS connection of @conn.
583 *
584 * For client side this will return the #GTlsClientConnection when connected
585 * over TLS.
586 *
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.
590 *
591 * Returns: (transfer none): the TLS connection for @conn.
592 *
593 * Since: 1.2
594 */
595 GTlsConnection *
gst_rtsp_connection_get_tls(GstRTSPConnection * conn,GError ** error)596 gst_rtsp_connection_get_tls (GstRTSPConnection * conn, GError ** error)
597 {
598 GTlsConnection *result;
599
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);
607 if (result) {
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);
612 }
613 } else {
614 /* client */
615 result = NULL;
616 g_set_error (error, GST_LIBRARY_ERROR, GST_LIBRARY_ERROR_FAILED,
617 "client not connected with TLS");
618 }
619 return result;
620 }
621
622 /**
623 * gst_rtsp_connection_set_tls_validation_flags:
624 * @conn: a #GstRTSPConnection
625 * @flags: the validation flags.
626 *
627 * Sets the TLS validation flags to be used to verify the peer
628 * certificate when a TLS connection is established.
629 *
630 * Returns: TRUE if the validation flags are set correctly, or FALSE if
631 * @conn is NULL or is not a TLS connection.
632 *
633 * Since: 1.2.1
634 */
635 gboolean
gst_rtsp_connection_set_tls_validation_flags(GstRTSPConnection * conn,GTlsCertificateFlags flags)636 gst_rtsp_connection_set_tls_validation_flags (GstRTSPConnection * conn,
637 GTlsCertificateFlags flags)
638 {
639 gboolean res = FALSE;
640
641 g_return_val_if_fail (conn != NULL, FALSE);
642
643 res = g_socket_client_get_tls (conn->client);
644 if (res)
645 g_socket_client_set_tls_validation_flags (conn->client, flags);
646
647 return res;
648 }
649
650 /**
651 * gst_rtsp_connection_get_tls_validation_flags:
652 * @conn: a #GstRTSPConnection
653 *
654 * Gets the TLS validation flags used to verify the peer certificate
655 * when a TLS connection is established.
656 *
657 * Returns: the validationg flags.
658 *
659 * Since: 1.2.1
660 */
661 GTlsCertificateFlags
gst_rtsp_connection_get_tls_validation_flags(GstRTSPConnection * conn)662 gst_rtsp_connection_get_tls_validation_flags (GstRTSPConnection * conn)
663 {
664 g_return_val_if_fail (conn != NULL, 0);
665
666 return g_socket_client_get_tls_validation_flags (conn->client);
667 }
668
669 /**
670 * gst_rtsp_connection_set_tls_database:
671 * @conn: a #GstRTSPConnection
672 * @database: a #GTlsDatabase
673 *
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.
677 *
678 * Since: 1.4
679 */
680 void
gst_rtsp_connection_set_tls_database(GstRTSPConnection * conn,GTlsDatabase * database)681 gst_rtsp_connection_set_tls_database (GstRTSPConnection * conn,
682 GTlsDatabase * database)
683 {
684 GTlsDatabase *old_db;
685
686 g_return_if_fail (conn != NULL);
687
688 if (database)
689 g_object_ref (database);
690
691 old_db = conn->tls_database;
692 conn->tls_database = database;
693
694 if (old_db)
695 g_object_unref (old_db);
696 }
697
698 /**
699 * gst_rtsp_connection_get_tls_database:
700 * @conn: a #GstRTSPConnection
701 *
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.
705 *
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.
709 *
710 * Since: 1.4
711 */
712 GTlsDatabase *
gst_rtsp_connection_get_tls_database(GstRTSPConnection * conn)713 gst_rtsp_connection_get_tls_database (GstRTSPConnection * conn)
714 {
715 GTlsDatabase *result;
716
717 g_return_val_if_fail (conn != NULL, NULL);
718
719 if ((result = conn->tls_database))
720 g_object_ref (result);
721
722 return result;
723 }
724
725 /**
726 * gst_rtsp_connection_set_tls_interaction:
727 * @conn: a #GstRTSPConnection
728 * @interaction: a #GTlsInteraction
729 *
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.
733 *
734 * Since: 1.6
735 */
736 void
gst_rtsp_connection_set_tls_interaction(GstRTSPConnection * conn,GTlsInteraction * interaction)737 gst_rtsp_connection_set_tls_interaction (GstRTSPConnection * conn,
738 GTlsInteraction * interaction)
739 {
740 GTlsInteraction *old_interaction;
741
742 g_return_if_fail (conn != NULL);
743
744 if (interaction)
745 g_object_ref (interaction);
746
747 old_interaction = conn->tls_interaction;
748 conn->tls_interaction = interaction;
749
750 if (old_interaction)
751 g_object_unref (old_interaction);
752 }
753
754 /**
755 * gst_rtsp_connection_get_tls_interaction:
756 * @conn: a #GstRTSPConnection
757 *
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.
761 *
762 * Returns: (transfer full): a reference on the #GTlsInteraction. Use
763 * g_object_unref() to release.
764 *
765 * Since: 1.6
766 */
767 GTlsInteraction *
gst_rtsp_connection_get_tls_interaction(GstRTSPConnection * conn)768 gst_rtsp_connection_get_tls_interaction (GstRTSPConnection * conn)
769 {
770 GTlsInteraction *result;
771
772 g_return_val_if_fail (conn != NULL, NULL);
773
774 if ((result = conn->tls_interaction))
775 g_object_ref (result);
776
777 return result;
778 }
779
780 /**
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
786 *
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
792 * be called.
793 *
794 * Since: 1.14
795 */
796 void
gst_rtsp_connection_set_accept_certificate_func(GstRTSPConnection * conn,GstRTSPConnectionAcceptCertificateFunc func,gpointer user_data,GDestroyNotify destroy_notify)797 gst_rtsp_connection_set_accept_certificate_func (GstRTSPConnection * conn,
798 GstRTSPConnectionAcceptCertificateFunc func,
799 gpointer user_data, GDestroyNotify destroy_notify)
800 {
801 if (conn->accept_certificate_destroy_notify)
802 conn->
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;
807 }
808
809 static gchar *
get_tunneled_connection_uri_strdup(GstRTSPUrl * url,guint16 port)810 get_tunneled_connection_uri_strdup (GstRTSPUrl * url, guint16 port)
811 {
812 const gchar *pre_host = "";
813 const gchar *post_host = "";
814
815 if (url->family == GST_RTSP_FAM_INET6) {
816 pre_host = "[";
817 post_host = "]";
818 }
819
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 : "");
823 }
824
825 static GstRTSPResult
setup_tunneling(GstRTSPConnection * conn,gint64 timeout,gchar * uri,GstRTSPMessage * response)826 setup_tunneling (GstRTSPConnection * conn, gint64 timeout, gchar * uri,
827 GstRTSPMessage * response)
828 {
829 gint i;
830 GstRTSPResult res;
831 gchar *value;
832 guint16 url_port;
833 GstRTSPMessage *msg;
834 gboolean old_http;
835 GstRTSPUrl *url;
836 GError *error = NULL;
837 GSocketConnection *connection;
838 GSocket *socket;
839 gchar *connection_uri = NULL;
840 gchar *request_uri = NULL;
841 gchar *host = NULL;
842
843 url = conn->url;
844
845 gst_rtsp_url_get_port (url, &url_port);
846 host = g_strdup_printf ("%s:%d", url->host, url_port);
847
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';
852
853 /* create the GET request for the read connection */
854 GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
855 no_message);
856 msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
857
858 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
859 conn->tunnelid);
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);
865
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),
870 write_failed);
871 gst_rtsp_message_free (msg);
872 conn->tunneled = TRUE;
873
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),
881 read_failed);
882 conn->manual_http = old_http;
883
884 if (response->type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
885 response->type_data.response.code != GST_RTSP_STS_OK)
886 goto wrong_result;
887
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) {
891 g_free (url->host);
892 url->host = g_strdup (value);
893 g_free (conn->remote_ip);
894 conn->remote_ip = g_strdup (value);
895 }
896
897 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
898
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);
904 } else {
905 connection = g_socket_client_connect_to_uri (conn->client,
906 connection_uri, 0, conn->cancellable, &error);
907 request_uri =
908 g_strdup_printf ("%s%s%s", url->abspath,
909 url->query ? "?" : "", url->query ? url->query : "");
910 }
911 if (connection == NULL)
912 goto connect_failed;
913
914 socket = g_socket_connection_get_socket (connection);
915
916 /* get remote address */
917 g_free (conn->remote_ip);
918 conn->remote_ip = NULL;
919
920 if (!collect_addresses (socket, &conn->remote_ip, NULL, TRUE, &error))
921 goto remote_address_failed;
922
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;
929
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;
934
935 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
936 conn->tunnelid);
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);
947
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),
952 write_failed);
953 gst_rtsp_message_free (msg);
954 conn->tunneled = TRUE;
955
956 exit:
957 g_free (connection_uri);
958 g_free (request_uri);
959 g_free (host);
960
961 return res;
962
963 /* ERRORS */
964 no_message:
965 {
966 GST_ERROR ("failed to create request (%d)", res);
967 goto exit;
968 }
969 write_failed:
970 {
971 GST_ERROR ("write failed (%d)", res);
972 gst_rtsp_message_free (msg);
973 conn->tunneled = TRUE;
974 goto exit;
975 }
976 read_failed:
977 {
978 GST_ERROR ("read failed (%d)", res);
979 conn->manual_http = FALSE;
980 goto exit;
981 }
982 wrong_result:
983 {
984 GST_ERROR ("got failure response %d %s",
985 response->type_data.response.code, response->type_data.response.reason);
986 res = GST_RTSP_ERROR;
987 goto exit;
988 }
989 connect_failed:
990 {
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);
994 goto exit;
995 }
996 remote_address_failed:
997 {
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);
1002 return res;
1003 }
1004 }
1005
1006 /**
1007 * gst_rtsp_connection_connect_with_response_usec:
1008 * @conn: a #GstRTSPConnection
1009 * @timeout: a timeout in microseconds
1010 * @response: a #GstRTSPMessage
1011 *
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.
1017 *
1018 * This function can be cancelled with gst_rtsp_connection_flush().
1019 *
1020 * Returns: #GST_RTSP_OK when a connection could be made.
1021 *
1022 * Since: 1.18
1023 */
1024 GstRTSPResult
gst_rtsp_connection_connect_with_response_usec(GstRTSPConnection * conn,gint64 timeout,GstRTSPMessage * response)1025 gst_rtsp_connection_connect_with_response_usec (GstRTSPConnection * conn,
1026 gint64 timeout, GstRTSPMessage * response)
1027 {
1028 GstRTSPResult res;
1029 GSocketConnection *connection;
1030 GSocket *socket;
1031 GError *error = NULL;
1032 gchar *connection_uri, *request_uri, *remote_ip;
1033 GstClockTime to;
1034 guint16 url_port;
1035 GstRTSPUrl *url;
1036
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);
1040
1041 to = timeout * 1000;
1042 g_socket_client_set_timeout (conn->client,
1043 (to + GST_SECOND - 1) / GST_SECOND);
1044
1045 url = conn->url;
1046
1047 gst_rtsp_url_get_port (url, &url_port);
1048
1049 if (conn->tunneled) {
1050 connection_uri = get_tunneled_connection_uri_strdup (url, url_port);
1051 } else {
1052 connection_uri = gst_rtsp_url_get_request_uri (url);
1053 }
1054
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);
1059 } else {
1060 connection = g_socket_client_connect_to_uri (conn->client,
1061 connection_uri, url_port, conn->cancellable, &error);
1062
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 : "");
1066 }
1067 if (connection == NULL)
1068 goto connect_failed;
1069
1070 /* get remote address */
1071 socket = g_socket_connection_get_socket (connection);
1072
1073 if (!collect_addresses (socket, &remote_ip, NULL, TRUE, &error))
1074 goto remote_address_failed;
1075
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;
1088
1089 if (conn->tunneled) {
1090 res = setup_tunneling (conn, timeout, request_uri, response);
1091 if (res != GST_RTSP_OK)
1092 goto tunneling_failed;
1093 }
1094 g_free (connection_uri);
1095 g_free (request_uri);
1096
1097 return GST_RTSP_OK;
1098
1099 /* ERRORS */
1100 connect_failed:
1101 {
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);
1107 return res;
1108 }
1109 remote_address_failed:
1110 {
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);
1117 return res;
1118 }
1119 tunneling_failed:
1120 {
1121 GST_ERROR ("failed to setup tunneling");
1122 g_free (connection_uri);
1123 g_free (request_uri);
1124 return res;
1125 }
1126 }
1127
1128 static void
add_auth_header(GstRTSPConnection * conn,GstRTSPMessage * message)1129 add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
1130 {
1131 switch (conn->auth_method) {
1132 case GST_RTSP_AUTH_BASIC:{
1133 gchar *user_pass;
1134 gchar *user_pass64;
1135 gchar *auth_string;
1136
1137 if (conn->username == NULL || conn->passwd == NULL)
1138 break;
1139
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);
1143
1144 gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
1145 auth_string);
1146
1147 g_free (user_pass);
1148 g_free (user_pass64);
1149 break;
1150 }
1151 case GST_RTSP_AUTH_DIGEST:{
1152 gchar *response;
1153 gchar *auth_string, *auth_string2;
1154 gchar *realm;
1155 gchar *nonce;
1156 gchar *opaque;
1157 const gchar *uri;
1158 const gchar *method;
1159
1160 /* we need to have some params set */
1161 if (conn->auth_params == NULL || conn->username == NULL ||
1162 conn->passwd == NULL)
1163 break;
1164
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)
1169 break;
1170
1171 method = gst_rtsp_method_as_text (message->type_data.request.method);
1172 uri = message->type_data.request.uri;
1173
1174 response =
1175 gst_rtsp_generate_digest_auth_response (NULL, method, realm,
1176 conn->username, conn->passwd, uri, nonce);
1177 auth_string =
1178 g_strdup_printf ("Digest username=\"%s\", "
1179 "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
1180 conn->username, realm, nonce, uri, response);
1181 g_free (response);
1182
1183 opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
1184 if (opaque) {
1185 auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
1186 opaque);
1187 g_free (auth_string);
1188 auth_string = auth_string2;
1189 }
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,
1193 auth_string);
1194 break;
1195 }
1196 default:
1197 /* Nothing to do */
1198 break;
1199 }
1200 }
1201
1202 /**
1203 * gst_rtsp_connection_connect_usec:
1204 * @conn: a #GstRTSPConnection
1205 * @timeout: a timeout in microseconds
1206 *
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.
1211 *
1212 * This function can be cancelled with gst_rtsp_connection_flush().
1213 *
1214 * Returns: #GST_RTSP_OK when a connection could be made.
1215 *
1216 * Since: 1.18
1217 */
1218 GstRTSPResult
gst_rtsp_connection_connect_usec(GstRTSPConnection * conn,gint64 timeout)1219 gst_rtsp_connection_connect_usec (GstRTSPConnection * conn, gint64 timeout)
1220 {
1221 GstRTSPResult result;
1222 GstRTSPMessage response;
1223
1224 memset (&response, 0, sizeof (response));
1225 gst_rtsp_message_init (&response);
1226
1227 result = gst_rtsp_connection_connect_with_response_usec (conn, timeout,
1228 &response);
1229
1230 gst_rtsp_message_unset (&response);
1231
1232 return result;
1233 }
1234
1235 static void
gen_date_string(gchar * date_string,guint len)1236 gen_date_string (gchar * date_string, guint len)
1237 {
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",
1242 "Nov", "Dec"
1243 };
1244 struct tm tm;
1245 time_t t;
1246
1247 time (&t);
1248
1249 #ifdef HAVE_GMTIME_R
1250 gmtime_r (&t, &tm);
1251 #else
1252 tm = *gmtime (&t);
1253 #endif
1254
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);
1258 }
1259
1260 static GstRTSPResult
write_bytes(GOutputStream * stream,const guint8 * buffer,guint * idx,guint size,gboolean block,GCancellable * cancellable)1261 write_bytes (GOutputStream * stream, const guint8 * buffer, guint * idx,
1262 guint size, gboolean block, GCancellable * cancellable)
1263 {
1264 guint left;
1265 gssize r;
1266 GstRTSPResult res;
1267 GError *err = NULL;
1268
1269 if (G_UNLIKELY (*idx > size))
1270 return GST_RTSP_ERROR;
1271
1272 left = size - *idx;
1273
1274 while (left) {
1275 if (block)
1276 r = g_output_stream_write (stream, (gchar *) & buffer[*idx], left,
1277 cancellable, &err);
1278 else
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))
1282 goto error;
1283
1284 left -= r;
1285 *idx += r;
1286 }
1287 return GST_RTSP_OK;
1288
1289 /* ERRORS */
1290 error:
1291 {
1292 if (G_UNLIKELY (r == 0))
1293 return GST_RTSP_EEOF;
1294
1295 if (!g_error_matches (err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
1296 GST_WARNING ("%s", err->message);
1297 else
1298 GST_DEBUG ("%s", err->message);
1299
1300 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1301 g_clear_error (&err);
1302 return res;
1303 }
1304 }
1305
1306 /* NOTE: This changes the values of vectors if multiple iterations are needed! */
1307 #if GLIB_CHECK_VERSION(2, 59, 1)
1308 static GstRTSPResult
writev_bytes(GOutputStream * stream,GOutputVector * vectors,gint n_vectors,gsize * bytes_written,gboolean block,GCancellable * cancellable)1309 writev_bytes (GOutputStream * stream, GOutputVector * vectors, gint n_vectors,
1310 gsize * bytes_written, gboolean block, GCancellable * cancellable)
1311 {
1312 gsize _bytes_written = 0;
1313 gsize written;
1314 GstRTSPResult ret;
1315 GError *err = NULL;
1316 GPollableReturn res = G_POLLABLE_RETURN_OK;
1317
1318 while (n_vectors > 0) {
1319 if (block) {
1320 if (G_UNLIKELY (!g_output_stream_writev (stream, vectors, n_vectors,
1321 &written, cancellable, &err))) {
1322 /* This will never return G_IO_ERROR_WOULD_BLOCK */
1323 res = G_POLLABLE_RETURN_FAILED;
1324 goto error;
1325 }
1326 } else {
1327 res =
1328 g_pollable_output_stream_writev_nonblocking (G_POLLABLE_OUTPUT_STREAM
1329 (stream), vectors, n_vectors, &written, cancellable, &err);
1330
1331 if (res != G_POLLABLE_RETURN_OK) {
1332 g_assert (written == 0);
1333 goto error;
1334 }
1335 }
1336 _bytes_written += written;
1337
1338 /* skip vectors that have been written in full */
1339 while (written > 0 && written >= vectors[0].size) {
1340 written -= vectors[0].size;
1341 ++vectors;
1342 --n_vectors;
1343 }
1344
1345 /* skip partially written vector data */
1346 if (written > 0) {
1347 vectors[0].size -= written;
1348 vectors[0].buffer = ((guint8 *) vectors[0].buffer) + written;
1349 }
1350 }
1351
1352 *bytes_written = _bytes_written;
1353
1354 return GST_RTSP_OK;
1355
1356 /* ERRORS */
1357 error:
1358 {
1359 *bytes_written = _bytes_written;
1360
1361 if (err)
1362 GST_WARNING ("%s", err->message);
1363 if (res == G_POLLABLE_RETURN_WOULD_BLOCK) {
1364 g_assert (!err);
1365 return GST_RTSP_EINTR;
1366 } else if (G_UNLIKELY (written == 0)) {
1367 g_clear_error (&err);
1368 return GST_RTSP_EEOF;
1369 }
1370
1371 ret = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1372 g_clear_error (&err);
1373 return ret;
1374 }
1375 }
1376 #else
1377 static GstRTSPResult
writev_bytes(GOutputStream * stream,GOutputVector * vectors,gint n_vectors,gsize * bytes_written,gboolean block,GCancellable * cancellable)1378 writev_bytes (GOutputStream * stream, GOutputVector * vectors, gint n_vectors,
1379 gsize * bytes_written, gboolean block, GCancellable * cancellable)
1380 {
1381 gsize _bytes_written = 0;
1382 guint written;
1383 gint i;
1384 GstRTSPResult res = GST_RTSP_OK;
1385
1386 for (i = 0; i < n_vectors; i++) {
1387 written = 0;
1388 res =
1389 write_bytes (stream, vectors[i].buffer, &written, vectors[i].size,
1390 block, cancellable);
1391 _bytes_written += written;
1392 if (G_UNLIKELY (res != GST_RTSP_OK))
1393 break;
1394 }
1395
1396 *bytes_written = _bytes_written;
1397
1398 return res;
1399 }
1400 #endif
1401
1402 static gint
fill_raw_bytes(GstRTSPConnection * conn,guint8 * buffer,guint size,gboolean block,GError ** err)1403 fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1404 gboolean block, GError ** err)
1405 {
1406 gint out = 0;
1407
1408 if (G_UNLIKELY (conn->initial_buffer != NULL)) {
1409 gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
1410
1411 out = MIN (left, size);
1412 memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
1413
1414 if (left == (gsize) out) {
1415 g_free (conn->initial_buffer);
1416 conn->initial_buffer = NULL;
1417 conn->initial_buffer_offset = 0;
1418 } else
1419 conn->initial_buffer_offset += out;
1420 }
1421
1422 if (G_LIKELY (size > (guint) out)) {
1423 gssize r;
1424 gsize count = size - out;
1425 if (block)
1426 r = g_input_stream_read (conn->input_stream, (gchar *) & buffer[out],
1427 count, conn->may_cancel ? conn->cancellable : NULL, err);
1428 else
1429 r = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM
1430 (conn->input_stream), (gchar *) & buffer[out], count,
1431 conn->may_cancel ? conn->cancellable : NULL, err);
1432
1433 if (G_UNLIKELY (r < 0)) {
1434 if (out == 0) {
1435 /* propagate the error */
1436 out = r;
1437 } else {
1438 /* we have some data ignore error */
1439 g_clear_error (err);
1440 }
1441 } else
1442 out += r;
1443 }
1444
1445 return out;
1446 }
1447
1448 static gint
fill_bytes(GstRTSPConnection * conn,guint8 * buffer,guint size,gboolean block,GError ** err)1449 fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size,
1450 gboolean block, GError ** err)
1451 {
1452 DecodeCtx *ctx = conn->ctxp;
1453 gint out = 0;
1454
1455 if (ctx) {
1456 while (size > 0) {
1457 guint8 in[sizeof (ctx->out) * 4 / 3];
1458 gint r;
1459
1460 while (size > 0 && ctx->cout < ctx->coutl) {
1461 /* we have some leftover bytes */
1462 *buffer++ = ctx->out[ctx->cout++];
1463 size--;
1464 out++;
1465 }
1466
1467 /* got what we needed? */
1468 if (size == 0)
1469 break;
1470
1471 /* try to read more bytes */
1472 r = fill_raw_bytes (conn, in, sizeof (in), block, err);
1473 if (r <= 0) {
1474 if (out == 0) {
1475 out = r;
1476 } else {
1477 /* we have some data ignore error */
1478 g_clear_error (err);
1479 }
1480 break;
1481 }
1482
1483 ctx->cout = 0;
1484 ctx->coutl =
1485 g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
1486 &ctx->save);
1487 }
1488 } else {
1489 out = fill_raw_bytes (conn, buffer, size, block, err);
1490 }
1491
1492 return out;
1493 }
1494
1495 static GstRTSPResult
read_bytes(GstRTSPConnection * conn,guint8 * buffer,guint * idx,guint size,gboolean block)1496 read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1497 gboolean block)
1498 {
1499 guint left;
1500 gint r;
1501 GstRTSPResult res;
1502 GError *err = NULL;
1503
1504 if (G_UNLIKELY (*idx > size))
1505 return GST_RTSP_ERROR;
1506
1507 left = size - *idx;
1508
1509 while (left) {
1510 r = fill_bytes (conn, &buffer[*idx], left, block, &err);
1511 if (G_UNLIKELY (r <= 0))
1512 goto error;
1513
1514 left -= r;
1515 *idx += r;
1516 }
1517 return GST_RTSP_OK;
1518
1519 /* ERRORS */
1520 error:
1521 {
1522 if (G_UNLIKELY (r == 0))
1523 return GST_RTSP_EEOF;
1524
1525 GST_DEBUG ("%s", err->message);
1526 res = gst_rtsp_result_from_g_io_error (err, GST_RTSP_ESYS);
1527 g_clear_error (&err);
1528 return res;
1529 }
1530 }
1531
1532 /* The code below tries to handle clients using \r, \n or \r\n to indicate the
1533 * end of a line. It even does its best to handle clients which mix them (even
1534 * though this is a really stupid idea (tm).) It also handles Line White Space
1535 * (LWS), where a line end followed by whitespace is considered LWS. This is
1536 * the method used in RTSP (and HTTP) to break long lines.
1537 */
1538 static GstRTSPResult
read_line(GstRTSPConnection * conn,guint8 * buffer,guint * idx,guint size,gboolean block)1539 read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size,
1540 gboolean block)
1541 {
1542 GstRTSPResult res;
1543
1544 while (TRUE) {
1545 guint8 c;
1546 guint i;
1547
1548 if (conn->read_ahead == READ_AHEAD_EOH) {
1549 /* the last call to read_line() already determined that we have reached
1550 * the end of the headers, so convey that information now */
1551 conn->read_ahead = 0;
1552 break;
1553 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1554 /* the last call to read_line() left off after having read \r\n */
1555 c = '\n';
1556 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1557 /* the last call to read_line() left off after having read \r\n\r */
1558 c = '\r';
1559 } else if (conn->read_ahead != 0) {
1560 /* the last call to read_line() left us with a character to start with */
1561 c = (guint8) conn->read_ahead;
1562 conn->read_ahead = 0;
1563 } else {
1564 /* read the next character */
1565 i = 0;
1566 res = read_bytes (conn, &c, &i, 1, block);
1567 if (G_UNLIKELY (res != GST_RTSP_OK))
1568 return res;
1569 }
1570
1571 /* special treatment of line endings */
1572 if (c == '\r' || c == '\n') {
1573 guint8 read_ahead;
1574
1575 retry:
1576 /* need to read ahead one more character to know what to do... */
1577 i = 0;
1578 res = read_bytes (conn, &read_ahead, &i, 1, block);
1579 if (G_UNLIKELY (res != GST_RTSP_OK))
1580 return res;
1581
1582 if (read_ahead == ' ' || read_ahead == '\t') {
1583 if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1584 /* got \r\n\r followed by whitespace, treat it as a normal line
1585 * followed by one starting with LWS */
1586 conn->read_ahead = read_ahead;
1587 break;
1588 } else {
1589 /* got LWS, change the line ending to a space and continue */
1590 c = ' ';
1591 conn->read_ahead = read_ahead;
1592 }
1593 } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
1594 if (read_ahead == '\r' || read_ahead == '\n') {
1595 /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
1596 conn->read_ahead = READ_AHEAD_EOH;
1597 break;
1598 } else {
1599 /* got \r\n\r followed by something else, this is not really
1600 * supported since we have probably just eaten the first character
1601 * of the body or the next message, so just ignore the second \r
1602 * and live with it... */
1603 conn->read_ahead = read_ahead;
1604 break;
1605 }
1606 } else if (conn->read_ahead == READ_AHEAD_CRLF) {
1607 if (read_ahead == '\r') {
1608 /* got \r\n\r so far, need one more character... */
1609 conn->read_ahead = READ_AHEAD_CRLFCR;
1610 goto retry;
1611 } else if (read_ahead == '\n') {
1612 /* got \r\n\n, treat it as the end of the headers */
1613 conn->read_ahead = READ_AHEAD_EOH;
1614 break;
1615 } else {
1616 /* found the end of a line, keep read_ahead for the next line */
1617 conn->read_ahead = read_ahead;
1618 break;
1619 }
1620 } else if (c == read_ahead) {
1621 /* got double \r or \n, treat it as the end of the headers */
1622 conn->read_ahead = READ_AHEAD_EOH;
1623 break;
1624 } else if (c == '\r' && read_ahead == '\n') {
1625 /* got \r\n so far, still need more to know what to do... */
1626 conn->read_ahead = READ_AHEAD_CRLF;
1627 goto retry;
1628 } else {
1629 /* found the end of a line, keep read_ahead for the next line */
1630 conn->read_ahead = read_ahead;
1631 break;
1632 }
1633 }
1634
1635 if (G_LIKELY (*idx < size - 1))
1636 buffer[(*idx)++] = c;
1637 }
1638 buffer[*idx] = '\0';
1639
1640 return GST_RTSP_OK;
1641 }
1642
1643 static void
set_read_socket_timeout(GstRTSPConnection * conn,gint64 timeout)1644 set_read_socket_timeout (GstRTSPConnection * conn, gint64 timeout)
1645 {
1646 GstClockTime to_nsecs;
1647 guint to_secs;
1648
1649 g_mutex_lock (&conn->socket_use_mutex);
1650
1651 g_assert (!conn->read_socket_used);
1652 conn->read_socket_used = TRUE;
1653
1654 to_nsecs = timeout * 1000;
1655 to_secs = (to_nsecs + GST_SECOND - 1) / GST_SECOND;
1656
1657 if (to_secs > g_socket_get_timeout (conn->read_socket)) {
1658 g_socket_set_timeout (conn->read_socket, to_secs);
1659 }
1660
1661 g_mutex_unlock (&conn->socket_use_mutex);
1662 }
1663
1664 static void
set_write_socket_timeout(GstRTSPConnection * conn,gint64 timeout)1665 set_write_socket_timeout (GstRTSPConnection * conn, gint64 timeout)
1666 {
1667 GstClockTime to_nsecs;
1668 guint to_secs;
1669
1670 g_mutex_lock (&conn->socket_use_mutex);
1671
1672 g_assert (!conn->write_socket_used);
1673 conn->write_socket_used = TRUE;
1674
1675 to_nsecs = timeout * 1000;
1676 to_secs = (to_nsecs + GST_SECOND - 1) / GST_SECOND;
1677
1678 if (to_secs > g_socket_get_timeout (conn->write_socket)) {
1679 g_socket_set_timeout (conn->write_socket, to_secs);
1680 }
1681
1682 g_mutex_unlock (&conn->socket_use_mutex);
1683 }
1684
1685 static void
clear_read_socket_timeout(GstRTSPConnection * conn)1686 clear_read_socket_timeout (GstRTSPConnection * conn)
1687 {
1688 g_mutex_lock (&conn->socket_use_mutex);
1689
1690 conn->read_socket_used = FALSE;
1691 if (conn->read_socket != conn->write_socket || !conn->write_socket_used) {
1692 g_socket_set_timeout (conn->read_socket, 0);
1693 }
1694
1695 g_mutex_unlock (&conn->socket_use_mutex);
1696 }
1697
1698 static void
clear_write_socket_timeout(GstRTSPConnection * conn)1699 clear_write_socket_timeout (GstRTSPConnection * conn)
1700 {
1701 g_mutex_lock (&conn->socket_use_mutex);
1702
1703 conn->write_socket_used = FALSE;
1704 if (conn->write_socket != conn->read_socket || !conn->read_socket_used) {
1705 g_socket_set_timeout (conn->write_socket, 0);
1706 }
1707
1708 g_mutex_unlock (&conn->socket_use_mutex);
1709 }
1710
1711 /**
1712 * gst_rtsp_connection_write_usec:
1713 * @conn: a #GstRTSPConnection
1714 * @data: the data to write
1715 * @size: the size of @data
1716 * @timeout: a timeout value or 0
1717 *
1718 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
1719 * the specified @timeout. @timeout can be 0, in which case this function
1720 * might block forever.
1721 *
1722 * This function can be cancelled with gst_rtsp_connection_flush().
1723 *
1724 * Returns: #GST_RTSP_OK on success.
1725 *
1726 * Since: 1.18
1727 */
1728 /* FIXME 2.0: This should've been static! */
1729 GstRTSPResult
gst_rtsp_connection_write_usec(GstRTSPConnection * conn,const guint8 * data,guint size,gint64 timeout)1730 gst_rtsp_connection_write_usec (GstRTSPConnection * conn, const guint8 * data,
1731 guint size, gint64 timeout)
1732 {
1733 guint offset;
1734 GstRTSPResult res;
1735
1736 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1737 g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
1738 g_return_val_if_fail (conn->output_stream != NULL, GST_RTSP_EINVAL);
1739
1740 offset = 0;
1741
1742 set_write_socket_timeout (conn, timeout);
1743
1744 res =
1745 write_bytes (conn->output_stream, data, &offset, size, TRUE,
1746 conn->cancellable);
1747
1748 clear_write_socket_timeout (conn);
1749
1750 return res;
1751 }
1752
1753 static gboolean
serialize_message(GstRTSPConnection * conn,GstRTSPMessage * message,GstRTSPSerializedMessage * serialized_message)1754 serialize_message (GstRTSPConnection * conn, GstRTSPMessage * message,
1755 GstRTSPSerializedMessage * serialized_message)
1756 {
1757 GString *str = NULL;
1758
1759 memset (serialized_message, 0, sizeof (*serialized_message));
1760
1761 /* Initially we borrow the body_data / body_buffer fields from
1762 * the message */
1763 serialized_message->borrowed = TRUE;
1764
1765 switch (message->type) {
1766 case GST_RTSP_MESSAGE_REQUEST:
1767 str = g_string_new ("");
1768
1769 /* create request string, add CSeq */
1770 g_string_append_printf (str, "%s %s RTSP/%s\r\n"
1771 "CSeq: %d\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 conn->cseq++);
1776 /* add session id if we have one */
1777 if (conn->session_id[0] != '\0') {
1778 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
1779 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
1780 conn->session_id);
1781 }
1782 /* add any authentication headers */
1783 add_auth_header (conn, message);
1784 break;
1785 case GST_RTSP_MESSAGE_RESPONSE:
1786 str = g_string_new ("");
1787
1788 /* create response string */
1789 g_string_append_printf (str, "RTSP/%s %d %s\r\n",
1790 gst_rtsp_version_as_text (message->type_data.response.version),
1791 message->type_data.response.code, message->type_data.response.reason);
1792 break;
1793 case GST_RTSP_MESSAGE_HTTP_REQUEST:
1794 str = g_string_new ("");
1795
1796 /* create request string */
1797 g_string_append_printf (str, "%s %s HTTP/%s\r\n",
1798 gst_rtsp_method_as_text (message->type_data.request.method),
1799 message->type_data.request.uri,
1800 gst_rtsp_version_as_text (message->type_data.request.version));
1801 /* add any authentication headers */
1802 add_auth_header (conn, message);
1803 break;
1804 case GST_RTSP_MESSAGE_HTTP_RESPONSE:
1805 str = g_string_new ("");
1806
1807 /* create response string */
1808 g_string_append_printf (str, "HTTP/%s %d %s\r\n",
1809 gst_rtsp_version_as_text (message->type_data.request.version),
1810 message->type_data.response.code, message->type_data.response.reason);
1811 break;
1812 case GST_RTSP_MESSAGE_DATA:
1813 {
1814 guint8 *data_header = serialized_message->data_header;
1815
1816 /* prepare data header */
1817 data_header[0] = '$';
1818 data_header[1] = message->type_data.data.channel;
1819 data_header[2] = (message->body_size >> 8) & 0xff;
1820 data_header[3] = message->body_size & 0xff;
1821
1822 /* create serialized message with header and data */
1823 serialized_message->data_is_data_header = TRUE;
1824 serialized_message->data_size = 4;
1825
1826 if (message->body) {
1827 serialized_message->body_data = message->body;
1828 serialized_message->body_data_size = message->body_size;
1829 } else {
1830 g_assert (message->body_buffer != NULL);
1831 serialized_message->body_buffer = message->body_buffer;
1832 }
1833 break;
1834 }
1835 default:
1836 g_string_free (str, TRUE);
1837 g_return_val_if_reached (FALSE);
1838 break;
1839 }
1840
1841 /* append headers and body */
1842 if (message->type != GST_RTSP_MESSAGE_DATA) {
1843 gchar date_string[100];
1844
1845 g_assert (str != NULL);
1846
1847 gen_date_string (date_string, sizeof (date_string));
1848
1849 /* add date header */
1850 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
1851 gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
1852
1853 /* append headers */
1854 gst_rtsp_message_append_headers (message, str);
1855
1856 /* append Content-Length and body if needed */
1857 if (message->body_size > 0) {
1858 gchar *len;
1859
1860 len = g_strdup_printf ("%d", message->body_size);
1861 g_string_append_printf (str, "%s: %s\r\n",
1862 gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
1863 g_free (len);
1864 /* header ends here */
1865 g_string_append (str, "\r\n");
1866
1867 if (message->body) {
1868 serialized_message->body_data = message->body;
1869 serialized_message->body_data_size = message->body_size;
1870 } else {
1871 g_assert (message->body_buffer != NULL);
1872 serialized_message->body_buffer = message->body_buffer;
1873 }
1874 } else {
1875 /* just end headers */
1876 g_string_append (str, "\r\n");
1877 }
1878
1879 serialized_message->data_size = str->len;
1880 serialized_message->data = (guint8 *) g_string_free (str, FALSE);
1881 }
1882
1883 return TRUE;
1884 }
1885
1886 /**
1887 * gst_rtsp_connection_send_usec:
1888 * @conn: a #GstRTSPConnection
1889 * @message: the message to send
1890 * @timeout: a timeout value in microseconds
1891 *
1892 * Attempt to send @message to the connected @conn, blocking up to
1893 * the specified @timeout. @timeout can be 0, in which case this function
1894 * might block forever.
1895 *
1896 * This function can be cancelled with gst_rtsp_connection_flush().
1897 *
1898 * Returns: #GST_RTSP_OK on success.
1899 *
1900 * Since: 1.18
1901 */
1902 GstRTSPResult
gst_rtsp_connection_send_usec(GstRTSPConnection * conn,GstRTSPMessage * message,gint64 timeout)1903 gst_rtsp_connection_send_usec (GstRTSPConnection * conn,
1904 GstRTSPMessage * message, gint64 timeout)
1905 {
1906 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1907 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
1908
1909 return gst_rtsp_connection_send_messages_usec (conn, message, 1, timeout);
1910 }
1911
1912 /**
1913 * gst_rtsp_connection_send_messages_usec:
1914 * @conn: a #GstRTSPConnection
1915 * @messages: (array length=n_messages): the messages to send
1916 * @n_messages: the number of messages to send
1917 * @timeout: a timeout value in microseconds
1918 *
1919 * Attempt to send @messages to the connected @conn, blocking up to
1920 * the specified @timeout. @timeout can be 0, in which case this function
1921 * might block forever.
1922 *
1923 * This function can be cancelled with gst_rtsp_connection_flush().
1924 *
1925 * Returns: #GST_RTSP_OK on Since.
1926 *
1927 * Since: 1.18
1928 */
1929 GstRTSPResult
gst_rtsp_connection_send_messages_usec(GstRTSPConnection * conn,GstRTSPMessage * messages,guint n_messages,gint64 timeout)1930 gst_rtsp_connection_send_messages_usec (GstRTSPConnection * conn,
1931 GstRTSPMessage * messages, guint n_messages, gint64 timeout)
1932 {
1933 GstRTSPResult res;
1934 GstRTSPSerializedMessage *serialized_messages;
1935 GOutputVector *vectors;
1936 GstMapInfo *map_infos;
1937 guint n_vectors, n_memories;
1938 gint i, j, k;
1939 gsize bytes_to_write, bytes_written;
1940
1941 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
1942 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
1943
1944 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
1945 memset (serialized_messages, 0,
1946 sizeof (GstRTSPSerializedMessage) * n_messages);
1947
1948 for (i = 0, n_vectors = 0, n_memories = 0, bytes_to_write = 0; i < n_messages;
1949 i++) {
1950 if (G_UNLIKELY (!serialize_message (conn, &messages[i],
1951 &serialized_messages[i])))
1952 goto no_message;
1953
1954 if (conn->tunneled) {
1955 gint state = 0, save = 0;
1956 gchar *base64_buffer, *out_buffer;
1957 gsize written = 0;
1958 gsize in_length;
1959
1960 in_length = serialized_messages[i].data_size;
1961 if (serialized_messages[i].body_data)
1962 in_length += serialized_messages[i].body_data_size;
1963 else if (serialized_messages[i].body_buffer)
1964 in_length += gst_buffer_get_size (serialized_messages[i].body_buffer);
1965
1966 in_length = (in_length / 3 + 1) * 4 + 4 + 1;
1967 base64_buffer = out_buffer = g_malloc0 (in_length);
1968
1969 written =
1970 g_base64_encode_step (serialized_messages[i].data_is_data_header ?
1971 serialized_messages[i].data_header : serialized_messages[i].data,
1972 serialized_messages[i].data_size, FALSE, out_buffer, &state, &save);
1973 out_buffer += written;
1974
1975 if (serialized_messages[i].body_data) {
1976 written =
1977 g_base64_encode_step (serialized_messages[i].body_data,
1978 serialized_messages[i].body_data_size, FALSE, out_buffer, &state,
1979 &save);
1980 out_buffer += written;
1981 } else if (serialized_messages[i].body_buffer) {
1982 guint j, n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
1983
1984 for (j = 0; j < n; j++) {
1985 GstMemory *mem =
1986 gst_buffer_peek_memory (serialized_messages[i].body_buffer, j);
1987 GstMapInfo map;
1988
1989 gst_memory_map (mem, &map, GST_MAP_READ);
1990
1991 written = g_base64_encode_step (map.data, map.size,
1992 FALSE, out_buffer, &state, &save);
1993 out_buffer += written;
1994
1995 gst_memory_unmap (mem, &map);
1996 }
1997 }
1998
1999 written = g_base64_encode_close (FALSE, out_buffer, &state, &save);
2000 out_buffer += written;
2001
2002 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
2003 memset (&serialized_messages[i], 0, sizeof (serialized_messages[i]));
2004
2005 serialized_messages[i].data = (guint8 *) base64_buffer;
2006 serialized_messages[i].data_size = (out_buffer - base64_buffer);
2007 n_vectors++;
2008 } else {
2009 n_vectors++;
2010 if (serialized_messages[i].body_data) {
2011 n_vectors++;
2012 } else if (serialized_messages[i].body_buffer) {
2013 n_vectors += gst_buffer_n_memory (serialized_messages[i].body_buffer);
2014 n_memories += gst_buffer_n_memory (serialized_messages[i].body_buffer);
2015 }
2016 }
2017 }
2018
2019 vectors = g_newa (GOutputVector, n_vectors);
2020 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
2021
2022 for (i = 0, j = 0, k = 0; i < n_messages; i++) {
2023 vectors[j].buffer = serialized_messages[i].data_is_data_header ?
2024 serialized_messages[i].data_header : serialized_messages[i].data;
2025 vectors[j].size = serialized_messages[i].data_size;
2026 bytes_to_write += vectors[j].size;
2027 j++;
2028
2029 if (serialized_messages[i].body_data) {
2030 vectors[j].buffer = serialized_messages[i].body_data;
2031 vectors[j].size = serialized_messages[i].body_data_size;
2032 bytes_to_write += vectors[j].size;
2033 j++;
2034 } else if (serialized_messages[i].body_buffer) {
2035 gint l, n;
2036
2037 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
2038 for (l = 0; l < n; l++) {
2039 GstMemory *mem =
2040 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
2041
2042 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
2043 vectors[j].buffer = map_infos[k].data;
2044 vectors[j].size = map_infos[k].size;
2045 bytes_to_write += vectors[j].size;
2046
2047 k++;
2048 j++;
2049 }
2050 }
2051 }
2052
2053 /* write request: this is synchronous */
2054 set_write_socket_timeout (conn, timeout);
2055
2056 res =
2057 writev_bytes (conn->output_stream, vectors, n_vectors, &bytes_written,
2058 TRUE, conn->cancellable);
2059
2060 clear_write_socket_timeout (conn);
2061
2062 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
2063
2064 /* free everything */
2065 for (i = 0, k = 0; i < n_messages; i++) {
2066 if (serialized_messages[i].body_buffer) {
2067 gint l, n;
2068
2069 n = gst_buffer_n_memory (serialized_messages[i].body_buffer);
2070 for (l = 0; l < n; l++) {
2071 GstMemory *mem =
2072 gst_buffer_peek_memory (serialized_messages[i].body_buffer, l);
2073
2074 gst_memory_unmap (mem, &map_infos[k]);
2075 k++;
2076 }
2077 }
2078
2079 g_free (serialized_messages[i].data);
2080 }
2081
2082 return res;
2083
2084 no_message:
2085 {
2086 for (i = 0; i < n_messages; i++) {
2087 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
2088 }
2089 g_warning ("Wrong message");
2090 return GST_RTSP_EINVAL;
2091 }
2092 }
2093
2094 static GstRTSPResult
parse_string(gchar * dest,gint size,gchar ** src)2095 parse_string (gchar * dest, gint size, gchar ** src)
2096 {
2097 GstRTSPResult res = GST_RTSP_OK;
2098 gint idx;
2099
2100 idx = 0;
2101 /* skip spaces */
2102 while (g_ascii_isspace (**src))
2103 (*src)++;
2104
2105 while (!g_ascii_isspace (**src) && **src != '\0') {
2106 if (idx < size - 1)
2107 dest[idx++] = **src;
2108 else
2109 res = GST_RTSP_EPARSE;
2110 (*src)++;
2111 }
2112 if (size > 0)
2113 dest[idx] = '\0';
2114
2115 return res;
2116 }
2117
2118 static GstRTSPResult
parse_protocol_version(gchar * protocol,GstRTSPMsgType * type,GstRTSPVersion * version)2119 parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
2120 GstRTSPVersion * version)
2121 {
2122 GstRTSPVersion rversion;
2123 GstRTSPResult res = GST_RTSP_OK;
2124 gchar *ver;
2125
2126 if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
2127 guint major;
2128 guint minor;
2129 gchar dummychar;
2130
2131 *ver++ = '\0';
2132
2133 /* the version number must be formatted as X.Y with nothing following */
2134 if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
2135 res = GST_RTSP_EPARSE;
2136
2137 rversion = major * 0x10 + minor;
2138 if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
2139
2140 if (rversion != GST_RTSP_VERSION_1_0 && rversion != GST_RTSP_VERSION_2_0) {
2141 *version = GST_RTSP_VERSION_INVALID;
2142 res = GST_RTSP_ERROR;
2143 }
2144 } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
2145 if (*type == GST_RTSP_MESSAGE_REQUEST)
2146 *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
2147 else if (*type == GST_RTSP_MESSAGE_RESPONSE)
2148 *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
2149
2150 if (rversion != GST_RTSP_VERSION_1_0 &&
2151 rversion != GST_RTSP_VERSION_1_1 && rversion != GST_RTSP_VERSION_2_0)
2152 res = GST_RTSP_ERROR;
2153 } else
2154 res = GST_RTSP_EPARSE;
2155 } else
2156 res = GST_RTSP_EPARSE;
2157
2158 if (res == GST_RTSP_OK)
2159 *version = rversion;
2160
2161 return res;
2162 }
2163
2164 static GstRTSPResult
parse_response_status(guint8 * buffer,GstRTSPMessage * msg)2165 parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
2166 {
2167 GstRTSPResult res = GST_RTSP_OK;
2168 GstRTSPResult res2;
2169 gchar versionstr[20];
2170 gchar codestr[4];
2171 gint code;
2172 gchar *bptr;
2173
2174 bptr = (gchar *) buffer;
2175
2176 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2177 res = GST_RTSP_EPARSE;
2178
2179 if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
2180 res = GST_RTSP_EPARSE;
2181 code = atoi (codestr);
2182 if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
2183 res = GST_RTSP_EPARSE;
2184
2185 while (g_ascii_isspace (*bptr))
2186 bptr++;
2187
2188 if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
2189 NULL) != GST_RTSP_OK))
2190 res = GST_RTSP_EPARSE;
2191
2192 res2 = parse_protocol_version (versionstr, &msg->type,
2193 &msg->type_data.response.version);
2194 if (G_LIKELY (res == GST_RTSP_OK))
2195 res = res2;
2196
2197 return res;
2198 }
2199
2200 static GstRTSPResult
parse_request_line(guint8 * buffer,GstRTSPMessage * msg)2201 parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
2202 {
2203 GstRTSPResult res = GST_RTSP_OK;
2204 GstRTSPResult res2;
2205 gchar versionstr[20];
2206 gchar methodstr[20];
2207 gchar urlstr[4096];
2208 gchar *bptr;
2209 GstRTSPMethod method;
2210
2211 bptr = (gchar *) buffer;
2212
2213 if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
2214 res = GST_RTSP_EPARSE;
2215 method = gst_rtsp_find_method (methodstr);
2216
2217 if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
2218 res = GST_RTSP_EPARSE;
2219 if (G_UNLIKELY (*urlstr == '\0'))
2220 res = GST_RTSP_EPARSE;
2221
2222 if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
2223 res = GST_RTSP_EPARSE;
2224
2225 if (G_UNLIKELY (*bptr != '\0'))
2226 res = GST_RTSP_EPARSE;
2227
2228 if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
2229 urlstr) != GST_RTSP_OK))
2230 res = GST_RTSP_EPARSE;
2231
2232 res2 = parse_protocol_version (versionstr, &msg->type,
2233 &msg->type_data.request.version);
2234 if (G_LIKELY (res == GST_RTSP_OK))
2235 res = res2;
2236
2237 if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
2238 /* GET and POST are not allowed as RTSP methods */
2239 if (msg->type_data.request.method == GST_RTSP_GET ||
2240 msg->type_data.request.method == GST_RTSP_POST) {
2241 msg->type_data.request.method = GST_RTSP_INVALID;
2242 if (res == GST_RTSP_OK)
2243 res = GST_RTSP_ERROR;
2244 }
2245 } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2246 /* only GET and POST are allowed as HTTP methods */
2247 if (msg->type_data.request.method != GST_RTSP_GET &&
2248 msg->type_data.request.method != GST_RTSP_POST) {
2249 msg->type_data.request.method = GST_RTSP_INVALID;
2250 if (res == GST_RTSP_OK)
2251 res = GST_RTSP_ERROR;
2252 }
2253 }
2254
2255 return res;
2256 }
2257
2258 /* parsing lines means reading a Key: Value pair */
2259 static GstRTSPResult
parse_line(guint8 * buffer,GstRTSPMessage * msg)2260 parse_line (guint8 * buffer, GstRTSPMessage * msg)
2261 {
2262 GstRTSPHeaderField field;
2263 gchar *line = (gchar *) buffer;
2264 gchar *field_name = NULL;
2265 gchar *value;
2266
2267 if ((value = strchr (line, ':')) == NULL || value == line)
2268 goto parse_error;
2269
2270 /* trim space before the colon */
2271 if (value[-1] == ' ')
2272 value[-1] = '\0';
2273
2274 /* replace the colon with a NUL */
2275 *value++ = '\0';
2276
2277 /* find the header */
2278 field = gst_rtsp_find_header_field (line);
2279 /* custom header not present in the list of pre-defined headers */
2280 if (field == GST_RTSP_HDR_INVALID)
2281 field_name = line;
2282
2283 /* split up the value in multiple key:value pairs if it contains comma(s) */
2284 while (*value != '\0') {
2285 gchar *next_value;
2286 gchar *comma = NULL;
2287 gboolean quoted = FALSE;
2288 guint comment = 0;
2289
2290 /* trim leading space */
2291 if (*value == ' ')
2292 value++;
2293
2294 /* for headers which may not appear multiple times, and thus may not
2295 * contain multiple values on the same line, we can short-circuit the loop
2296 * below and the entire value results in just one key:value pair*/
2297 if (!gst_rtsp_header_allow_multiple (field))
2298 next_value = value + strlen (value);
2299 else
2300 next_value = value;
2301
2302 /* find the next value, taking special care of quotes and comments */
2303 while (*next_value != '\0') {
2304 if ((quoted || comment != 0) && *next_value == '\\' &&
2305 next_value[1] != '\0')
2306 next_value++;
2307 else if (comment == 0 && *next_value == '"')
2308 quoted = !quoted;
2309 else if (!quoted && *next_value == '(')
2310 comment++;
2311 else if (comment != 0 && *next_value == ')')
2312 comment--;
2313 else if (!quoted && comment == 0) {
2314 /* To quote RFC 2068: "User agents MUST take special care in parsing
2315 * the WWW-Authenticate field value if it contains more than one
2316 * challenge, or if more than one WWW-Authenticate header field is
2317 * provided, since the contents of a challenge may itself contain a
2318 * comma-separated list of authentication parameters."
2319 *
2320 * What this means is that we cannot just look for an unquoted comma
2321 * when looking for multiple values in Proxy-Authenticate and
2322 * WWW-Authenticate headers. Instead we need to look for the sequence
2323 * "comma [space] token space token" before we can split after the
2324 * comma...
2325 */
2326 if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
2327 field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
2328 if (*next_value == ',') {
2329 if (next_value[1] == ' ') {
2330 /* skip any space following the comma so we do not mistake it for
2331 * separating between two tokens */
2332 next_value++;
2333 }
2334 comma = next_value;
2335 } else if (*next_value == ' ' && next_value[1] != ',' &&
2336 next_value[1] != '=' && comma != NULL) {
2337 next_value = comma;
2338 comma = NULL;
2339 break;
2340 }
2341 } else if (*next_value == ',')
2342 break;
2343 }
2344
2345 next_value++;
2346 }
2347
2348 if (msg->type == GST_RTSP_MESSAGE_REQUEST && field == GST_RTSP_HDR_SESSION) {
2349 /* The timeout parameter is only allowed in a session response header
2350 * but some clients send it as part of the session request header.
2351 * Ignore everything from the semicolon to the end of the line. */
2352 next_value = value;
2353 while (*next_value != '\0') {
2354 if (*next_value == ';') {
2355 break;
2356 }
2357 next_value++;
2358 }
2359 }
2360
2361 /* trim space */
2362 if (value != next_value && next_value[-1] == ' ')
2363 next_value[-1] = '\0';
2364
2365 if (*next_value != '\0')
2366 *next_value++ = '\0';
2367
2368 /* add the key:value pair */
2369 if (*value != '\0') {
2370 if (field != GST_RTSP_HDR_INVALID)
2371 gst_rtsp_message_add_header (msg, field, value);
2372 else
2373 gst_rtsp_message_add_header_by_name (msg, field_name, value);
2374 }
2375
2376 value = next_value;
2377 }
2378
2379 return GST_RTSP_OK;
2380
2381 /* ERRORS */
2382 parse_error:
2383 {
2384 return GST_RTSP_EPARSE;
2385 }
2386 }
2387
2388 /* convert all consecutive whitespace to a single space */
2389 static void
normalize_line(guint8 * buffer)2390 normalize_line (guint8 * buffer)
2391 {
2392 while (*buffer) {
2393 if (g_ascii_isspace (*buffer)) {
2394 guint8 *tmp;
2395
2396 *buffer++ = ' ';
2397 for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
2398 }
2399 if (buffer != tmp)
2400 memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
2401 } else {
2402 buffer++;
2403 }
2404 }
2405 }
2406
2407 static gboolean
cseq_validation(GstRTSPConnection * conn,GstRTSPMessage * message)2408 cseq_validation (GstRTSPConnection * conn, GstRTSPMessage * message)
2409 {
2410 gchar *cseq_header;
2411 gint64 cseq = 0;
2412 GstRTSPResult res;
2413
2414 if (message->type == GST_RTSP_MESSAGE_RESPONSE ||
2415 message->type == GST_RTSP_MESSAGE_REQUEST) {
2416 if ((res = gst_rtsp_message_get_header (message, GST_RTSP_HDR_CSEQ,
2417 &cseq_header, 0)) != GST_RTSP_OK) {
2418 /* rfc2326 This field MUST be present in all RTSP req and resp */
2419 goto invalid_format;
2420 }
2421
2422 errno = 0;
2423 cseq = g_ascii_strtoll (cseq_header, NULL, 10);
2424 if (errno != 0 || cseq < 0) {
2425 /* CSeq has no valid value */
2426 goto invalid_format;
2427 }
2428
2429 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2430 (conn->cseq == 0 || conn->cseq < cseq)) {
2431 /* Response CSeq can't be higher than the number of outgoing requests
2432 * neither is a response valid if no request has been made */
2433 goto invalid_format;
2434 }
2435 }
2436 return GST_RTSP_OK;
2437
2438 invalid_format:
2439 {
2440 return GST_RTSP_EPARSE;
2441 }
2442 }
2443
2444 /* returns:
2445 * GST_RTSP_OK when a complete message was read.
2446 * GST_RTSP_EEOF: when the read socket is closed
2447 * GST_RTSP_EINTR: when more data is needed.
2448 * GST_RTSP_..: some other error occurred.
2449 */
2450 static GstRTSPResult
build_next(GstRTSPBuilder * builder,GstRTSPMessage * message,GstRTSPConnection * conn,gboolean block)2451 build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
2452 GstRTSPConnection * conn, gboolean block)
2453 {
2454 GstRTSPResult res;
2455
2456 while (TRUE) {
2457 switch (builder->state) {
2458 case STATE_START:
2459 {
2460 guint8 c;
2461
2462 builder->offset = 0;
2463 res =
2464 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1,
2465 block);
2466 if (res != GST_RTSP_OK)
2467 goto done;
2468
2469 c = builder->buffer[0];
2470
2471 /* we have 1 bytes now and we can see if this is a data message or
2472 * not */
2473 if (c == '$') {
2474 /* data message, prepare for the header */
2475 builder->state = STATE_DATA_HEADER;
2476 conn->may_cancel = FALSE;
2477 } else if (c == '\n' || c == '\r') {
2478 /* skip \n and \r */
2479 builder->offset = 0;
2480 } else {
2481 builder->line = 0;
2482 builder->state = STATE_READ_LINES;
2483 conn->may_cancel = FALSE;
2484 }
2485 break;
2486 }
2487 case STATE_DATA_HEADER:
2488 {
2489 res =
2490 read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4,
2491 block);
2492 if (res != GST_RTSP_OK)
2493 goto done;
2494
2495 gst_rtsp_message_init_data (message, builder->buffer[1]);
2496
2497 builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
2498 builder->body_data = g_malloc (builder->body_len + 1);
2499 builder->body_data[builder->body_len] = '\0';
2500 builder->offset = 0;
2501 builder->state = STATE_DATA_BODY;
2502 break;
2503 }
2504 case STATE_DATA_BODY:
2505 {
2506 res =
2507 read_bytes (conn, builder->body_data, &builder->offset,
2508 builder->body_len, block);
2509 if (res != GST_RTSP_OK)
2510 goto done;
2511
2512 /* we have the complete body now, store in the message adjusting the
2513 * length to include the trailing '\0' */
2514 gst_rtsp_message_take_body (message,
2515 (guint8 *) builder->body_data, builder->body_len + 1);
2516 builder->body_data = NULL;
2517 builder->body_len = 0;
2518
2519 builder->state = STATE_END;
2520 break;
2521 }
2522 case STATE_READ_LINES:
2523 {
2524 res = read_line (conn, builder->buffer, &builder->offset,
2525 sizeof (builder->buffer), block);
2526 if (res != GST_RTSP_OK)
2527 goto done;
2528
2529 /* we have a regular response */
2530 if (builder->buffer[0] == '\0') {
2531 gchar *hdrval;
2532 gint64 content_length_parsed = 0;
2533
2534 /* empty line, end of message header */
2535 /* see if there is a Content-Length header, but ignore it if this
2536 * is a POST request with an x-sessioncookie header */
2537 if (gst_rtsp_message_get_header (message,
2538 GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
2539 (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
2540 message->type_data.request.method != GST_RTSP_POST ||
2541 gst_rtsp_message_get_header (message,
2542 GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
2543 /* there is, prepare to read the body */
2544 errno = 0;
2545 content_length_parsed = g_ascii_strtoll (hdrval, NULL, 10);
2546 if (errno != 0 || content_length_parsed < 0) {
2547 res = GST_RTSP_EPARSE;
2548 goto invalid_body_len;
2549 } else if (content_length_parsed > conn->content_length_limit) {
2550 res = GST_RTSP_ENOMEM;
2551 goto invalid_body_len;
2552 }
2553 builder->body_len = content_length_parsed;
2554 builder->body_data = g_try_malloc (builder->body_len + 1);
2555 /* we can't do much here, we need the length to know how many bytes
2556 * we need to read next and when allocation fails, we can't read the payload. */
2557 if (builder->body_data == NULL) {
2558 res = GST_RTSP_ENOMEM;
2559 goto invalid_body_len;
2560 }
2561
2562 builder->body_data[builder->body_len] = '\0';
2563 builder->offset = 0;
2564 builder->state = STATE_DATA_BODY;
2565 } else {
2566 builder->state = STATE_END;
2567 }
2568 break;
2569 }
2570
2571 /* we have a line */
2572 normalize_line (builder->buffer);
2573 if (builder->line == 0) {
2574 /* first line, check for response status */
2575 if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
2576 memcmp (builder->buffer, "HTTP", 4) == 0) {
2577 builder->status = parse_response_status (builder->buffer, message);
2578 } else {
2579 builder->status = parse_request_line (builder->buffer, message);
2580 }
2581 } else {
2582 /* else just parse the line */
2583 res = parse_line (builder->buffer, message);
2584 if (res != GST_RTSP_OK)
2585 builder->status = res;
2586 }
2587 if (builder->status != GST_RTSP_OK) {
2588 res = builder->status;
2589 goto invalid_format;
2590 }
2591
2592 builder->line++;
2593 builder->offset = 0;
2594 break;
2595 }
2596 case STATE_END:
2597 {
2598 gchar *session_cookie;
2599 gchar *session_id;
2600
2601 conn->may_cancel = TRUE;
2602
2603 if ((res = cseq_validation (conn, message)) != GST_RTSP_OK) {
2604 /* message don't comply with rfc2326 regarding CSeq */
2605 goto invalid_format;
2606 }
2607
2608 if (message->type == GST_RTSP_MESSAGE_DATA) {
2609 /* data messages don't have headers */
2610 res = GST_RTSP_OK;
2611 goto done;
2612 }
2613
2614 /* save the tunnel session in the connection */
2615 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
2616 !conn->manual_http &&
2617 conn->tstate == TUNNEL_STATE_NONE &&
2618 gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
2619 &session_cookie, 0) == GST_RTSP_OK) {
2620 strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
2621 conn->tunnelid[TUNNELID_LEN - 1] = '\0';
2622 conn->tunneled = TRUE;
2623 }
2624
2625 /* save session id in the connection for further use */
2626 if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
2627 gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
2628 &session_id, 0) == GST_RTSP_OK) {
2629 gint maxlen, i;
2630
2631 maxlen = sizeof (conn->session_id) - 1;
2632 /* the sessionid can have attributes marked with ;
2633 * Make sure we strip them */
2634 for (i = 0; i < maxlen && session_id[i] != '\0'; i++) {
2635 if (session_id[i] == ';') {
2636 maxlen = i;
2637 /* parse timeout */
2638 do {
2639 i++;
2640 } while (g_ascii_isspace (session_id[i]));
2641 if (g_str_has_prefix (&session_id[i], "timeout=")) {
2642 gint to;
2643
2644 /* if we parsed something valid, configure */
2645 if ((to = atoi (&session_id[i + 8])) > 0)
2646 conn->timeout = to;
2647 }
2648 break;
2649 }
2650 }
2651
2652 /* make sure to not overflow */
2653 if (conn->remember_session_id) {
2654 strncpy (conn->session_id, session_id, maxlen);
2655 conn->session_id[maxlen] = '\0';
2656 }
2657 }
2658 res = builder->status;
2659 goto done;
2660 }
2661 default:
2662 res = GST_RTSP_ERROR;
2663 goto done;
2664 }
2665 }
2666 done:
2667 conn->may_cancel = TRUE;
2668 return res;
2669
2670 /* ERRORS */
2671 invalid_body_len:
2672 {
2673 conn->may_cancel = TRUE;
2674 GST_DEBUG ("could not allocate body");
2675 return res;
2676 }
2677 invalid_format:
2678 {
2679 conn->may_cancel = TRUE;
2680 GST_DEBUG ("could not parse");
2681 return res;
2682 }
2683 }
2684
2685 /**
2686 * gst_rtsp_connection_read_usec:
2687 * @conn: a #GstRTSPConnection
2688 * @data: the data to read
2689 * @size: the size of @data
2690 * @timeout: a timeout value in microseconds
2691 *
2692 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
2693 * the specified @timeout. @timeout can be 0, in which case this function
2694 * might block forever.
2695 *
2696 * This function can be cancelled with gst_rtsp_connection_flush().
2697 *
2698 * Returns: #GST_RTSP_OK on success.
2699 *
2700 * Since: 1.18
2701 */
2702 GstRTSPResult
gst_rtsp_connection_read_usec(GstRTSPConnection * conn,guint8 * data,guint size,gint64 timeout)2703 gst_rtsp_connection_read_usec (GstRTSPConnection * conn, guint8 * data,
2704 guint size, gint64 timeout)
2705 {
2706 guint offset;
2707 GstRTSPResult res;
2708
2709 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2710 g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
2711 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2712
2713 if (G_UNLIKELY (size == 0))
2714 return GST_RTSP_OK;
2715
2716 offset = 0;
2717
2718 /* configure timeout if any */
2719 set_read_socket_timeout (conn, timeout);
2720
2721 res = read_bytes (conn, data, &offset, size, TRUE);
2722
2723 clear_read_socket_timeout (conn);
2724
2725 return res;
2726 }
2727
2728 static GstRTSPMessage *
gen_tunnel_reply(GstRTSPConnection * conn,GstRTSPStatusCode code,const GstRTSPMessage * request)2729 gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
2730 const GstRTSPMessage * request)
2731 {
2732 GstRTSPMessage *msg;
2733 GstRTSPResult res;
2734
2735 if (gst_rtsp_status_as_text (code) == NULL)
2736 code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
2737
2738 GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
2739 no_message);
2740
2741 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
2742 "GStreamer RTSP Server");
2743 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
2744 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
2745 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
2746
2747 if (code == GST_RTSP_STS_OK) {
2748 /* add the local ip address to the tunnel reply, this is where the client
2749 * should send the POST request to */
2750 if (conn->local_ip)
2751 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
2752 conn->local_ip);
2753 gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
2754 "application/x-rtsp-tunnelled");
2755 }
2756
2757 return msg;
2758
2759 /* ERRORS */
2760 no_message:
2761 {
2762 return NULL;
2763 }
2764 }
2765
2766 /**
2767 * gst_rtsp_connection_receive_usec:
2768 * @conn: a #GstRTSPConnection
2769 * @message: the message to read
2770 * @timeout: a timeout value or 0
2771 *
2772 * Attempt to read into @message from the connected @conn, blocking up to
2773 * the specified @timeout. @timeout can be 0, in which case this function
2774 * might block forever.
2775 *
2776 * This function can be cancelled with gst_rtsp_connection_flush().
2777 *
2778 * Returns: #GST_RTSP_OK on success.
2779 *
2780 * Since: 1.18
2781 */
2782 GstRTSPResult
gst_rtsp_connection_receive_usec(GstRTSPConnection * conn,GstRTSPMessage * message,gint64 timeout)2783 gst_rtsp_connection_receive_usec (GstRTSPConnection * conn,
2784 GstRTSPMessage * message, gint64 timeout)
2785 {
2786 GstRTSPResult res;
2787 GstRTSPBuilder builder;
2788
2789 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2790 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2791 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2792
2793 /* configure timeout if any */
2794 set_read_socket_timeout (conn, timeout);
2795
2796 memset (&builder, 0, sizeof (GstRTSPBuilder));
2797 res = build_next (&builder, message, conn, TRUE);
2798
2799 clear_read_socket_timeout (conn);
2800
2801 if (G_UNLIKELY (res != GST_RTSP_OK))
2802 goto read_error;
2803
2804 if (!conn->manual_http) {
2805 if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
2806 if (conn->tstate == TUNNEL_STATE_NONE &&
2807 message->type_data.request.method == GST_RTSP_GET) {
2808 GstRTSPMessage *response;
2809
2810 conn->tstate = TUNNEL_STATE_GET;
2811
2812 /* tunnel GET request, we can reply now */
2813 response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
2814 res = gst_rtsp_connection_send_usec (conn, response, timeout);
2815 gst_rtsp_message_free (response);
2816 if (res == GST_RTSP_OK)
2817 res = GST_RTSP_ETGET;
2818 goto cleanup;
2819 } else if (conn->tstate == TUNNEL_STATE_NONE &&
2820 message->type_data.request.method == GST_RTSP_POST) {
2821 conn->tstate = TUNNEL_STATE_POST;
2822
2823 /* tunnel POST request, the caller now has to link the two
2824 * connections. */
2825 res = GST_RTSP_ETPOST;
2826 goto cleanup;
2827 } else {
2828 res = GST_RTSP_EPARSE;
2829 goto cleanup;
2830 }
2831 } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
2832 res = GST_RTSP_EPARSE;
2833 goto cleanup;
2834 }
2835 }
2836
2837 /* we have a message here */
2838 build_reset (&builder);
2839
2840 return GST_RTSP_OK;
2841
2842 /* ERRORS */
2843 read_error:
2844 cleanup:
2845 {
2846 build_reset (&builder);
2847 gst_rtsp_message_unset (message);
2848 return res;
2849 }
2850 }
2851
2852 /**
2853 * gst_rtsp_connection_close:
2854 * @conn: a #GstRTSPConnection
2855 *
2856 * Close the connected @conn. After this call, the connection is in the same
2857 * state as when it was first created.
2858 *
2859 * Returns: #GST_RTSP_OK on success.
2860 */
2861 GstRTSPResult
gst_rtsp_connection_close(GstRTSPConnection * conn)2862 gst_rtsp_connection_close (GstRTSPConnection * conn)
2863 {
2864 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2865
2866 /* last unref closes the connection we don't want to explicitly close here
2867 * because these sockets might have been provided at construction */
2868 if (conn->stream0) {
2869 g_object_unref (conn->stream0);
2870 conn->stream0 = NULL;
2871 conn->socket0 = NULL;
2872 }
2873 if (conn->stream1) {
2874 g_object_unref (conn->stream1);
2875 conn->stream1 = NULL;
2876 conn->socket1 = NULL;
2877 }
2878
2879 /* these were owned by the stream */
2880 conn->input_stream = NULL;
2881 conn->output_stream = NULL;
2882 conn->control_stream = NULL;
2883
2884 g_free (conn->remote_ip);
2885 conn->remote_ip = NULL;
2886 g_free (conn->local_ip);
2887 conn->local_ip = NULL;
2888
2889 conn->read_ahead = 0;
2890
2891 g_free (conn->initial_buffer);
2892 conn->initial_buffer = NULL;
2893 conn->initial_buffer_offset = 0;
2894
2895 conn->write_socket = NULL;
2896 conn->read_socket = NULL;
2897 conn->write_socket_used = FALSE;
2898 conn->read_socket_used = FALSE;
2899 conn->tunneled = FALSE;
2900 conn->tstate = TUNNEL_STATE_NONE;
2901 conn->ctxp = NULL;
2902 g_free (conn->username);
2903 conn->username = NULL;
2904 g_free (conn->passwd);
2905 conn->passwd = NULL;
2906 gst_rtsp_connection_clear_auth_params (conn);
2907 conn->timeout = 60;
2908 conn->cseq = 0;
2909 conn->session_id[0] = '\0';
2910
2911 return GST_RTSP_OK;
2912 }
2913
2914 /**
2915 * gst_rtsp_connection_free:
2916 * @conn: a #GstRTSPConnection
2917 *
2918 * Close and free @conn.
2919 *
2920 * Returns: #GST_RTSP_OK on success.
2921 */
2922 GstRTSPResult
gst_rtsp_connection_free(GstRTSPConnection * conn)2923 gst_rtsp_connection_free (GstRTSPConnection * conn)
2924 {
2925 GstRTSPResult res;
2926
2927 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2928
2929 res = gst_rtsp_connection_close (conn);
2930
2931 if (conn->cancellable)
2932 g_object_unref (conn->cancellable);
2933 if (conn->client)
2934 g_object_unref (conn->client);
2935 if (conn->tls_database)
2936 g_object_unref (conn->tls_database);
2937 if (conn->tls_interaction)
2938 g_object_unref (conn->tls_interaction);
2939 if (conn->accept_certificate_destroy_notify)
2940 conn->
2941 accept_certificate_destroy_notify (conn->accept_certificate_user_data);
2942
2943 g_timer_destroy (conn->timer);
2944 gst_rtsp_url_free (conn->url);
2945 g_free (conn->proxy_host);
2946 g_free (conn);
2947
2948 return res;
2949 }
2950
2951 /**
2952 * gst_rtsp_connection_poll_usec:
2953 * @conn: a #GstRTSPConnection
2954 * @events: a bitmask of #GstRTSPEvent flags to check
2955 * @revents: location for result flags
2956 * @timeout: a timeout in microseconds
2957 *
2958 * Wait up to the specified @timeout for the connection to become available for
2959 * at least one of the operations specified in @events. When the function returns
2960 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
2961 * @conn.
2962 *
2963 * @timeout can be 0, in which case this function might block forever.
2964 *
2965 * This function can be cancelled with gst_rtsp_connection_flush().
2966 *
2967 * Returns: #GST_RTSP_OK on success.
2968 *
2969 * Since: 1.18
2970 */
2971 GstRTSPResult
gst_rtsp_connection_poll_usec(GstRTSPConnection * conn,GstRTSPEvent events,GstRTSPEvent * revents,gint64 timeout)2972 gst_rtsp_connection_poll_usec (GstRTSPConnection * conn, GstRTSPEvent events,
2973 GstRTSPEvent * revents, gint64 timeout)
2974 {
2975 GMainContext *ctx;
2976 GSource *rs, *ws, *ts;
2977 GIOCondition condition;
2978
2979 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
2980 g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
2981 g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
2982 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
2983 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
2984
2985 ctx = g_main_context_new ();
2986
2987 /* configure timeout if any */
2988 if (timeout) {
2989 ts = g_timeout_source_new (timeout / 1000);
2990 g_source_set_dummy_callback (ts);
2991 g_source_attach (ts, ctx);
2992 g_source_unref (ts);
2993 }
2994
2995 if (events & GST_RTSP_EV_READ) {
2996 rs = g_socket_create_source (conn->read_socket, G_IO_IN | G_IO_PRI,
2997 conn->cancellable);
2998 g_source_set_dummy_callback (rs);
2999 g_source_attach (rs, ctx);
3000 g_source_unref (rs);
3001 }
3002
3003 if (events & GST_RTSP_EV_WRITE) {
3004 ws = g_socket_create_source (conn->write_socket, G_IO_OUT,
3005 conn->cancellable);
3006 g_source_set_dummy_callback (ws);
3007 g_source_attach (ws, ctx);
3008 g_source_unref (ws);
3009 }
3010
3011 /* Returns after handling all pending events */
3012 while (!g_main_context_iteration (ctx, TRUE));
3013
3014 g_main_context_unref (ctx);
3015
3016 *revents = 0;
3017 if (events & GST_RTSP_EV_READ) {
3018 condition = g_socket_condition_check (conn->read_socket,
3019 G_IO_IN | G_IO_PRI);
3020 if ((condition & G_IO_IN) || (condition & G_IO_PRI))
3021 *revents |= GST_RTSP_EV_READ;
3022 }
3023 if (events & GST_RTSP_EV_WRITE) {
3024 condition = g_socket_condition_check (conn->write_socket, G_IO_OUT);
3025 if ((condition & G_IO_OUT))
3026 *revents |= GST_RTSP_EV_WRITE;
3027 }
3028
3029 if (*revents == 0)
3030 return GST_RTSP_ETIMEOUT;
3031
3032 return GST_RTSP_OK;
3033 }
3034
3035 /**
3036 * gst_rtsp_connection_next_timeout_usec:
3037 * @conn: a #GstRTSPConnection
3038 *
3039 * Calculate the next timeout for @conn
3040 *
3041 * Returns: #the next timeout in microseconds
3042 *
3043 * Since: 1.18
3044 */
3045 gint64
gst_rtsp_connection_next_timeout_usec(GstRTSPConnection * conn)3046 gst_rtsp_connection_next_timeout_usec (GstRTSPConnection * conn)
3047 {
3048 gdouble elapsed;
3049 gulong usec;
3050 gint ctimeout;
3051 gint64 timeout = 0;
3052
3053 g_return_val_if_fail (conn != NULL, 1);
3054
3055 ctimeout = conn->timeout;
3056 if (ctimeout >= 20) {
3057 /* Because we should act before the timeout we timeout 5
3058 * seconds in advance. */
3059 ctimeout -= 5;
3060 } else if (ctimeout >= 5) {
3061 /* else timeout 20% earlier */
3062 ctimeout -= ctimeout / 5;
3063 } else if (ctimeout >= 1) {
3064 /* else timeout 1 second earlier */
3065 ctimeout -= 1;
3066 }
3067
3068 elapsed = g_timer_elapsed (conn->timer, &usec);
3069 if (elapsed >= ctimeout) {
3070 timeout = 0;
3071 } else {
3072 gint64 sec = ctimeout - elapsed;
3073 if (usec <= G_USEC_PER_SEC)
3074 usec = G_USEC_PER_SEC - usec;
3075 else
3076 usec = 0;
3077 timeout = usec + sec * G_USEC_PER_SEC;
3078 }
3079
3080 return timeout;
3081 }
3082
3083 /**
3084 * gst_rtsp_connection_reset_timeout:
3085 * @conn: a #GstRTSPConnection
3086 *
3087 * Reset the timeout of @conn.
3088 *
3089 * Returns: #GST_RTSP_OK.
3090 */
3091 GstRTSPResult
gst_rtsp_connection_reset_timeout(GstRTSPConnection * conn)3092 gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
3093 {
3094 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3095
3096 g_timer_start (conn->timer);
3097
3098 return GST_RTSP_OK;
3099 }
3100
3101 /**
3102 * gst_rtsp_connection_flush:
3103 * @conn: a #GstRTSPConnection
3104 * @flush: start or stop the flush
3105 *
3106 * Start or stop the flushing action on @conn. When flushing, all current
3107 * and future actions on @conn will return #GST_RTSP_EINTR until the connection
3108 * is set to non-flushing mode again.
3109 *
3110 * Returns: #GST_RTSP_OK.
3111 */
3112 GstRTSPResult
gst_rtsp_connection_flush(GstRTSPConnection * conn,gboolean flush)3113 gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
3114 {
3115 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3116
3117 if (flush) {
3118 g_cancellable_cancel (conn->cancellable);
3119 } else {
3120 g_object_unref (conn->cancellable);
3121 conn->cancellable = g_cancellable_new ();
3122 }
3123
3124 return GST_RTSP_OK;
3125 }
3126
3127 /**
3128 * gst_rtsp_connection_set_proxy:
3129 * @conn: a #GstRTSPConnection
3130 * @host: the proxy host
3131 * @port: the proxy port
3132 *
3133 * Set the proxy host and port.
3134 *
3135 * Returns: #GST_RTSP_OK.
3136 */
3137 GstRTSPResult
gst_rtsp_connection_set_proxy(GstRTSPConnection * conn,const gchar * host,guint port)3138 gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
3139 const gchar * host, guint port)
3140 {
3141 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3142
3143 g_free (conn->proxy_host);
3144 conn->proxy_host = g_strdup (host);
3145 conn->proxy_port = port;
3146
3147 return GST_RTSP_OK;
3148 }
3149
3150 /**
3151 * gst_rtsp_connection_set_auth:
3152 * @conn: a #GstRTSPConnection
3153 * @method: authentication method
3154 * @user: the user
3155 * @pass: the password
3156 *
3157 * Configure @conn for authentication mode @method with @user and @pass as the
3158 * user and password respectively.
3159 *
3160 * Returns: #GST_RTSP_OK.
3161 */
3162 GstRTSPResult
gst_rtsp_connection_set_auth(GstRTSPConnection * conn,GstRTSPAuthMethod method,const gchar * user,const gchar * pass)3163 gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
3164 GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
3165 {
3166 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3167
3168 if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
3169 || g_strrstr (user, ":") != NULL))
3170 return GST_RTSP_EINVAL;
3171
3172 /* Make sure the username and passwd are being set for authentication */
3173 if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
3174 return GST_RTSP_EINVAL;
3175
3176 /* ":" chars are not allowed in usernames for basic auth */
3177 if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
3178 return GST_RTSP_EINVAL;
3179
3180 g_free (conn->username);
3181 g_free (conn->passwd);
3182
3183 conn->auth_method = method;
3184 conn->username = g_strdup (user);
3185 conn->passwd = g_strdup (pass);
3186
3187 return GST_RTSP_OK;
3188 }
3189
3190 /**
3191 * str_case_hash:
3192 * @key: ASCII string to hash
3193 *
3194 * Hashes @key in a case-insensitive manner.
3195 *
3196 * Returns: the hash code.
3197 **/
3198 static guint
str_case_hash(gconstpointer key)3199 str_case_hash (gconstpointer key)
3200 {
3201 const char *p = key;
3202 guint h = g_ascii_toupper (*p);
3203
3204 if (h)
3205 for (p += 1; *p != '\0'; p++)
3206 h = (h << 5) - h + g_ascii_toupper (*p);
3207
3208 return h;
3209 }
3210
3211 /**
3212 * str_case_equal:
3213 * @v1: an ASCII string
3214 * @v2: another ASCII string
3215 *
3216 * Compares @v1 and @v2 in a case-insensitive manner
3217 *
3218 * Returns: %TRUE if they are equal (modulo case)
3219 **/
3220 static gboolean
str_case_equal(gconstpointer v1,gconstpointer v2)3221 str_case_equal (gconstpointer v1, gconstpointer v2)
3222 {
3223 const char *string1 = v1;
3224 const char *string2 = v2;
3225
3226 return g_ascii_strcasecmp (string1, string2) == 0;
3227 }
3228
3229 /**
3230 * gst_rtsp_connection_set_auth_param:
3231 * @conn: a #GstRTSPConnection
3232 * @param: authentication directive
3233 * @value: value
3234 *
3235 * Setup @conn with authentication directives. This is not necessary for
3236 * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
3237 * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
3238 * in the WWW-Authenticate response header and can include realm, domain,
3239 * nonce, opaque, stale, algorithm, qop as per RFC2617.
3240 */
3241 void
gst_rtsp_connection_set_auth_param(GstRTSPConnection * conn,const gchar * param,const gchar * value)3242 gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
3243 const gchar * param, const gchar * value)
3244 {
3245 g_return_if_fail (conn != NULL);
3246 g_return_if_fail (param != NULL);
3247
3248 if (conn->auth_params == NULL) {
3249 conn->auth_params =
3250 g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
3251 }
3252 g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
3253 }
3254
3255 /**
3256 * gst_rtsp_connection_clear_auth_params:
3257 * @conn: a #GstRTSPConnection
3258 *
3259 * Clear the list of authentication directives stored in @conn.
3260 */
3261 void
gst_rtsp_connection_clear_auth_params(GstRTSPConnection * conn)3262 gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
3263 {
3264 g_return_if_fail (conn != NULL);
3265
3266 if (conn->auth_params != NULL) {
3267 g_hash_table_destroy (conn->auth_params);
3268 conn->auth_params = NULL;
3269 }
3270 }
3271
3272 static GstRTSPResult
set_qos_dscp(GSocket * socket,guint qos_dscp)3273 set_qos_dscp (GSocket * socket, guint qos_dscp)
3274 {
3275 #ifndef IP_TOS
3276 GST_FIXME ("IP_TOS socket option is not defined, not setting dscp");
3277 return GST_RTSP_OK;
3278 #else
3279 gint fd;
3280 union gst_sockaddr sa;
3281 socklen_t slen = sizeof (sa);
3282 gint af;
3283 gint tos;
3284
3285 if (!socket)
3286 return GST_RTSP_OK;
3287
3288 fd = g_socket_get_fd (socket);
3289 if (getsockname (fd, &sa.sa, &slen) < 0)
3290 goto no_getsockname;
3291
3292 af = sa.sa.sa_family;
3293
3294 /* if this is an IPv4-mapped address then do IPv4 QoS */
3295 if (af == AF_INET6) {
3296 if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
3297 af = AF_INET;
3298 }
3299
3300 /* extract and shift 6 bits of the DSCP */
3301 tos = (qos_dscp & 0x3f) << 2;
3302
3303 #ifdef G_OS_WIN32
3304 # define SETSOCKOPT_ARG4_TYPE const char *
3305 #else
3306 # define SETSOCKOPT_ARG4_TYPE const void *
3307 #endif
3308
3309 switch (af) {
3310 case AF_INET:
3311 if (setsockopt (fd, IPPROTO_IP, IP_TOS, (SETSOCKOPT_ARG4_TYPE) & tos,
3312 sizeof (tos)) < 0)
3313 goto no_setsockopt;
3314 break;
3315 case AF_INET6:
3316 #ifdef IPV6_TCLASS
3317 if (setsockopt (fd, IPPROTO_IPV6, IPV6_TCLASS,
3318 (SETSOCKOPT_ARG4_TYPE) & tos, sizeof (tos)) < 0)
3319 goto no_setsockopt;
3320 break;
3321 #endif
3322 default:
3323 goto wrong_family;
3324 }
3325
3326 return GST_RTSP_OK;
3327
3328 /* ERRORS */
3329 no_getsockname:
3330 no_setsockopt:
3331 {
3332 return GST_RTSP_ESYS;
3333 }
3334 wrong_family:
3335 {
3336 return GST_RTSP_ERROR;
3337 }
3338 #endif
3339 }
3340
3341 /**
3342 * gst_rtsp_connection_set_qos_dscp:
3343 * @conn: a #GstRTSPConnection
3344 * @qos_dscp: DSCP value
3345 *
3346 * Configure @conn to use the specified DSCP value.
3347 *
3348 * Returns: #GST_RTSP_OK on success.
3349 */
3350 GstRTSPResult
gst_rtsp_connection_set_qos_dscp(GstRTSPConnection * conn,guint qos_dscp)3351 gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
3352 {
3353 GstRTSPResult res;
3354
3355 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3356 g_return_val_if_fail (conn->read_socket != NULL, GST_RTSP_EINVAL);
3357 g_return_val_if_fail (conn->write_socket != NULL, GST_RTSP_EINVAL);
3358
3359 res = set_qos_dscp (conn->socket0, qos_dscp);
3360 if (res == GST_RTSP_OK)
3361 res = set_qos_dscp (conn->socket1, qos_dscp);
3362
3363 return res;
3364 }
3365
3366 /**
3367 * gst_rtsp_connection_set_content_length_limit:
3368 * @conn: a #GstRTSPConnection
3369 * @limit: Content-Length limit
3370 *
3371 * Configure @conn to use the specified Content-Length limit.
3372 * Both requests and responses are validated. If content-length is
3373 * exceeded, ENOMEM error will be returned.
3374 *
3375 * Since: 1.18
3376 */
3377 void
gst_rtsp_connection_set_content_length_limit(GstRTSPConnection * conn,guint limit)3378 gst_rtsp_connection_set_content_length_limit (GstRTSPConnection * conn,
3379 guint limit)
3380 {
3381 g_return_if_fail (conn != NULL);
3382
3383 conn->content_length_limit = limit;
3384 }
3385
3386 /**
3387 * gst_rtsp_connection_get_url:
3388 * @conn: a #GstRTSPConnection
3389 *
3390 * Retrieve the URL of the other end of @conn.
3391 *
3392 * Returns: The URL. This value remains valid until the
3393 * connection is freed.
3394 */
3395 GstRTSPUrl *
gst_rtsp_connection_get_url(const GstRTSPConnection * conn)3396 gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
3397 {
3398 g_return_val_if_fail (conn != NULL, NULL);
3399
3400 return conn->url;
3401 }
3402
3403 /**
3404 * gst_rtsp_connection_get_ip:
3405 * @conn: a #GstRTSPConnection
3406 *
3407 * Retrieve the IP address of the other end of @conn.
3408 *
3409 * Returns: The IP address as a string. this value remains valid until the
3410 * connection is closed.
3411 */
3412 const gchar *
gst_rtsp_connection_get_ip(const GstRTSPConnection * conn)3413 gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
3414 {
3415 g_return_val_if_fail (conn != NULL, NULL);
3416
3417 return conn->remote_ip;
3418 }
3419
3420 /**
3421 * gst_rtsp_connection_set_ip:
3422 * @conn: a #GstRTSPConnection
3423 * @ip: an ip address
3424 *
3425 * Set the IP address of the server.
3426 */
3427 void
gst_rtsp_connection_set_ip(GstRTSPConnection * conn,const gchar * ip)3428 gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
3429 {
3430 g_return_if_fail (conn != NULL);
3431
3432 g_free (conn->remote_ip);
3433 conn->remote_ip = g_strdup (ip);
3434 }
3435
3436 /**
3437 * gst_rtsp_connection_get_read_socket:
3438 * @conn: a #GstRTSPConnection
3439 *
3440 * Get the file descriptor for reading.
3441 *
3442 * Returns: (transfer none): the file descriptor used for reading or %NULL on
3443 * error. The file descriptor remains valid until the connection is closed.
3444 */
3445 GSocket *
gst_rtsp_connection_get_read_socket(const GstRTSPConnection * conn)3446 gst_rtsp_connection_get_read_socket (const GstRTSPConnection * conn)
3447 {
3448 g_return_val_if_fail (conn != NULL, NULL);
3449 g_return_val_if_fail (conn->read_socket != NULL, NULL);
3450
3451 return conn->read_socket;
3452 }
3453
3454 /**
3455 * gst_rtsp_connection_get_write_socket:
3456 * @conn: a #GstRTSPConnection
3457 *
3458 * Get the file descriptor for writing.
3459 *
3460 * Returns: (transfer none): the file descriptor used for writing or NULL on
3461 * error. The file descriptor remains valid until the connection is closed.
3462 */
3463 GSocket *
gst_rtsp_connection_get_write_socket(const GstRTSPConnection * conn)3464 gst_rtsp_connection_get_write_socket (const GstRTSPConnection * conn)
3465 {
3466 g_return_val_if_fail (conn != NULL, NULL);
3467 g_return_val_if_fail (conn->write_socket != NULL, NULL);
3468
3469 return conn->write_socket;
3470 }
3471
3472 /**
3473 * gst_rtsp_connection_set_http_mode:
3474 * @conn: a #GstRTSPConnection
3475 * @enable: %TRUE to enable manual HTTP mode
3476 *
3477 * By setting the HTTP mode to %TRUE the message parsing will support HTTP
3478 * messages in addition to the RTSP messages. It will also disable the
3479 * automatic handling of setting up an HTTP tunnel.
3480 */
3481 void
gst_rtsp_connection_set_http_mode(GstRTSPConnection * conn,gboolean enable)3482 gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
3483 {
3484 g_return_if_fail (conn != NULL);
3485
3486 conn->manual_http = enable;
3487 }
3488
3489 /**
3490 * gst_rtsp_connection_set_tunneled:
3491 * @conn: a #GstRTSPConnection
3492 * @tunneled: the new state
3493 *
3494 * Set the HTTP tunneling state of the connection. This must be configured before
3495 * the @conn is connected.
3496 */
3497 void
gst_rtsp_connection_set_tunneled(GstRTSPConnection * conn,gboolean tunneled)3498 gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
3499 {
3500 g_return_if_fail (conn != NULL);
3501 g_return_if_fail (conn->read_socket == NULL);
3502 g_return_if_fail (conn->write_socket == NULL);
3503
3504 conn->tunneled = tunneled;
3505 }
3506
3507 /**
3508 * gst_rtsp_connection_is_tunneled:
3509 * @conn: a #GstRTSPConnection
3510 *
3511 * Get the tunneling state of the connection.
3512 *
3513 * Returns: if @conn is using HTTP tunneling.
3514 */
3515 gboolean
gst_rtsp_connection_is_tunneled(const GstRTSPConnection * conn)3516 gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
3517 {
3518 g_return_val_if_fail (conn != NULL, FALSE);
3519
3520 return conn->tunneled;
3521 }
3522
3523 /**
3524 * gst_rtsp_connection_get_tunnelid:
3525 * @conn: a #GstRTSPConnection
3526 *
3527 * Get the tunnel session id the connection.
3528 *
3529 * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
3530 */
3531 const gchar *
gst_rtsp_connection_get_tunnelid(const GstRTSPConnection * conn)3532 gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
3533 {
3534 g_return_val_if_fail (conn != NULL, NULL);
3535
3536 if (!conn->tunneled)
3537 return NULL;
3538
3539 return conn->tunnelid;
3540 }
3541
3542 /**
3543 * gst_rtsp_connection_set_ignore_x_server_reply:
3544 * @conn: a #GstRTSPConnection
3545 * @ignore: %TRUE to ignore the x-server-ip-address header reply or %FALSE to
3546 * comply with it (%FALSE is the default).
3547 *
3548 * Set whether to ignore the x-server-ip-address header reply or not. If the
3549 * header is ignored, the original address will be used instead.
3550 *
3551 * Since: 1.20
3552 */
3553 void
gst_rtsp_connection_set_ignore_x_server_reply(GstRTSPConnection * conn,gboolean ignore)3554 gst_rtsp_connection_set_ignore_x_server_reply (GstRTSPConnection * conn,
3555 gboolean ignore)
3556 {
3557 g_return_if_fail (conn != NULL);
3558
3559 conn->ignore_x_server_reply = ignore;
3560 }
3561
3562 /**
3563 * gst_rtsp_connection_get_ignore_x_server_reply:
3564 * @conn: a #GstRTSPConnection
3565 *
3566 * Get the ignore_x_server_reply value.
3567 *
3568 * Returns: returns %TRUE if the x-server-ip-address header reply will be
3569 * ignored, else returns %FALSE
3570 *
3571 * Since: 1.20
3572 */
3573 gboolean
gst_rtsp_connection_get_ignore_x_server_reply(const GstRTSPConnection * conn)3574 gst_rtsp_connection_get_ignore_x_server_reply (const GstRTSPConnection * conn)
3575 {
3576 g_return_val_if_fail (conn != NULL, FALSE);
3577
3578 return conn->ignore_x_server_reply;
3579 }
3580
3581 /**
3582 * gst_rtsp_connection_do_tunnel:
3583 * @conn: a #GstRTSPConnection
3584 * @conn2: a #GstRTSPConnection or %NULL
3585 *
3586 * If @conn received the first tunnel connection and @conn2 received
3587 * the second tunnel connection, link the two connections together so that
3588 * @conn manages the tunneled connection.
3589 *
3590 * After this call, @conn2 cannot be used anymore and must be freed with
3591 * gst_rtsp_connection_free().
3592 *
3593 * If @conn2 is %NULL then only the base64 decoding context will be setup for
3594 * @conn.
3595 *
3596 * Returns: return GST_RTSP_OK on success.
3597 */
3598 GstRTSPResult
gst_rtsp_connection_do_tunnel(GstRTSPConnection * conn,GstRTSPConnection * conn2)3599 gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
3600 GstRTSPConnection * conn2)
3601 {
3602 g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
3603
3604 if (conn2 != NULL) {
3605 GstRTSPTunnelState ts1 = conn->tstate;
3606 GstRTSPTunnelState ts2 = conn2->tstate;
3607
3608 g_return_val_if_fail ((ts1 == TUNNEL_STATE_GET && ts2 == TUNNEL_STATE_POST)
3609 || (ts1 == TUNNEL_STATE_POST && ts2 == TUNNEL_STATE_GET),
3610 GST_RTSP_EINVAL);
3611 g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
3612 TUNNELID_LEN), GST_RTSP_EINVAL);
3613
3614 /* both connections have socket0 as the read/write socket */
3615 if (ts1 == TUNNEL_STATE_GET) {
3616 /* conn2 is the HTTP POST channel. take its socket and set it as read
3617 * socket in conn */
3618 conn->socket1 = conn2->socket0;
3619 conn->stream1 = conn2->stream0;
3620 conn->input_stream = conn2->input_stream;
3621 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3622 conn2->output_stream = NULL;
3623 } else {
3624 /* conn2 is the HTTP GET channel. take its socket and set it as write
3625 * socket in conn */
3626 conn->socket1 = conn->socket0;
3627 conn->stream1 = conn->stream0;
3628 conn->socket0 = conn2->socket0;
3629 conn->stream0 = conn2->stream0;
3630 conn->output_stream = conn2->output_stream;
3631 conn->control_stream = g_io_stream_get_input_stream (conn->stream0);
3632 }
3633
3634 /* clean up some of the state of conn2 */
3635 g_cancellable_cancel (conn2->cancellable);
3636 conn2->write_socket = conn2->read_socket = NULL;
3637 conn2->socket0 = NULL;
3638 conn2->stream0 = NULL;
3639 conn2->socket1 = NULL;
3640 conn2->stream1 = NULL;
3641 conn2->input_stream = NULL;
3642 conn2->control_stream = NULL;
3643 g_object_unref (conn2->cancellable);
3644 conn2->cancellable = NULL;
3645
3646 /* We make socket0 the write socket and socket1 the read socket. */
3647 conn->write_socket = conn->socket0;
3648 conn->read_socket = conn->socket1;
3649
3650 conn->tstate = TUNNEL_STATE_COMPLETE;
3651
3652 g_free (conn->initial_buffer);
3653 conn->initial_buffer = conn2->initial_buffer;
3654 conn2->initial_buffer = NULL;
3655 conn->initial_buffer_offset = conn2->initial_buffer_offset;
3656 }
3657
3658 /* we need base64 decoding for the readfd */
3659 conn->ctx.state = 0;
3660 conn->ctx.save = 0;
3661 conn->ctx.cout = 0;
3662 conn->ctx.coutl = 0;
3663 conn->ctxp = &conn->ctx;
3664
3665 return GST_RTSP_OK;
3666 }
3667
3668 /**
3669 * gst_rtsp_connection_set_remember_session_id:
3670 * @conn: a #GstRTSPConnection
3671 * @remember: %TRUE if the connection should remember the session id
3672 *
3673 * Sets if the #GstRTSPConnection should remember the session id from the last
3674 * response received and force it onto any further requests.
3675 *
3676 * The default value is %TRUE
3677 */
3678
3679 void
gst_rtsp_connection_set_remember_session_id(GstRTSPConnection * conn,gboolean remember)3680 gst_rtsp_connection_set_remember_session_id (GstRTSPConnection * conn,
3681 gboolean remember)
3682 {
3683 conn->remember_session_id = remember;
3684 if (!remember)
3685 conn->session_id[0] = '\0';
3686 }
3687
3688 /**
3689 * gst_rtsp_connection_get_remember_session_id:
3690 * @conn: a #GstRTSPConnection
3691 *
3692 * Returns: %TRUE if the #GstRTSPConnection remembers the session id in the
3693 * last response to set it on any further request.
3694 */
3695
3696 gboolean
gst_rtsp_connection_get_remember_session_id(GstRTSPConnection * conn)3697 gst_rtsp_connection_get_remember_session_id (GstRTSPConnection * conn)
3698 {
3699 return conn->remember_session_id;
3700 }
3701
3702
3703 #define READ_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3704 #define READ_COND (G_IO_IN | READ_ERR)
3705 #define WRITE_ERR (G_IO_HUP | G_IO_ERR | G_IO_NVAL)
3706 #define WRITE_COND (G_IO_OUT | WRITE_ERR)
3707
3708 /* async functions */
3709 struct _GstRTSPWatch
3710 {
3711 GSource source;
3712
3713 GstRTSPConnection *conn;
3714
3715 GstRTSPBuilder builder;
3716 GstRTSPMessage message;
3717
3718 GSource *readsrc;
3719 GSource *writesrc;
3720 GSource *controlsrc;
3721
3722 gboolean keep_running;
3723
3724 /* queued message for transmission */
3725 guint id;
3726 GMutex mutex;
3727 GstQueueArray *messages;
3728 gsize messages_bytes;
3729 guint messages_count;
3730
3731 gsize max_bytes;
3732 guint max_messages;
3733 GCond queue_not_full;
3734 gboolean flushing;
3735
3736 GstRTSPWatchFuncs funcs;
3737
3738 gpointer user_data;
3739 GDestroyNotify notify;
3740 };
3741
3742 #define IS_BACKLOG_FULL(w) (((w)->max_bytes != 0 && (w)->messages_bytes >= (w)->max_bytes) || \
3743 ((w)->max_messages != 0 && (w)->messages_count >= (w)->max_messages))
3744
3745 static gboolean
gst_rtsp_source_prepare(GSource * source,gint * timeout)3746 gst_rtsp_source_prepare (GSource * source, gint * timeout)
3747 {
3748 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3749
3750 if (watch->conn->initial_buffer != NULL)
3751 return TRUE;
3752
3753 *timeout = (watch->conn->timeout * 1000);
3754
3755 return FALSE;
3756 }
3757
3758 static gboolean
gst_rtsp_source_check(GSource * source)3759 gst_rtsp_source_check (GSource * source)
3760 {
3761 return FALSE;
3762 }
3763
3764 static gboolean
gst_rtsp_source_dispatch_read_get_channel(GPollableInputStream * stream,GstRTSPWatch * watch)3765 gst_rtsp_source_dispatch_read_get_channel (GPollableInputStream * stream,
3766 GstRTSPWatch * watch)
3767 {
3768 gssize count;
3769 guint8 buffer[1024];
3770 GError *error = NULL;
3771
3772 /* try to read in order to be able to detect errors, we read 1k in case some
3773 * client actually decides to send data on the GET channel */
3774 count = g_pollable_input_stream_read_nonblocking (stream, buffer, 1024, NULL,
3775 &error);
3776 if (count == 0) {
3777 /* other end closed the socket */
3778 goto eof;
3779 }
3780
3781 if (count < 0) {
3782 GST_DEBUG ("%s", error->message);
3783 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK) ||
3784 g_error_matches (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT)) {
3785 g_clear_error (&error);
3786 goto done;
3787 }
3788 g_clear_error (&error);
3789 goto read_error;
3790 }
3791
3792 /* client sent data on the GET channel, ignore it */
3793
3794 done:
3795 return TRUE;
3796
3797 /* ERRORS */
3798 eof:
3799 {
3800 if (watch->funcs.closed)
3801 watch->funcs.closed (watch, watch->user_data);
3802
3803 /* the read connection was closed, stop the watch now */
3804 watch->keep_running = FALSE;
3805
3806 return FALSE;
3807 }
3808 read_error:
3809 {
3810 if (watch->funcs.error_full)
3811 watch->funcs.error_full (watch, GST_RTSP_ESYS, &watch->message,
3812 0, watch->user_data);
3813 else if (watch->funcs.error)
3814 watch->funcs.error (watch, GST_RTSP_ESYS, watch->user_data);
3815
3816 goto eof;
3817 }
3818 }
3819
3820 static gboolean
gst_rtsp_source_dispatch_read(GPollableInputStream * stream,GstRTSPWatch * watch)3821 gst_rtsp_source_dispatch_read (GPollableInputStream * stream,
3822 GstRTSPWatch * watch)
3823 {
3824 GstRTSPResult res = GST_RTSP_ERROR;
3825 GstRTSPConnection *conn = watch->conn;
3826
3827 /* if this connection was already closed, stop now */
3828 if (G_POLLABLE_INPUT_STREAM (conn->input_stream) != stream)
3829 goto eof;
3830
3831 res = build_next (&watch->builder, &watch->message, conn, FALSE);
3832 if (res == GST_RTSP_EINTR)
3833 goto done;
3834 else if (G_UNLIKELY (res == GST_RTSP_EEOF)) {
3835 g_mutex_lock (&watch->mutex);
3836 if (watch->readsrc) {
3837 if (!g_source_is_destroyed ((GSource *) watch))
3838 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
3839 g_source_unref (watch->readsrc);
3840 watch->readsrc = NULL;
3841 }
3842
3843 if (conn->stream1) {
3844 g_object_unref (conn->stream1);
3845 conn->stream1 = NULL;
3846 conn->socket1 = NULL;
3847 conn->input_stream = NULL;
3848 }
3849 g_mutex_unlock (&watch->mutex);
3850
3851 /* When we are in tunnelled mode, the read socket can be closed and we
3852 * should be prepared for a new POST method to reopen it */
3853 if (conn->tstate == TUNNEL_STATE_COMPLETE) {
3854 /* remove the read connection for the tunnel */
3855 /* we accept a new POST request */
3856 conn->tstate = TUNNEL_STATE_GET;
3857 /* and signal that we lost our tunnel */
3858 if (watch->funcs.tunnel_lost)
3859 res = watch->funcs.tunnel_lost (watch, watch->user_data);
3860 /* we add read source on the write socket able to detect when client closes get channel in tunneled mode */
3861 g_mutex_lock (&watch->mutex);
3862 if (watch->conn->control_stream && !watch->controlsrc) {
3863 watch->controlsrc =
3864 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
3865 (watch->conn->control_stream), NULL);
3866 g_source_set_callback (watch->controlsrc,
3867 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
3868 NULL);
3869 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
3870 }
3871 g_mutex_unlock (&watch->mutex);
3872 goto read_done;
3873 } else
3874 goto eof;
3875 } else if (G_LIKELY (res == GST_RTSP_OK)) {
3876 if (!conn->manual_http &&
3877 watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3878 if (conn->tstate == TUNNEL_STATE_NONE &&
3879 watch->message.type_data.request.method == GST_RTSP_GET) {
3880 GstRTSPMessage *response;
3881 GstRTSPStatusCode code;
3882
3883 conn->tstate = TUNNEL_STATE_GET;
3884
3885 if (watch->funcs.tunnel_start)
3886 code = watch->funcs.tunnel_start (watch, watch->user_data);
3887 else
3888 code = GST_RTSP_STS_OK;
3889
3890 /* queue the response */
3891 response = gen_tunnel_reply (conn, code, &watch->message);
3892 if (watch->funcs.tunnel_http_response)
3893 watch->funcs.tunnel_http_response (watch, &watch->message, response,
3894 watch->user_data);
3895 gst_rtsp_watch_send_message (watch, response, NULL);
3896 gst_rtsp_message_free (response);
3897 goto read_done;
3898 } else if (conn->tstate == TUNNEL_STATE_NONE &&
3899 watch->message.type_data.request.method == GST_RTSP_POST) {
3900 conn->tstate = TUNNEL_STATE_POST;
3901
3902 /* in the callback the connection should be tunneled with the
3903 * GET connection */
3904 if (watch->funcs.tunnel_complete) {
3905 watch->funcs.tunnel_complete (watch, watch->user_data);
3906 }
3907 goto read_done;
3908 }
3909 }
3910 } else
3911 goto read_error;
3912
3913 if (!conn->manual_http) {
3914 /* if manual HTTP support is not enabled, then restore the message to
3915 * what it would have looked like without the support for parsing HTTP
3916 * messages being present */
3917 if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
3918 watch->message.type = GST_RTSP_MESSAGE_REQUEST;
3919 watch->message.type_data.request.method = GST_RTSP_INVALID;
3920 if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
3921 watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
3922 res = GST_RTSP_EPARSE;
3923 } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
3924 watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
3925 if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
3926 watch->message.type_data.response.version = GST_RTSP_VERSION_INVALID;
3927 res = GST_RTSP_EPARSE;
3928 }
3929 }
3930 if (G_LIKELY (res != GST_RTSP_OK))
3931 goto read_error;
3932
3933 if (watch->funcs.message_received)
3934 watch->funcs.message_received (watch, &watch->message, watch->user_data);
3935
3936 read_done:
3937 gst_rtsp_message_unset (&watch->message);
3938 build_reset (&watch->builder);
3939
3940 done:
3941 return TRUE;
3942
3943 /* ERRORS */
3944 eof:
3945 {
3946 if (watch->funcs.closed)
3947 watch->funcs.closed (watch, watch->user_data);
3948
3949 /* we closed the read connection, stop the watch now */
3950 watch->keep_running = FALSE;
3951
3952 /* always stop when the input returns EOF in non-tunneled mode */
3953 return FALSE;
3954 }
3955 read_error:
3956 {
3957 if (watch->funcs.error_full)
3958 watch->funcs.error_full (watch, res, &watch->message,
3959 0, watch->user_data);
3960 else if (watch->funcs.error)
3961 watch->funcs.error (watch, res, watch->user_data);
3962
3963 goto eof;
3964 }
3965 }
3966
3967 static gboolean
gst_rtsp_source_dispatch(GSource * source,GSourceFunc callback G_GNUC_UNUSED,gpointer user_data G_GNUC_UNUSED)3968 gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
3969 gpointer user_data G_GNUC_UNUSED)
3970 {
3971 GstRTSPWatch *watch = (GstRTSPWatch *) source;
3972 GstRTSPConnection *conn = watch->conn;
3973
3974 if (conn->initial_buffer != NULL) {
3975 gst_rtsp_source_dispatch_read (G_POLLABLE_INPUT_STREAM (conn->input_stream),
3976 watch);
3977 }
3978 return watch->keep_running;
3979 }
3980
3981 static gboolean
gst_rtsp_source_dispatch_write(GPollableOutputStream * stream,GstRTSPWatch * watch)3982 gst_rtsp_source_dispatch_write (GPollableOutputStream * stream,
3983 GstRTSPWatch * watch)
3984 {
3985 GstRTSPResult res = GST_RTSP_ERROR;
3986 GstRTSPConnection *conn = watch->conn;
3987
3988 /* if this connection was already closed, stop now */
3989 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
3990 !watch->messages)
3991 goto eof;
3992
3993 g_mutex_lock (&watch->mutex);
3994 do {
3995 guint n_messages = gst_queue_array_get_length (watch->messages);
3996 GOutputVector *vectors;
3997 GstMapInfo *map_infos;
3998 guint *ids;
3999 gsize bytes_to_write, bytes_written;
4000 guint n_vectors, n_memories, n_ids, drop_messages;
4001 gint i, j, l, n_mmap;
4002 GstRTSPSerializedMessage *msg;
4003
4004 /* if this connection was already closed, stop now */
4005 if (G_POLLABLE_OUTPUT_STREAM (conn->output_stream) != stream ||
4006 !watch->messages) {
4007 g_mutex_unlock (&watch->mutex);
4008 goto eof;
4009 }
4010
4011 if (n_messages == 0) {
4012 if (watch->writesrc) {
4013 if (!g_source_is_destroyed ((GSource *) watch))
4014 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
4015 g_source_unref (watch->writesrc);
4016 watch->writesrc = NULL;
4017 /* we create and add the write source again when we actually have
4018 * something to write */
4019
4020 /* since write source is now removed we add read source on the write
4021 * socket instead to be able to detect when client closes get channel
4022 * in tunneled mode */
4023 if (watch->conn->control_stream) {
4024 watch->controlsrc =
4025 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4026 (watch->conn->control_stream), NULL);
4027 g_source_set_callback (watch->controlsrc,
4028 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch,
4029 NULL);
4030 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
4031 } else {
4032 watch->controlsrc = NULL;
4033 }
4034 }
4035 break;
4036 }
4037
4038 for (i = 0, n_vectors = 0, n_memories = 0, n_ids = 0; i < n_messages; i++) {
4039 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4040 if (msg->id != 0)
4041 n_ids++;
4042
4043 if (msg->data_offset < msg->data_size)
4044 n_vectors++;
4045
4046 if (msg->body_data && msg->body_offset < msg->body_data_size) {
4047 n_vectors++;
4048 } else if (msg->body_buffer) {
4049 guint m, n;
4050 guint offset = 0;
4051
4052 n = gst_buffer_n_memory (msg->body_buffer);
4053 for (m = 0; m < n; m++) {
4054 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
4055
4056 /* Skip all memories we already wrote */
4057 if (offset + mem->size <= msg->body_offset) {
4058 offset += mem->size;
4059 continue;
4060 }
4061 offset += mem->size;
4062
4063 n_memories++;
4064 n_vectors++;
4065 }
4066 }
4067 }
4068
4069 vectors = g_newa (GOutputVector, n_vectors);
4070 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
4071 ids = n_ids ? g_newa (guint, n_ids + 1) : NULL;
4072 if (ids)
4073 memset (ids, 0, sizeof (guint) * (n_ids + 1));
4074
4075 for (i = 0, j = 0, n_mmap = 0, l = 0, bytes_to_write = 0; i < n_messages;
4076 i++) {
4077 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4078
4079 if (msg->data_offset < msg->data_size) {
4080 vectors[j].buffer = (msg->data_is_data_header ?
4081 msg->data_header : msg->data) + msg->data_offset;
4082 vectors[j].size = msg->data_size - msg->data_offset;
4083 bytes_to_write += vectors[j].size;
4084 j++;
4085 }
4086
4087 if (msg->body_data) {
4088 if (msg->body_offset < msg->body_data_size) {
4089 vectors[j].buffer = msg->body_data + msg->body_offset;
4090 vectors[j].size = msg->body_data_size - msg->body_offset;
4091 bytes_to_write += vectors[j].size;
4092 j++;
4093 }
4094 } else if (msg->body_buffer) {
4095 guint m, n;
4096 guint offset = 0;
4097 n = gst_buffer_n_memory (msg->body_buffer);
4098 for (m = 0; m < n; m++) {
4099 GstMemory *mem = gst_buffer_peek_memory (msg->body_buffer, m);
4100 guint off;
4101
4102 /* Skip all memories we already wrote */
4103 if (offset + mem->size <= msg->body_offset) {
4104 offset += mem->size;
4105 continue;
4106 }
4107
4108 if (offset < msg->body_offset)
4109 off = msg->body_offset - offset;
4110 else
4111 off = 0;
4112
4113 offset += mem->size;
4114
4115 g_assert (off < mem->size);
4116
4117 gst_memory_map (mem, &map_infos[n_mmap], GST_MAP_READ);
4118 vectors[j].buffer = map_infos[n_mmap].data + off;
4119 vectors[j].size = map_infos[n_mmap].size - off;
4120 bytes_to_write += vectors[j].size;
4121
4122 n_mmap++;
4123 j++;
4124 }
4125 }
4126 }
4127
4128 res =
4129 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4130 &bytes_written, FALSE, watch->conn->cancellable);
4131 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4132
4133 /* First unmap all memories here, this simplifies the code below
4134 * as we don't have to skip all memories that were already written
4135 * before */
4136 for (i = 0; i < n_mmap; i++) {
4137 gst_memory_unmap (map_infos[i].memory, &map_infos[i]);
4138 }
4139
4140 if (bytes_written == bytes_to_write) {
4141 /* fast path, just unmap all memories, free memory, drop all messages and notify them */
4142 l = 0;
4143 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4144 if (msg->id) {
4145 ids[l] = msg->id;
4146 l++;
4147 }
4148
4149 gst_rtsp_serialized_message_clear (msg);
4150 }
4151
4152 g_assert (watch->messages_bytes >= bytes_written);
4153 watch->messages_bytes -= bytes_written;
4154 } else if (bytes_written > 0) {
4155 /* not done, let's skip all messages that were sent already and free them */
4156 for (i = 0, drop_messages = 0; i < n_messages; i++) {
4157 msg = gst_queue_array_peek_nth_struct (watch->messages, i);
4158
4159 if (bytes_written >= msg->data_size - msg->data_offset) {
4160 guint body_size;
4161
4162 /* all data of this message is sent, check body and otherwise
4163 * skip the whole message for next time */
4164 bytes_written -= (msg->data_size - msg->data_offset);
4165 watch->messages_bytes -= (msg->data_size - msg->data_offset);
4166 msg->data_offset = msg->data_size;
4167
4168 if (msg->body_data) {
4169 body_size = msg->body_data_size;
4170 } else if (msg->body_buffer) {
4171 body_size = gst_buffer_get_size (msg->body_buffer);
4172 } else {
4173 body_size = 0;
4174 }
4175
4176 if (bytes_written + msg->body_offset >= body_size) {
4177 /* body written, drop this message */
4178 bytes_written -= body_size - msg->body_offset;
4179 watch->messages_bytes -= body_size - msg->body_offset;
4180 msg->body_offset = body_size;
4181 drop_messages++;
4182
4183 if (msg->id) {
4184 ids[l] = msg->id;
4185 l++;
4186 }
4187
4188 gst_rtsp_serialized_message_clear (msg);
4189 } else {
4190 msg->body_offset += bytes_written;
4191 watch->messages_bytes -= bytes_written;
4192 bytes_written = 0;
4193 }
4194 } else {
4195 /* Need to continue sending from the data of this message */
4196 msg->data_offset += bytes_written;
4197 watch->messages_bytes -= bytes_written;
4198 bytes_written = 0;
4199 }
4200 }
4201
4202 while (drop_messages > 0) {
4203 msg = gst_queue_array_pop_head_struct (watch->messages);
4204 g_assert (msg);
4205 drop_messages--;
4206 }
4207
4208 g_assert (watch->messages_bytes >= bytes_written);
4209 watch->messages_bytes -= bytes_written;
4210 }
4211
4212 if (!IS_BACKLOG_FULL (watch))
4213 g_cond_signal (&watch->queue_not_full);
4214 g_mutex_unlock (&watch->mutex);
4215
4216 /* notify all messages that were successfully written */
4217 if (ids) {
4218 while (*ids) {
4219 /* only decrease the counter for messages that have an id. Only
4220 * the last message of a messages chunk is counted */
4221 watch->messages_count--;
4222
4223 if (watch->funcs.message_sent)
4224 watch->funcs.message_sent (watch, *ids, watch->user_data);
4225 ids++;
4226 }
4227 }
4228
4229 if (res == GST_RTSP_EINTR) {
4230 goto write_blocked;
4231 } else if (G_UNLIKELY (res != GST_RTSP_OK)) {
4232 goto write_error;
4233 }
4234 g_mutex_lock (&watch->mutex);
4235 } while (TRUE);
4236 g_mutex_unlock (&watch->mutex);
4237
4238 write_blocked:
4239 return TRUE;
4240
4241 /* ERRORS */
4242 eof:
4243 {
4244 return FALSE;
4245 }
4246 write_error:
4247 {
4248 if (watch->funcs.error_full) {
4249 guint i, n_messages;
4250
4251 n_messages = gst_queue_array_get_length (watch->messages);
4252 for (i = 0; i < n_messages; i++) {
4253 GstRTSPSerializedMessage *msg =
4254 gst_queue_array_peek_nth_struct (watch->messages, i);
4255 if (msg->id)
4256 watch->funcs.error_full (watch, res, NULL, msg->id, watch->user_data);
4257 }
4258 } else if (watch->funcs.error) {
4259 watch->funcs.error (watch, res, watch->user_data);
4260 }
4261
4262 return FALSE;
4263 }
4264 }
4265
4266 static void
gst_rtsp_source_finalize(GSource * source)4267 gst_rtsp_source_finalize (GSource * source)
4268 {
4269 GstRTSPWatch *watch = (GstRTSPWatch *) source;
4270 GstRTSPSerializedMessage *msg;
4271
4272 if (watch->notify)
4273 watch->notify (watch->user_data);
4274
4275 build_reset (&watch->builder);
4276 gst_rtsp_message_unset (&watch->message);
4277
4278 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4279 gst_rtsp_serialized_message_clear (msg);
4280 }
4281 gst_queue_array_free (watch->messages);
4282 watch->messages = NULL;
4283 watch->messages_bytes = 0;
4284 watch->messages_count = 0;
4285
4286 g_cond_clear (&watch->queue_not_full);
4287
4288 if (watch->readsrc)
4289 g_source_unref (watch->readsrc);
4290 if (watch->writesrc)
4291 g_source_unref (watch->writesrc);
4292 if (watch->controlsrc)
4293 g_source_unref (watch->controlsrc);
4294
4295 g_mutex_clear (&watch->mutex);
4296 }
4297
4298 static GSourceFuncs gst_rtsp_source_funcs = {
4299 gst_rtsp_source_prepare,
4300 gst_rtsp_source_check,
4301 gst_rtsp_source_dispatch,
4302 gst_rtsp_source_finalize,
4303 NULL,
4304 NULL
4305 };
4306
4307 /**
4308 * gst_rtsp_watch_new: (skip)
4309 * @conn: a #GstRTSPConnection
4310 * @funcs: watch functions
4311 * @user_data: user data to pass to @funcs
4312 * @notify: notify when @user_data is not referenced anymore
4313 *
4314 * Create a watch object for @conn. The functions provided in @funcs will be
4315 * called with @user_data when activity happened on the watch.
4316 *
4317 * The new watch is usually created so that it can be attached to a
4318 * maincontext with gst_rtsp_watch_attach().
4319 *
4320 * @conn must exist for the entire lifetime of the watch.
4321 *
4322 * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
4323 * communication. Free with gst_rtsp_watch_unref () after usage.
4324 */
4325 GstRTSPWatch *
gst_rtsp_watch_new(GstRTSPConnection * conn,GstRTSPWatchFuncs * funcs,gpointer user_data,GDestroyNotify notify)4326 gst_rtsp_watch_new (GstRTSPConnection * conn,
4327 GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
4328 {
4329 GstRTSPWatch *result;
4330
4331 g_return_val_if_fail (conn != NULL, NULL);
4332 g_return_val_if_fail (funcs != NULL, NULL);
4333 g_return_val_if_fail (conn->read_socket != NULL, NULL);
4334 g_return_val_if_fail (conn->write_socket != NULL, NULL);
4335
4336 result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
4337 sizeof (GstRTSPWatch));
4338
4339 result->conn = conn;
4340 result->builder.state = STATE_START;
4341
4342 g_mutex_init (&result->mutex);
4343 result->messages =
4344 gst_queue_array_new_for_struct (sizeof (GstRTSPSerializedMessage), 10);
4345 g_cond_init (&result->queue_not_full);
4346
4347 gst_rtsp_watch_reset (result);
4348 result->keep_running = TRUE;
4349 result->flushing = FALSE;
4350
4351 result->funcs = *funcs;
4352 result->user_data = user_data;
4353 result->notify = notify;
4354
4355 return result;
4356 }
4357
4358 /**
4359 * gst_rtsp_watch_reset:
4360 * @watch: a #GstRTSPWatch
4361 *
4362 * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
4363 * when the file descriptors of the connection might have changed.
4364 */
4365 void
gst_rtsp_watch_reset(GstRTSPWatch * watch)4366 gst_rtsp_watch_reset (GstRTSPWatch * watch)
4367 {
4368 g_mutex_lock (&watch->mutex);
4369 if (watch->readsrc) {
4370 g_source_remove_child_source ((GSource *) watch, watch->readsrc);
4371 g_source_unref (watch->readsrc);
4372 }
4373 if (watch->writesrc) {
4374 g_source_remove_child_source ((GSource *) watch, watch->writesrc);
4375 g_source_unref (watch->writesrc);
4376 watch->writesrc = NULL;
4377 }
4378 if (watch->controlsrc) {
4379 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4380 g_source_unref (watch->controlsrc);
4381 watch->controlsrc = NULL;
4382 }
4383
4384 if (watch->conn->input_stream) {
4385 watch->readsrc =
4386 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4387 (watch->conn->input_stream), NULL);
4388 g_source_set_callback (watch->readsrc,
4389 (GSourceFunc) gst_rtsp_source_dispatch_read, watch, NULL);
4390 g_source_add_child_source ((GSource *) watch, watch->readsrc);
4391 } else {
4392 watch->readsrc = NULL;
4393 }
4394
4395 /* we create and add the write source when we actually have something to
4396 * write */
4397
4398 /* when write source is not added we add read source on the write socket
4399 * instead to be able to detect when client closes get channel in tunneled
4400 * mode */
4401 if (watch->conn->control_stream) {
4402 watch->controlsrc =
4403 g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
4404 (watch->conn->control_stream), NULL);
4405 g_source_set_callback (watch->controlsrc,
4406 (GSourceFunc) gst_rtsp_source_dispatch_read_get_channel, watch, NULL);
4407 g_source_add_child_source ((GSource *) watch, watch->controlsrc);
4408 } else {
4409 watch->controlsrc = NULL;
4410 }
4411 g_mutex_unlock (&watch->mutex);
4412 }
4413
4414 /**
4415 * gst_rtsp_watch_attach:
4416 * @watch: a #GstRTSPWatch
4417 * @context: a GMainContext (if NULL, the default context will be used)
4418 *
4419 * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
4420 *
4421 * Returns: the ID (greater than 0) for the watch within the GMainContext.
4422 */
4423 guint
gst_rtsp_watch_attach(GstRTSPWatch * watch,GMainContext * context)4424 gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
4425 {
4426 g_return_val_if_fail (watch != NULL, 0);
4427
4428 return g_source_attach ((GSource *) watch, context);
4429 }
4430
4431 /**
4432 * gst_rtsp_watch_unref:
4433 * @watch: a #GstRTSPWatch
4434 *
4435 * Decreases the reference count of @watch by one. If the resulting reference
4436 * count is zero the watch and associated memory will be destroyed.
4437 */
4438 void
gst_rtsp_watch_unref(GstRTSPWatch * watch)4439 gst_rtsp_watch_unref (GstRTSPWatch * watch)
4440 {
4441 g_return_if_fail (watch != NULL);
4442
4443 g_source_unref ((GSource *) watch);
4444 }
4445
4446 /**
4447 * gst_rtsp_watch_set_send_backlog:
4448 * @watch: a #GstRTSPWatch
4449 * @bytes: maximum bytes
4450 * @messages: maximum messages
4451 *
4452 * Set the maximum amount of bytes and messages that will be queued in @watch.
4453 * When the maximum amounts are exceeded, gst_rtsp_watch_write_data() and
4454 * gst_rtsp_watch_send_message() will return #GST_RTSP_ENOMEM.
4455 *
4456 * A value of 0 for @bytes or @messages means no limits.
4457 *
4458 * Since: 1.2
4459 */
4460 void
gst_rtsp_watch_set_send_backlog(GstRTSPWatch * watch,gsize bytes,guint messages)4461 gst_rtsp_watch_set_send_backlog (GstRTSPWatch * watch,
4462 gsize bytes, guint messages)
4463 {
4464 g_return_if_fail (watch != NULL);
4465
4466 g_mutex_lock (&watch->mutex);
4467 watch->max_bytes = bytes;
4468 watch->max_messages = messages;
4469 if (!IS_BACKLOG_FULL (watch))
4470 g_cond_signal (&watch->queue_not_full);
4471 g_mutex_unlock (&watch->mutex);
4472
4473 GST_DEBUG ("set backlog to bytes %" G_GSIZE_FORMAT ", messages %u",
4474 bytes, messages);
4475 }
4476
4477 /**
4478 * gst_rtsp_watch_get_send_backlog:
4479 * @watch: a #GstRTSPWatch
4480 * @bytes: (out) (allow-none): maximum bytes
4481 * @messages: (out) (allow-none): maximum messages
4482 *
4483 * Get the maximum amount of bytes and messages that will be queued in @watch.
4484 * See gst_rtsp_watch_set_send_backlog().
4485 *
4486 * Since: 1.2
4487 */
4488 void
gst_rtsp_watch_get_send_backlog(GstRTSPWatch * watch,gsize * bytes,guint * messages)4489 gst_rtsp_watch_get_send_backlog (GstRTSPWatch * watch,
4490 gsize * bytes, guint * messages)
4491 {
4492 g_return_if_fail (watch != NULL);
4493
4494 g_mutex_lock (&watch->mutex);
4495 if (bytes)
4496 *bytes = watch->max_bytes;
4497 if (messages)
4498 *messages = watch->max_messages;
4499 g_mutex_unlock (&watch->mutex);
4500 }
4501
4502 static GstRTSPResult
gst_rtsp_watch_write_serialized_messages(GstRTSPWatch * watch,GstRTSPSerializedMessage * messages,guint n_messages,guint * id)4503 gst_rtsp_watch_write_serialized_messages (GstRTSPWatch * watch,
4504 GstRTSPSerializedMessage * messages, guint n_messages, guint * id)
4505 {
4506 GstRTSPResult res;
4507 GMainContext *context = NULL;
4508 gint i;
4509
4510 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4511 g_return_val_if_fail (messages != NULL, GST_RTSP_EINVAL);
4512
4513 g_mutex_lock (&watch->mutex);
4514 if (watch->flushing)
4515 goto flushing;
4516
4517 /* try to send the message synchronously first */
4518 if (gst_queue_array_get_length (watch->messages) == 0) {
4519 gint j, k;
4520 GOutputVector *vectors;
4521 GstMapInfo *map_infos;
4522 gsize bytes_to_write, bytes_written;
4523 guint n_vectors, n_memories, drop_messages;
4524
4525 for (i = 0, n_vectors = 0, n_memories = 0; i < n_messages; i++) {
4526 n_vectors++;
4527 if (messages[i].body_data) {
4528 n_vectors++;
4529 } else if (messages[i].body_buffer) {
4530 n_vectors += gst_buffer_n_memory (messages[i].body_buffer);
4531 n_memories += gst_buffer_n_memory (messages[i].body_buffer);
4532 }
4533 }
4534
4535 vectors = g_newa (GOutputVector, n_vectors);
4536 map_infos = n_memories ? g_newa (GstMapInfo, n_memories) : NULL;
4537
4538 for (i = 0, j = 0, k = 0, bytes_to_write = 0; i < n_messages; i++) {
4539 vectors[j].buffer = messages[i].data_is_data_header ?
4540 messages[i].data_header : messages[i].data;
4541 vectors[j].size = messages[i].data_size;
4542 bytes_to_write += vectors[j].size;
4543 j++;
4544
4545 if (messages[i].body_data) {
4546 vectors[j].buffer = messages[i].body_data;
4547 vectors[j].size = messages[i].body_data_size;
4548 bytes_to_write += vectors[j].size;
4549 j++;
4550 } else if (messages[i].body_buffer) {
4551 gint l, n;
4552
4553 n = gst_buffer_n_memory (messages[i].body_buffer);
4554 for (l = 0; l < n; l++) {
4555 GstMemory *mem = gst_buffer_peek_memory (messages[i].body_buffer, l);
4556
4557 gst_memory_map (mem, &map_infos[k], GST_MAP_READ);
4558 vectors[j].buffer = map_infos[k].data;
4559 vectors[j].size = map_infos[k].size;
4560 bytes_to_write += vectors[j].size;
4561
4562 k++;
4563 j++;
4564 }
4565 }
4566 }
4567
4568 res =
4569 writev_bytes (watch->conn->output_stream, vectors, n_vectors,
4570 &bytes_written, FALSE, watch->conn->cancellable);
4571 g_assert (bytes_written == bytes_to_write || res != GST_RTSP_OK);
4572
4573 /* At this point we sent everything we could without blocking or
4574 * error and updated the offsets inside the message accordingly */
4575
4576 /* First of all unmap all memories. This simplifies the code below */
4577 for (k = 0; k < n_memories; k++) {
4578 gst_memory_unmap (map_infos[k].memory, &map_infos[k]);
4579 }
4580
4581 if (res != GST_RTSP_EINTR) {
4582 /* actual error or done completely */
4583 if (id != NULL)
4584 *id = 0;
4585
4586 /* free everything */
4587 for (i = 0, k = 0; i < n_messages; i++) {
4588 gst_rtsp_serialized_message_clear (&messages[i]);
4589 }
4590
4591 goto done;
4592 }
4593
4594 /* not done, let's skip all messages that were sent already and free them */
4595 for (i = 0, k = 0, drop_messages = 0; i < n_messages; i++) {
4596 if (bytes_written >= messages[i].data_size) {
4597 guint body_size;
4598
4599 /* all data of this message is sent, check body and otherwise
4600 * skip the whole message for next time */
4601 messages[i].data_offset = messages[i].data_size;
4602 bytes_written -= messages[i].data_size;
4603
4604 if (messages[i].body_data) {
4605 body_size = messages[i].body_data_size;
4606
4607 } else if (messages[i].body_buffer) {
4608 body_size = gst_buffer_get_size (messages[i].body_buffer);
4609 } else {
4610 body_size = 0;
4611 }
4612
4613 if (bytes_written >= body_size) {
4614 /* body written, drop this message */
4615 messages[i].body_offset = body_size;
4616 bytes_written -= body_size;
4617 drop_messages++;
4618
4619 gst_rtsp_serialized_message_clear (&messages[i]);
4620 } else {
4621 messages[i].body_offset = bytes_written;
4622 bytes_written = 0;
4623 }
4624 } else {
4625 /* Need to continue sending from the data of this message */
4626 messages[i].data_offset = bytes_written;
4627 bytes_written = 0;
4628 }
4629 }
4630
4631 g_assert (n_messages > drop_messages);
4632
4633 messages += drop_messages;
4634 n_messages -= drop_messages;
4635 }
4636
4637 /* check limits */
4638 if (IS_BACKLOG_FULL (watch))
4639 goto too_much_backlog;
4640
4641 for (i = 0; i < n_messages; i++) {
4642 GstRTSPSerializedMessage local_message;
4643
4644 /* make a record with the data and id for sending async */
4645 local_message = messages[i];
4646
4647 /* copy the body data or take an additional reference to the body buffer
4648 * we don't own them here */
4649 if (local_message.body_data) {
4650 local_message.body_data =
4651 g_memdup2 (local_message.body_data, local_message.body_data_size);
4652 } else if (local_message.body_buffer) {
4653 gst_buffer_ref (local_message.body_buffer);
4654 }
4655 local_message.borrowed = FALSE;
4656
4657 /* set an id for the very last message */
4658 if (i == n_messages - 1) {
4659 do {
4660 /* make sure rec->id is never 0 */
4661 local_message.id = ++watch->id;
4662 } while (G_UNLIKELY (local_message.id == 0));
4663
4664 if (id != NULL)
4665 *id = local_message.id;
4666 } else {
4667 local_message.id = 0;
4668 }
4669
4670 /* add the record to a queue. */
4671 gst_queue_array_push_tail_struct (watch->messages, &local_message);
4672 watch->messages_bytes +=
4673 (local_message.data_size - local_message.data_offset);
4674 if (local_message.body_data)
4675 watch->messages_bytes +=
4676 (local_message.body_data_size - local_message.body_offset);
4677 else if (local_message.body_buffer)
4678 watch->messages_bytes +=
4679 (gst_buffer_get_size (local_message.body_buffer) -
4680 local_message.body_offset);
4681 }
4682 /* each message chunks is one unit */
4683 watch->messages_count++;
4684
4685 /* make sure the main context will now also check for writability on the
4686 * socket */
4687 context = ((GSource *) watch)->context;
4688 if (!watch->writesrc) {
4689 /* remove the read source on the write socket, we will be able to detect
4690 * errors while writing */
4691 if (watch->controlsrc) {
4692 g_source_remove_child_source ((GSource *) watch, watch->controlsrc);
4693 g_source_unref (watch->controlsrc);
4694 watch->controlsrc = NULL;
4695 }
4696
4697 watch->writesrc =
4698 g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM
4699 (watch->conn->output_stream), NULL);
4700 g_source_set_callback (watch->writesrc,
4701 (GSourceFunc) gst_rtsp_source_dispatch_write, watch, NULL);
4702 g_source_add_child_source ((GSource *) watch, watch->writesrc);
4703 }
4704 res = GST_RTSP_OK;
4705
4706 done:
4707 g_mutex_unlock (&watch->mutex);
4708
4709 if (context)
4710 g_main_context_wakeup (context);
4711
4712 return res;
4713
4714 /* ERRORS */
4715 flushing:
4716 {
4717 GST_DEBUG ("we are flushing");
4718 g_mutex_unlock (&watch->mutex);
4719 for (i = 0; i < n_messages; i++) {
4720 gst_rtsp_serialized_message_clear (&messages[i]);
4721 }
4722 return GST_RTSP_EINTR;
4723 }
4724 too_much_backlog:
4725 {
4726 GST_WARNING ("too much backlog: max_bytes %" G_GSIZE_FORMAT ", current %"
4727 G_GSIZE_FORMAT ", max_messages %u, current %u", watch->max_bytes,
4728 watch->messages_bytes, watch->max_messages, watch->messages_count);
4729 g_mutex_unlock (&watch->mutex);
4730 for (i = 0; i < n_messages; i++) {
4731 gst_rtsp_serialized_message_clear (&messages[i]);
4732 }
4733 return GST_RTSP_ENOMEM;
4734 }
4735
4736 return GST_RTSP_OK;
4737 }
4738
4739 /**
4740 * gst_rtsp_watch_write_data:
4741 * @watch: a #GstRTSPWatch
4742 * @data: (array length=size) (transfer full): the data to queue
4743 * @size: the size of @data
4744 * @id: (out) (allow-none): location for a message ID or %NULL
4745 *
4746 * Write @data using the connection of the @watch. If it cannot be sent
4747 * immediately, it will be queued for transmission in @watch. The contents of
4748 * @message will then be serialized and transmitted when the connection of the
4749 * @watch becomes writable. In case the @message is queued, the ID returned in
4750 * @id will be non-zero and used as the ID argument in the message_sent
4751 * callback.
4752 *
4753 * This function will take ownership of @data and g_free() it after use.
4754 *
4755 * If the amount of queued data exceeds the limits set with
4756 * gst_rtsp_watch_set_send_backlog(), this function will return
4757 * #GST_RTSP_ENOMEM.
4758 *
4759 * Returns: #GST_RTSP_OK on success. #GST_RTSP_ENOMEM when the backlog limits
4760 * are reached. #GST_RTSP_EINTR when @watch was flushing.
4761 */
4762 /* FIXME 2.0: This should've been static! */
4763 GstRTSPResult
gst_rtsp_watch_write_data(GstRTSPWatch * watch,const guint8 * data,guint size,guint * id)4764 gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
4765 guint size, guint * id)
4766 {
4767 GstRTSPSerializedMessage serialized_message;
4768
4769 memset (&serialized_message, 0, sizeof (serialized_message));
4770 serialized_message.data = (guint8 *) data;
4771 serialized_message.data_size = size;
4772
4773 return gst_rtsp_watch_write_serialized_messages (watch, &serialized_message,
4774 1, id);
4775 }
4776
4777 /**
4778 * gst_rtsp_watch_send_message:
4779 * @watch: a #GstRTSPWatch
4780 * @message: a #GstRTSPMessage
4781 * @id: (out) (allow-none): location for a message ID or %NULL
4782 *
4783 * Send a @message using the connection of the @watch. If it cannot be sent
4784 * immediately, it will be queued for transmission in @watch. The contents of
4785 * @message will then be serialized and transmitted when the connection of the
4786 * @watch becomes writable. In case the @message is queued, the ID returned in
4787 * @id will be non-zero and used as the ID argument in the message_sent
4788 * callback.
4789 *
4790 * Returns: #GST_RTSP_OK on success.
4791 */
4792 GstRTSPResult
gst_rtsp_watch_send_message(GstRTSPWatch * watch,GstRTSPMessage * message,guint * id)4793 gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
4794 guint * id)
4795 {
4796 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4797 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4798
4799 return gst_rtsp_watch_send_messages (watch, message, 1, id);
4800 }
4801
4802 /**
4803 * gst_rtsp_watch_send_messages:
4804 * @watch: a #GstRTSPWatch
4805 * @messages: (array length=n_messages): the messages to send
4806 * @n_messages: the number of messages to send
4807 * @id: (out) (allow-none): location for a message ID or %NULL
4808 *
4809 * Sends @messages using the connection of the @watch. If they cannot be sent
4810 * immediately, they will be queued for transmission in @watch. The contents of
4811 * @messages will then be serialized and transmitted when the connection of the
4812 * @watch becomes writable. In case the @messages are queued, the ID returned in
4813 * @id will be non-zero and used as the ID argument in the message_sent
4814 * callback once the last message is sent. The callback will only be called
4815 * once for the last message.
4816 *
4817 * Returns: #GST_RTSP_OK on success.
4818 *
4819 * Since: 1.16
4820 */
4821 GstRTSPResult
gst_rtsp_watch_send_messages(GstRTSPWatch * watch,GstRTSPMessage * messages,guint n_messages,guint * id)4822 gst_rtsp_watch_send_messages (GstRTSPWatch * watch, GstRTSPMessage * messages,
4823 guint n_messages, guint * id)
4824 {
4825 GstRTSPSerializedMessage *serialized_messages;
4826 gint i;
4827
4828 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4829 g_return_val_if_fail (messages != NULL || n_messages == 0, GST_RTSP_EINVAL);
4830
4831 serialized_messages = g_newa (GstRTSPSerializedMessage, n_messages);
4832 memset (serialized_messages, 0,
4833 sizeof (GstRTSPSerializedMessage) * n_messages);
4834
4835 for (i = 0; i < n_messages; i++) {
4836 if (!serialize_message (watch->conn, &messages[i], &serialized_messages[i]))
4837 goto error;
4838 }
4839
4840 return gst_rtsp_watch_write_serialized_messages (watch, serialized_messages,
4841 n_messages, id);
4842
4843 error:
4844 for (i = 0; i < n_messages; i++) {
4845 gst_rtsp_serialized_message_clear (&serialized_messages[i]);
4846 }
4847
4848 return GST_RTSP_EINVAL;
4849 }
4850
4851 /**
4852 * gst_rtsp_watch_wait_backlog_usec:
4853 * @watch: a #GstRTSPWatch
4854 * @timeout: a timeout in microseconds
4855 *
4856 * Wait until there is place in the backlog queue, @timeout is reached
4857 * or @watch is set to flushing.
4858 *
4859 * If @timeout is 0 this function can block forever. If @timeout
4860 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
4861 * after the timeout expired.
4862 *
4863 * The typically use of this function is when gst_rtsp_watch_write_data
4864 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
4865 * free space in the backlog queue and try again.
4866 *
4867 * Returns: %GST_RTSP_OK when if there is room in queue.
4868 * %GST_RTSP_ETIMEOUT when @timeout was reached.
4869 * %GST_RTSP_EINTR when @watch is flushing
4870 * %GST_RTSP_EINVAL when called with invalid parameters.
4871 *
4872 * Since: 1.18
4873 */
4874 GstRTSPResult
gst_rtsp_watch_wait_backlog_usec(GstRTSPWatch * watch,gint64 timeout)4875 gst_rtsp_watch_wait_backlog_usec (GstRTSPWatch * watch, gint64 timeout)
4876 {
4877 gint64 end_time;
4878
4879 g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
4880
4881 end_time = g_get_monotonic_time () + timeout;
4882
4883 g_mutex_lock (&watch->mutex);
4884 if (watch->flushing)
4885 goto flushing;
4886
4887 while (IS_BACKLOG_FULL (watch)) {
4888 gboolean res;
4889
4890 res = g_cond_wait_until (&watch->queue_not_full, &watch->mutex, end_time);
4891 if (watch->flushing)
4892 goto flushing;
4893
4894 if (!res)
4895 goto timeout;
4896 }
4897 g_mutex_unlock (&watch->mutex);
4898
4899 return GST_RTSP_OK;
4900
4901 /* ERRORS */
4902 flushing:
4903 {
4904 GST_DEBUG ("we are flushing");
4905 g_mutex_unlock (&watch->mutex);
4906 return GST_RTSP_EINTR;
4907 }
4908 timeout:
4909 {
4910 GST_DEBUG ("we timed out");
4911 g_mutex_unlock (&watch->mutex);
4912 return GST_RTSP_ETIMEOUT;
4913 }
4914 }
4915
4916 /**
4917 * gst_rtsp_watch_set_flushing:
4918 * @watch: a #GstRTSPWatch
4919 * @flushing: new flushing state
4920 *
4921 * When @flushing is %TRUE, abort a call to gst_rtsp_watch_wait_backlog()
4922 * and make sure gst_rtsp_watch_write_data() returns immediately with
4923 * #GST_RTSP_EINTR. And empty the queue.
4924 *
4925 * Since: 1.4
4926 */
4927 void
gst_rtsp_watch_set_flushing(GstRTSPWatch * watch,gboolean flushing)4928 gst_rtsp_watch_set_flushing (GstRTSPWatch * watch, gboolean flushing)
4929 {
4930 g_return_if_fail (watch != NULL);
4931
4932 g_mutex_lock (&watch->mutex);
4933 watch->flushing = flushing;
4934 g_cond_signal (&watch->queue_not_full);
4935 if (flushing) {
4936 GstRTSPSerializedMessage *msg;
4937
4938 while ((msg = gst_queue_array_pop_head_struct (watch->messages))) {
4939 gst_rtsp_serialized_message_clear (msg);
4940 }
4941 }
4942 g_mutex_unlock (&watch->mutex);
4943 }
4944
4945
4946 #ifndef GST_DISABLE_DEPRECATED
4947 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
4948 /* Deprecated */
4949 #define TV_TO_USEC(tv) ((tv) ? ((tv)->tv_sec * G_USEC_PER_SEC + (tv)->tv_usec) : 0)
4950 /**
4951 * gst_rtsp_connection_connect:
4952 * @conn: a #GstRTSPConnection
4953 * @timeout: a GTimeVal timeout
4954 *
4955 * Attempt to connect to the url of @conn made with
4956 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4957 * forever. If @timeout contains a valid timeout, this function will return
4958 * #GST_RTSP_ETIMEOUT after the timeout expired.
4959 *
4960 * This function can be cancelled with gst_rtsp_connection_flush().
4961 *
4962 * Returns: #GST_RTSP_OK when a connection could be made.
4963 *
4964 * Deprecated: 1.18
4965 */
4966 GstRTSPResult
gst_rtsp_connection_connect(GstRTSPConnection * conn,GTimeVal * timeout)4967 gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
4968 {
4969 return gst_rtsp_connection_connect_usec (conn, TV_TO_USEC (timeout));
4970 }
4971
4972 /**
4973 * gst_rtsp_connection_connect_with_response:
4974 * @conn: a #GstRTSPConnection
4975 * @timeout: a GTimeVal timeout
4976 * @response: a #GstRTSPMessage
4977 *
4978 * Attempt to connect to the url of @conn made with
4979 * gst_rtsp_connection_create(). If @timeout is %NULL this function can block
4980 * forever. If @timeout contains a valid timeout, this function will return
4981 * #GST_RTSP_ETIMEOUT after the timeout expired. If @conn is set to tunneled,
4982 * @response will contain a response to the tunneling request messages.
4983 *
4984 * This function can be cancelled with gst_rtsp_connection_flush().
4985 *
4986 * Returns: #GST_RTSP_OK when a connection could be made.
4987 *
4988 * Since: 1.8
4989 * Deprecated: 1.18
4990 */
4991 GstRTSPResult
gst_rtsp_connection_connect_with_response(GstRTSPConnection * conn,GTimeVal * timeout,GstRTSPMessage * response)4992 gst_rtsp_connection_connect_with_response (GstRTSPConnection * conn,
4993 GTimeVal * timeout, GstRTSPMessage * response)
4994 {
4995 return gst_rtsp_connection_connect_with_response_usec (conn,
4996 TV_TO_USEC (timeout), response);
4997 }
4998
4999 /**
5000 * gst_rtsp_connection_read:
5001 * @conn: a #GstRTSPConnection
5002 * @data: the data to read
5003 * @size: the size of @data
5004 * @timeout: a timeout value or %NULL
5005 *
5006 * Attempt to read @size bytes into @data from the connected @conn, blocking up to
5007 * the specified @timeout. @timeout can be %NULL, in which case this function
5008 * might block forever.
5009 *
5010 * This function can be cancelled with gst_rtsp_connection_flush().
5011 *
5012 * Returns: #GST_RTSP_OK on success.
5013 *
5014 * Deprecated: 1.18
5015 */
5016 GstRTSPResult
gst_rtsp_connection_read(GstRTSPConnection * conn,guint8 * data,guint size,GTimeVal * timeout)5017 gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
5018 GTimeVal * timeout)
5019 {
5020 return gst_rtsp_connection_read_usec (conn, data, size, TV_TO_USEC (timeout));
5021 }
5022
5023 /**
5024 * gst_rtsp_connection_write:
5025 * @conn: a #GstRTSPConnection
5026 * @data: the data to write
5027 * @size: the size of @data
5028 * @timeout: a timeout value or %NULL
5029 *
5030 * Attempt to write @size bytes of @data to the connected @conn, blocking up to
5031 * the specified @timeout. @timeout can be %NULL, in which case this function
5032 * might block forever.
5033 *
5034 * This function can be cancelled with gst_rtsp_connection_flush().
5035 *
5036 * Returns: #GST_RTSP_OK on success.
5037 *
5038 * Deprecated: 1.18
5039 */
5040 GstRTSPResult
gst_rtsp_connection_write(GstRTSPConnection * conn,const guint8 * data,guint size,GTimeVal * timeout)5041 gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
5042 guint size, GTimeVal * timeout)
5043 {
5044 return gst_rtsp_connection_write_usec (conn, data, size,
5045 TV_TO_USEC (timeout));
5046 }
5047
5048 /**
5049 * gst_rtsp_connection_send:
5050 * @conn: a #GstRTSPConnection
5051 * @message: the message to send
5052 * @timeout: a timeout value or %NULL
5053 *
5054 * Attempt to send @message to the connected @conn, blocking up to
5055 * the specified @timeout. @timeout can be %NULL, in which case this function
5056 * might block forever.
5057 *
5058 * This function can be cancelled with gst_rtsp_connection_flush().
5059 *
5060 * Returns: #GST_RTSP_OK on success.
5061 *
5062 * Deprecated: 1.18
5063 */
5064 GstRTSPResult
gst_rtsp_connection_send(GstRTSPConnection * conn,GstRTSPMessage * message,GTimeVal * timeout)5065 gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
5066 GTimeVal * timeout)
5067 {
5068 return gst_rtsp_connection_send_usec (conn, message, TV_TO_USEC (timeout));
5069 }
5070
5071 /**
5072 * gst_rtsp_connection_send_messages:
5073 * @conn: a #GstRTSPConnection
5074 * @messages: (array length=n_messages): the messages to send
5075 * @n_messages: the number of messages to send
5076 * @timeout: a timeout value or %NULL
5077 *
5078 * Attempt to send @messages to the connected @conn, blocking up to
5079 * the specified @timeout. @timeout can be %NULL, in which case this function
5080 * might block forever.
5081 *
5082 * This function can be cancelled with gst_rtsp_connection_flush().
5083 *
5084 * Returns: #GST_RTSP_OK on success.
5085 *
5086 * Since: 1.16
5087 * Deprecated: 1.18
5088 */
5089 GstRTSPResult
gst_rtsp_connection_send_messages(GstRTSPConnection * conn,GstRTSPMessage * messages,guint n_messages,GTimeVal * timeout)5090 gst_rtsp_connection_send_messages (GstRTSPConnection * conn,
5091 GstRTSPMessage * messages, guint n_messages, GTimeVal * timeout)
5092 {
5093 return gst_rtsp_connection_send_messages_usec (conn, messages, n_messages,
5094 TV_TO_USEC (timeout));
5095 }
5096
5097 /**
5098 * gst_rtsp_connection_receive:
5099 * @conn: a #GstRTSPConnection
5100 * @message: the message to read
5101 * @timeout: a timeout value or %NULL
5102 *
5103 * Attempt to read into @message from the connected @conn, blocking up to
5104 * the specified @timeout. @timeout can be %NULL, in which case this function
5105 * might block forever.
5106 *
5107 * This function can be cancelled with gst_rtsp_connection_flush().
5108 *
5109 * Returns: #GST_RTSP_OK on success.
5110 *
5111 * Deprecated: 1.18
5112 */
5113 GstRTSPResult
gst_rtsp_connection_receive(GstRTSPConnection * conn,GstRTSPMessage * message,GTimeVal * timeout)5114 gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
5115 GTimeVal * timeout)
5116 {
5117 return gst_rtsp_connection_receive_usec (conn, message, TV_TO_USEC (timeout));
5118 }
5119
5120 /**
5121 * gst_rtsp_connection_poll:
5122 * @conn: a #GstRTSPConnection
5123 * @events: a bitmask of #GstRTSPEvent flags to check
5124 * @revents: location for result flags
5125 * @timeout: a timeout
5126 *
5127 * Wait up to the specified @timeout for the connection to become available for
5128 * at least one of the operations specified in @events. When the function returns
5129 * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
5130 * @conn.
5131 *
5132 * @timeout can be %NULL, in which case this function might block forever.
5133 *
5134 * This function can be cancelled with gst_rtsp_connection_flush().
5135 *
5136 * Returns: #GST_RTSP_OK on success.
5137 *
5138 * Deprecated: 1.18
5139 */
5140 GstRTSPResult
gst_rtsp_connection_poll(GstRTSPConnection * conn,GstRTSPEvent events,GstRTSPEvent * revents,GTimeVal * timeout)5141 gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
5142 GstRTSPEvent * revents, GTimeVal * timeout)
5143 {
5144 return gst_rtsp_connection_poll_usec (conn, events, revents,
5145 TV_TO_USEC (timeout));
5146 }
5147
5148 /**
5149 * gst_rtsp_connection_next_timeout:
5150 * @conn: a #GstRTSPConnection
5151 * @timeout: a timeout
5152 *
5153 * Calculate the next timeout for @conn, storing the result in @timeout.
5154 *
5155 * Returns: #GST_RTSP_OK.
5156 *
5157 * Deprecated: 1.18
5158 */
5159 GstRTSPResult
gst_rtsp_connection_next_timeout(GstRTSPConnection * conn,GTimeVal * timeout)5160 gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
5161 {
5162 gint64 tmptimeout = 0;
5163
5164 g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
5165
5166 tmptimeout = gst_rtsp_connection_next_timeout_usec (conn);
5167
5168 timeout->tv_sec = tmptimeout / G_USEC_PER_SEC;
5169 timeout->tv_usec = tmptimeout % G_USEC_PER_SEC;
5170
5171 return GST_RTSP_OK;
5172 }
5173
5174
5175 /**
5176 * gst_rtsp_watch_wait_backlog:
5177 * @watch: a #GstRTSPWatch
5178 * @timeout: a GTimeVal timeout
5179 *
5180 * Wait until there is place in the backlog queue, @timeout is reached
5181 * or @watch is set to flushing.
5182 *
5183 * If @timeout is %NULL this function can block forever. If @timeout
5184 * contains a valid timeout, this function will return %GST_RTSP_ETIMEOUT
5185 * after the timeout expired.
5186 *
5187 * The typically use of this function is when gst_rtsp_watch_write_data
5188 * returns %GST_RTSP_ENOMEM. The caller then calls this function to wait for
5189 * free space in the backlog queue and try again.
5190 *
5191 * Returns: %GST_RTSP_OK when if there is room in queue.
5192 * %GST_RTSP_ETIMEOUT when @timeout was reached.
5193 * %GST_RTSP_EINTR when @watch is flushing
5194 * %GST_RTSP_EINVAL when called with invalid parameters.
5195 *
5196 * Since: 1.4
5197 * Deprecated: 1.18
5198 */
5199 GstRTSPResult
gst_rtsp_watch_wait_backlog(GstRTSPWatch * watch,GTimeVal * timeout)5200 gst_rtsp_watch_wait_backlog (GstRTSPWatch * watch, GTimeVal * timeout)
5201 {
5202 return gst_rtsp_watch_wait_backlog_usec (watch, TV_TO_USEC (timeout));
5203 }
5204
5205 G_GNUC_END_IGNORE_DEPRECATIONS
5206 #endif /* GST_DISABLE_DEPRECATED */
5207