From ed66f974dd14a66ae72ad8fdd34cb84376bf226a Mon Sep 17 00:00:00 2001 From: Ognyan Tonchev Date: Tue, 3 Jul 2012 18:06:00 +0200 Subject: [PATCH] rtsp-server: use an existing socket to establish HTTP tunnel Make it possible to transfer a socket from an HTTP server to be used as an RTSP over HTTP tunnel. --- gst/rtsp-server/rtsp-client.c | 108 ++++++++++++++++++++++++---------- gst/rtsp-server/rtsp-client.h | 7 +++ gst/rtsp-server/rtsp-server.c | 59 +++++++++++++++++++ gst/rtsp-server/rtsp-server.h | 2 + 4 files changed, 145 insertions(+), 31 deletions(-) diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 57d1441baa..adc892478a 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -1904,26 +1904,10 @@ client_watch_notify (GstRTSPClient * client) g_object_unref (client); } -/** - * gst_rtsp_client_attach: - * @client: a #GstRTSPClient - * @socket: a #GSocket - * @cancellable: a #GCancellable - * @error: a #GError - * - * Accept a new connection for @client on @socket. - * - * This function should be called when the client properties and urls are fully - * configured and the client is ready to start. - * - * Returns: %TRUE if the client could be accepted. - */ -gboolean -gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, - GCancellable * cancellable, GError ** error) +static gboolean +attach_client (GstRTSPClient * client, GSocket * socket, + GstRTSPConnection *conn, GError ** error) { - GstRTSPConnection *conn; - GstRTSPResult res; GSocket *read_socket; GSocketAddress *addres; GSource *source; @@ -1933,10 +1917,6 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, socklen_t addrlen; gchar ip[INET6_ADDRSTRLEN]; - /* a new client connected. */ - GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), - accept_failed); - read_socket = gst_rtsp_connection_get_read_socket (conn); client->is_ipv6 = g_socket_get_family (socket) == G_SOCKET_FAMILY_IPV6; @@ -1982,14 +1962,6 @@ gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, return TRUE; /* ERRORS */ -accept_failed: - { - gchar *str = gst_rtsp_strresult (res); - - GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); - g_free (str); - return FALSE; - } no_address: { GST_ERROR ("could not get remote address %s", (*error)->message); @@ -2007,3 +1979,77 @@ getnameinfo_failed: return FALSE; } } + +/** + * gst_rtsp_client_create_from_socket: + * @client: a #GstRTSPClient + * @socket: a #GSocket + * @ip: the IP address of the remote client + * @port: the port used by the other end + * @initial_buffer: any initial data that was already read from the socket + * @error: a #GError + * + * Take an existing network socket and use it for an RTSP connection. + * + * Returns: %TRUE on success. + */ +gboolean +gst_rtsp_client_create_from_socket (GstRTSPClient * client, GSocket * socket, + const gchar * ip, gint port, const gchar * initial_buffer, GError ** error) +{ + GstRTSPConnection *conn; + GstRTSPResult res; + + GST_RTSP_CHECK (gst_rtsp_connection_create_from_socket (socket, ip, port, + initial_buffer, &conn), no_connection); + + return attach_client (client, socket, conn, error); + + /* ERRORS */ +no_connection: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ERROR ("could not create connection from socket %p: %s", socket, str); + g_free (str); + return FALSE; + } +} + +/** + * gst_rtsp_client_attach: + * @client: a #GstRTSPClient + * @socket: a #GSocket + * @cancellable: a #GCancellable + * @error: a #GError + * + * Accept a new connection for @client on @socket. + * + * This function should be called when the client properties and urls are fully + * configured and the client is ready to start. + * + * Returns: %TRUE if the client could be accepted. + */ +gboolean +gst_rtsp_client_accept (GstRTSPClient * client, GSocket * socket, + GCancellable * cancellable, GError ** error) +{ + GstRTSPConnection *conn; + GstRTSPResult res; + + /* a new client connected. */ + GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, cancellable), + accept_failed); + + return attach_client (client, socket, conn, error); + + /* ERRORS */ +accept_failed: + { + gchar *str = gst_rtsp_strresult (res); + + GST_ERROR ("Could not accept client on server socket %p: %s", socket, str); + g_free (str); + return FALSE; + } +} diff --git a/gst/rtsp-server/rtsp-client.h b/gst/rtsp-server/rtsp-client.h index bc56cc7c55..97bb0c2417 100644 --- a/gst/rtsp-server/rtsp-client.h +++ b/gst/rtsp-server/rtsp-client.h @@ -136,6 +136,13 @@ gboolean gst_rtsp_client_accept (GstRTSPClient *client, GCancellable *cancellable, GError **error); +gboolean gst_rtsp_client_create_from_socket(GstRTSPClient * client, + GSocket *socket, + const gchar * ip, + gint port, + const gchar *initial_buffer, + GError **error); + G_END_DECLS #endif /* __GST_RTSP_CLIENT_H__ */ diff --git a/gst/rtsp-server/rtsp-server.c b/gst/rtsp-server/rtsp-server.c index c4b951e22f..9c4594a360 100644 --- a/gst/rtsp-server/rtsp-server.c +++ b/gst/rtsp-server/rtsp-server.c @@ -779,6 +779,65 @@ accept_failed: } } +/** + * gst_rtsp_server_transfer_connection: + * @server: a #GstRTSPServer + * @socket: a network socket + * @ip: the IP address of the remote client + * @port: the port used by the other end + * @initial_buffer: any initial data that was already read from the socket + * + * Take an existing network socket and use it for an RTSP connection. This + * is used when transferring a socket from an HTTP server which should be used + * as an RTSP over HTTP tunnel. The @initial_buffer contains any remaining data + * that the HTTP server read from the socket while parsing the HTTP header. + * + * Returns: TRUE if all was ok, FALSE if an error occured. + */ +gboolean +gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket * socket, + const gchar * ip, gint port, const gchar *initial_buffer) +{ + GstRTSPClient *client = NULL; + GstRTSPServerClass *klass; + GError *error = NULL; + + klass = GST_RTSP_SERVER_GET_CLASS (server); + + if (klass->create_client) + client = klass->create_client (server); + if (client == NULL) + goto client_failed; + + /* a new client connected, create a client object to handle the client. */ + if (!gst_rtsp_client_create_from_socket (client, socket, ip, port, + initial_buffer, &error)) { + goto transfer_failed; + } + + /* manage the client connection */ + manage_client (server, client); + + g_signal_emit (server, gst_rtsp_server_signals[SIGNAL_CLIENT_CONNECTED], 0, + client); + + return TRUE; + + /* ERRORS */ +client_failed: + { + GST_ERROR_OBJECT (server, "failed to create a client"); + return FALSE; + } +transfer_failed: + { + GST_ERROR_OBJECT (server, "failed to accept client: %s", error->message); + g_error_free (error); + gst_object_unref (client); + return FALSE; + } +} + /** * gst_rtsp_server_io_func: * @socket: a #GSocket diff --git a/gst/rtsp-server/rtsp-server.h b/gst/rtsp-server/rtsp-server.h index 1c5cb0c632..595f2f1bd5 100644 --- a/gst/rtsp-server/rtsp-server.h +++ b/gst/rtsp-server/rtsp-server.h @@ -116,6 +116,8 @@ GstRTSPMediaMapping * gst_rtsp_server_get_media_mapping (GstRTSPServer *serve void gst_rtsp_server_set_auth (GstRTSPServer *server, GstRTSPAuth *auth); GstRTSPAuth * gst_rtsp_server_get_auth (GstRTSPServer *server); +gboolean gst_rtsp_server_transfer_connection (GstRTSPServer * server, GSocket *socket, const gchar * ip, gint port, const gchar *initial_buffer); + gboolean gst_rtsp_server_io_func (GSocket *socket, GIOCondition condition, GstRTSPServer *server);