summaryrefslogtreecommitdiffstats
path: root/gst/rtsp/rtspconnection.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2005-05-11 07:44:44 +0000
committerWim Taymans <wim.taymans@gmail.com>2005-05-11 07:44:44 +0000
commit6f0ea35883cec1b68eb1ac2f2bc511f856018f6f (patch)
tree601e40d1ac5cd282ad5f207f4a9a647da62fc126 /gst/rtsp/rtspconnection.c
parent6cacd6f64958db92328a9ae52563160a583a395a (diff)
Ported to 0.9.
Original commit message from CVS: Ported to 0.9. Set up transports, init UDP ports, init RTP session managers.
Diffstat (limited to 'gst/rtsp/rtspconnection.c')
-rw-r--r--gst/rtsp/rtspconnection.c432
1 files changed, 432 insertions, 0 deletions
diff --git a/gst/rtsp/rtspconnection.c b/gst/rtsp/rtspconnection.c
new file mode 100644
index 00000000..f9a1b420
--- /dev/null
+++ b/gst/rtsp/rtspconnection.c
@@ -0,0 +1,432 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "rtspconnection.h"
+
+RTSPResult
+rtsp_connection_open (RTSPUrl * url, RTSPConnection ** conn)
+{
+ gint fd;
+ struct sockaddr_in sin;
+ struct hostent *hostinfo;
+ char **addrs;
+ gchar *ip;
+ struct in_addr addr;
+ gint ret;
+
+ if (url == NULL || conn == NULL)
+ return RTSP_EINVAL;
+
+ if (url->protocol != RTSP_PROTO_TCP)
+ return RTSP_ENOTIMPL;
+
+ /* first check if it already is an IP address */
+ if (inet_aton (url->host, &addr)) {
+ ip = url->host;
+ } else {
+ hostinfo = gethostbyname (url->host);
+ if (!hostinfo)
+ goto not_resolved; /* h_errno set */
+
+ if (hostinfo->h_addrtype != AF_INET)
+ goto not_ip; /* host not an IP host */
+
+ addrs = hostinfo->h_addr_list;
+ ip = inet_ntoa (*(struct in_addr *) *addrs);
+ }
+
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ goto sys_error;
+
+ memset (&sin, 0, sizeof (sin));
+ sin.sin_family = AF_INET; /* network socket */
+ sin.sin_port = htons (url->port); /* on port */
+ sin.sin_addr.s_addr = inet_addr (ip); /* on host ip */
+
+ ret = connect (fd, (struct sockaddr *) &sin, sizeof (sin));
+ if (ret != 0)
+ goto sys_error;
+
+ return rtsp_connection_create (fd, conn);
+
+sys_error:
+ {
+ return RTSP_ESYS;
+ }
+not_resolved:
+ {
+ g_warning ("could not resolve host \"%s\"\n", url->host);
+ return RTSP_ESYS;
+ }
+not_ip:
+ {
+ g_warning ("host \"%s\" is not IP\n", url->host);
+ return RTSP_ESYS;
+ }
+}
+
+RTSPResult
+rtsp_connection_create (gint fd, RTSPConnection ** conn)
+{
+ RTSPConnection *newconn;
+
+ /* FIXME check fd */
+
+ newconn = g_new (RTSPConnection, 1);
+
+ newconn->fd = fd;
+ newconn->cseq = 0;
+ newconn->session_id[0] = 0;
+ newconn->state = RTSP_STATE_INIT;
+
+ *conn = newconn;
+
+ return RTSP_OK;
+}
+
+static void
+append_header (gint key, gchar * value, GString * str)
+{
+ const gchar *keystr = rtsp_header_as_text (key);
+
+ g_string_append_printf (str, "%s: %s\r\n", keystr, value);
+}
+
+RTSPResult
+rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
+{
+ GString *str;
+
+ if (conn == NULL || message == NULL)
+ return RTSP_EINVAL;
+
+ str = g_string_new ("");
+
+ g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
+ "CSeq: %d\r\n",
+ rtsp_method_as_text (message->type_data.request.method),
+ message->type_data.request.uri, conn->cseq);
+
+ if (conn->session_id[0] != '\0') {
+ rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id);
+ }
+
+ g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
+
+
+ g_string_append (str, "\r\n");
+
+ write (conn->fd, str->str, str->len);
+ g_string_free (str, TRUE);
+
+ return RTSP_OK;
+}
+
+static RTSPResult
+read_line (gint fd, gchar * buffer, guint size)
+{
+ gint idx;
+ gchar c;
+ gint ret;
+
+ idx = 0;
+ while (TRUE) {
+ ret = read (fd, &c, 1);
+ if (ret < 1)
+ goto error;
+
+ if (c == '\n') /* end on \n */
+ break;
+ if (c == '\r') /* ignore \r */
+ continue;
+
+ if (idx < size - 1)
+ buffer[idx++] = c;
+ }
+ buffer[idx] = '\0';
+
+ return RTSP_OK;
+
+error:
+ {
+ perror ("read");
+ return RTSP_ESYS;
+ }
+}
+
+static void
+read_string (gchar * dest, gint size, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (!g_ascii_isspace (**src) && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static void
+read_key (gchar * dest, gint size, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ while (**src != ':' && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static RTSPResult
+parse_response_status (gchar * buffer, RTSPMessage * msg)
+{
+ gchar versionstr[20];
+ gchar codestr[4];
+ gint code;
+ gchar *bptr;
+
+ bptr = buffer;
+
+ read_string (versionstr, sizeof (versionstr), &bptr);
+ if (strcmp (versionstr, "RTSP/1.0") != 0)
+ goto wrong_version;
+
+ read_string (codestr, sizeof (codestr), &bptr);
+ code = atoi (codestr);
+
+ while (g_ascii_isspace (*bptr))
+ bptr++;
+
+ rtsp_message_init_response (code, bptr, NULL, msg);
+
+ return RTSP_OK;
+
+wrong_version:
+ {
+ return RTSP_EINVAL;
+ }
+}
+
+static RTSPResult
+parse_line (gchar * buffer, RTSPMessage * msg)
+{
+ gchar key[32];
+ gchar *bptr;
+ RTSPHeaderField field;
+
+ bptr = buffer;
+
+ read_key (key, sizeof (key), &bptr);
+ if (*bptr != ':')
+ return RTSP_EINVAL;
+
+ bptr++;
+
+ field = rtsp_find_header_field (key);
+ if (field == -1) {
+ g_warning ("unknown header field '%s'\n", key);
+ } else {
+ while (g_ascii_isspace (*bptr))
+ bptr++;
+ rtsp_message_add_header (msg, field, bptr);
+ }
+
+ return RTSP_OK;
+}
+
+static RTSPResult
+read_body (gint fd, glong content_length, RTSPMessage * msg)
+{
+ gchar *body, *bodyptr;
+ gint to_read, r;
+
+ if (content_length <= 0) {
+ rtsp_message_set_body (msg, NULL, 0);
+ return RTSP_OK;
+ }
+
+ body = g_malloc (content_length);
+ bodyptr = body;
+ to_read = content_length;
+ while (to_read > 0) {
+ r = read (fd, bodyptr, to_read);
+
+ to_read -= r;
+ bodyptr += r;
+ }
+
+ rtsp_message_set_body (msg, body, content_length);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
+{
+ gchar buffer[4096];
+ gint line;
+ gchar *hdrval;
+ glong content_length;
+ RTSPResult res;
+ gboolean need_body;
+
+ if (conn == NULL || msg == NULL)
+ return RTSP_EINVAL;
+
+ line = 0;
+
+ need_body = TRUE;
+
+ /* parse first line and headers */
+ while (TRUE) {
+ gchar c;
+ gint ret;
+
+ ret = read (conn->fd, &c, 1);
+ if (ret < 0)
+ goto read_error;
+ if (ret < 1)
+ break;
+
+ /* check for data packet */
+ if (c == '$') {
+ guint16 size;
+
+ /* read channel */
+ ret = read (conn->fd, &c, 1);
+ if (ret < 0)
+ goto read_error;
+ if (ret < 1)
+ goto error;
+
+ rtsp_message_init_data ((gint) c, msg);
+
+ ret = read (conn->fd, &size, 2);
+ if (ret < 0)
+ goto read_error;
+ if (ret < 2)
+ goto error;
+
+ size = GUINT16_FROM_BE (size);
+
+ read_body (conn->fd, size, msg);
+ need_body = FALSE;
+ break;
+ } else {
+ gint offset = 0;
+
+ if (c != '\r') {
+ buffer[0] = c;
+ offset = 1;
+ }
+ /* should not happen */
+ if (c == '\n')
+ break;
+
+ read_line (conn->fd, buffer + offset, sizeof (buffer) - offset);
+
+ if (buffer[0] == '\0')
+ break;
+
+ if (line == 0) {
+ if (g_str_has_prefix (buffer, "RTSP")) {
+ parse_response_status (buffer, msg);
+ } else {
+ g_warning ("parsing request not implemented\n");
+ goto error;
+ }
+ } else {
+ parse_line (buffer, msg);
+ }
+ }
+ line++;
+ }
+
+ if (need_body) {
+ /* parse body */
+ res = rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH, &hdrval);
+ if (res == RTSP_OK) {
+ content_length = atol (hdrval);
+ read_body (conn->fd, content_length, msg);
+ }
+
+ /* save session id */
+ {
+ gchar *session_id;
+
+ if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
+ &session_id) == RTSP_OK) {
+ strncpy (conn->session_id, session_id, sizeof (conn->session_id) - 1);
+ conn->session_id[sizeof (conn->session_id) - 1] = '\0';
+ }
+ }
+ }
+
+ return RTSP_OK;
+
+error:
+ {
+ return RTSP_EPARSE;
+ }
+read_error:
+ {
+ perror ("read");
+ return RTSP_ESYS;
+ }
+}
+
+RTSPResult
+rtsp_connection_close (RTSPConnection * conn)
+{
+ gint res;
+
+ if (conn == NULL)
+ return RTSP_EINVAL;
+
+ res = close (conn->fd);
+ conn->fd = -1;
+ if (res != 0)
+ goto sys_error;
+
+ return RTSP_OK;
+
+sys_error:
+ {
+ return RTSP_ESYS;
+ }
+}