diff options
Diffstat (limited to 'gst/fsmsnconference/fs-msn-connection.c')
-rw-r--r-- | gst/fsmsnconference/fs-msn-connection.c | 1134 |
1 files changed, 0 insertions, 1134 deletions
diff --git a/gst/fsmsnconference/fs-msn-connection.c b/gst/fsmsnconference/fs-msn-connection.c deleted file mode 100644 index 0acf8c33..00000000 --- a/gst/fsmsnconference/fs-msn-connection.c +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * Farstream - Farstream MSN Connection - * - * Copyright 2008 Richard Spiers <richard.spiers@gmail.com> - * Copyright 2007 Nokia Corp. - * Copyright 2007-2009 Collabora Ltd. - * @author: Olivier Crete <olivier.crete@collabora.co.uk> - * @author: Youness Alaoui <youness.alaoui@collabora.co.uk> - * - * fs-msn-connection.c - A MSN Connection gobject - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "fs-msn-connection.h" - -#include <arpa/inet.h> -#include <errno.h> -#include <fcntl.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/socket.h> -#include <unistd.h> -#include <stdio.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - -#include <gst/gst.h> -#include <nice/interfaces.h> - -#define GST_CAT_DEFAULT fsmsnconference_debug - -/* Signals */ -enum -{ - SIGNAL_NEW_LOCAL_CANDIDATE, - SIGNAL_LOCAL_CANDIDATES_PREPARED, - SIGNAL_CONNECTED, - SIGNAL_CONNECTION_FAILED, - N_SIGNALS -}; - - -static guint signals[N_SIGNALS]; - -/* props */ -enum -{ - PROP_0, - PROP_SESSION_ID -}; - - -typedef enum { - FS_MSN_STATUS_AUTH, - FS_MSN_STATUS_CONNECTED, - FS_MSN_STATUS_CONNECTED2, - FS_MSN_STATUS_SEND_RECEIVE, - FS_MSN_STATUS_PAUSED, -} FsMsnStatus; - -typedef struct _FsMsnPollFD FsMsnPollFD; -typedef void (*PollFdCallback) (FsMsnConnection *self, FsMsnPollFD *pollfd); - -struct _FsMsnPollFD { - GstPollFD pollfd; - FsMsnStatus status; - gboolean server; - gboolean want_read; - gboolean want_write; - PollFdCallback callback; -}; - -#define FS_MSN_CONNECTION_LOCK(conn) g_rec_mutex_lock(&(conn)->mutex) -#define FS_MSN_CONNECTION_UNLOCK(conn) g_rec_mutex_unlock(&(conn)->mutex) - - -G_DEFINE_TYPE(FsMsnConnection, fs_msn_connection, G_TYPE_OBJECT); - -static void fs_msn_connection_dispose (GObject *object); -static void fs_msn_connection_finalize (GObject *object); -static void fs_msn_connection_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void fs_msn_connection_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); - - -static gboolean fs_msn_connection_attempt_connection_locked ( - FsMsnConnection *connection, - FsCandidate *candidate, - GError **error); -static gboolean fs_msn_open_listening_port_unlock (FsMsnConnection *connection, - guint16 port, - GError **error); - -static void successful_connection_cb (FsMsnConnection *self, FsMsnPollFD *fd); -static void accept_connection_cb (FsMsnConnection *self, FsMsnPollFD *fd); -static void connection_cb (FsMsnConnection *self, FsMsnPollFD *fd); - -static gpointer connection_polling_thread (gpointer data); -static void shutdown_fd (FsMsnConnection *self, FsMsnPollFD *pollfd, - gboolean equal); -static void shutdown_fd_locked (FsMsnConnection *self, FsMsnPollFD *pollfd, - gboolean equal); -static FsMsnPollFD * add_pollfd_locked (FsMsnConnection *self, int fd, - PollFdCallback callback, gboolean read, gboolean write, gboolean server); - -static void -fs_msn_connection_class_init (FsMsnConnectionClass *klass) -{ - GObjectClass *gobject_class = (GObjectClass *) klass; - - gobject_class->dispose = fs_msn_connection_dispose; - gobject_class->finalize = fs_msn_connection_finalize; - gobject_class->get_property = fs_msn_connection_get_property; - gobject_class->set_property = fs_msn_connection_set_property; - - signals[SIGNAL_NEW_LOCAL_CANDIDATE] = g_signal_new - ("new-local-candidate", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__BOXED, - G_TYPE_NONE, 1, FS_TYPE_CANDIDATE); - - signals[SIGNAL_LOCAL_CANDIDATES_PREPARED] = g_signal_new - ("local-candidates-prepared", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - signals[SIGNAL_CONNECTED] = g_signal_new - ("connected", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__UINT, - G_TYPE_NONE, 1, G_TYPE_UINT); - - signals[SIGNAL_CONNECTION_FAILED] = g_signal_new - ("connection-failed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - - g_object_class_install_property (gobject_class, - PROP_SESSION_ID, - g_param_spec_uint ("session-id", - "The session-id of the session", - "This is the session-id of the MSN session", - 1, 9999, 1, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - -static void -fs_msn_connection_init (FsMsnConnection *self) -{ - /* member init */ - - self->poll_timeout = GST_CLOCK_TIME_NONE; - self->poll = gst_poll_new (TRUE); - gst_poll_set_flushing (self->poll, FALSE); - self->pollfds = g_ptr_array_new (); - - g_rec_mutex_init (&self->mutex); -} - -static void -fs_msn_connection_dispose (GObject *object) -{ - FsMsnConnection *self = FS_MSN_CONNECTION (object); - - FS_MSN_CONNECTION_LOCK(self); - - if (self->polling_thread) - { - GThread *polling_thread = g_thread_ref (self->polling_thread); - gst_poll_set_flushing (self->poll, TRUE); - FS_MSN_CONNECTION_UNLOCK(self); - g_thread_join (polling_thread); - FS_MSN_CONNECTION_LOCK(self); - g_thread_unref (polling_thread); - self->polling_thread = NULL; - } - - FS_MSN_CONNECTION_UNLOCK(self); - - G_OBJECT_CLASS (fs_msn_connection_parent_class)->dispose (object); -} - -static void -fs_msn_connection_finalize (GObject *object) -{ - FsMsnConnection *self = FS_MSN_CONNECTION (object); - gint i; - - g_free (self->local_recipient_id); - g_free (self->remote_recipient_id); - - gst_poll_free (self->poll); - - for (i = 0; i < self->pollfds->len; i++) - { - FsMsnPollFD *p = g_ptr_array_index(self->pollfds, i); - close (p->pollfd.fd); - g_slice_free (FsMsnPollFD, p); - } - g_ptr_array_free (self->pollfds, TRUE); - - g_rec_mutex_clear (&self->mutex); - - G_OBJECT_CLASS (fs_msn_connection_parent_class)->finalize (object); -} - -/** - * fs_msn_connection_new: - * @session: The #FsMsnSession this connection is a child of - * @participant: The #FsMsnParticipant this connection is for - * @direction: the initial #FsDirection for this connection - * - * - * This function create a new connection - * - * Returns: the newly created string or NULL on error - */ - -FsMsnConnection * -fs_msn_connection_new (guint session_id, gboolean producer, guint initial_port) -{ - FsMsnConnection *self = g_object_new (FS_TYPE_MSN_CONNECTION, NULL); - - if (self) { - self->session_id = session_id; - self->initial_port = initial_port; - self->producer = producer; - } - - return self; -} - -static void -fs_msn_connection_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - FsMsnConnection *self = FS_MSN_CONNECTION (object); - - FS_MSN_CONNECTION_LOCK (self); - switch (prop_id) - { - case PROP_SESSION_ID: - g_value_set_uint (value, self->session_id); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - FS_MSN_CONNECTION_UNLOCK (self); -} - -static void -fs_msn_connection_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - FsMsnConnection *self = FS_MSN_CONNECTION (object); - - FS_MSN_CONNECTION_LOCK (self); - switch (prop_id) - { - case PROP_SESSION_ID: - self->session_id = g_value_get_uint (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } - FS_MSN_CONNECTION_LOCK (self); - -} - -gboolean -fs_msn_connection_gather_local_candidates (FsMsnConnection *self, - GError **error) -{ - gboolean ret; - - FS_MSN_CONNECTION_LOCK(self); - - self->polling_thread = g_thread_try_new ("msn polling thread", - connection_polling_thread, self, error); - - if (!self->polling_thread) - { - FS_MSN_CONNECTION_UNLOCK(self); - return FALSE; - } - - ret = fs_msn_open_listening_port_unlock (self, self->initial_port, error); - - g_signal_emit (self, signals[SIGNAL_LOCAL_CANDIDATES_PREPARED], 0); - - return ret; -} - - -/** - * fs_msn_connection_add_remote_candidate: - */ -gboolean -fs_msn_connection_add_remote_candidates (FsMsnConnection *self, - GList *candidates, GError **error) -{ - GList *item = NULL; - gchar *recipient_id = NULL; - gboolean ret = FALSE; - guint session_id = 0; - - if (!candidates) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "Candidate list can no be empty"); - return FALSE; - } - - FS_MSN_CONNECTION_LOCK(self); - - recipient_id = self->remote_recipient_id; - - for (item = candidates; item; item = g_list_next (item)) - { - FsCandidate *candidate = item->data; - - if (!candidate->ip || !candidate->port) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "The candidate passed does not contain a valid ip or port"); - goto out; - } - if (!candidate->foundation) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "The candidate passed does not have a foundation (MSN recipient ID)"); - goto out; - } - if (recipient_id) - { - if (g_strcmp0 (candidate->foundation, recipient_id) != 0) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "The candidates do not have the same recipient ID"); - goto out; - } - } - else - { - recipient_id = candidate->foundation; - } - - if (candidate->username) - { - gint sid = atoi (candidate->username); - - if (sid < 1 || sid > 9999) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "The session ID (in the username) must be between 1 and 9999," - " %d is invalid", sid); - goto out; - } - - if (session_id) - { - if (session_id != sid) - { - g_set_error (error, FS_ERROR, FS_ERROR_INVALID_ARGUMENTS, - "The candidates do not have the same session ID" - " (in the username)"); - goto out; - } - } - else - { - session_id = sid; - } - } - } - - self->remote_recipient_id = g_strdup (recipient_id); - self->session_id = session_id; - ret = TRUE; - for (item = candidates; item; item = g_list_next (item)) - { - FsCandidate *candidate = item->data; - if (!fs_msn_connection_attempt_connection_locked (self, candidate, error)) - { - ret = FALSE; - break; - } - } - - out: - FS_MSN_CONNECTION_UNLOCK(self); - return ret; -} - - - -static GList * -filter_ips_ipv4 (GList *ips) -{ - GList *item; - - for (item = ips; item;) - { - gchar *ip = item->data; - GList *next = item->next; - - if (!strchr (ip, '.')) - { - g_free (ip); - ips = g_list_delete_link (ips, item); - } - item = next; - } - - return ips; -} - -static gboolean -fs_msn_open_listening_port_unlock (FsMsnConnection *self, guint16 port, - GError **error) -{ - gint fd = -1; - struct sockaddr_in myaddr; - guint myaddr_len = sizeof (struct sockaddr_in); - FsCandidate * candidate = NULL; - GList *addresses = nice_interfaces_get_local_ips (FALSE); - GList *item = NULL; - gchar *session_id; - - addresses = filter_ips_ipv4 (addresses); - - - GST_DEBUG ("Attempting to listen on port %d.....",port); - - if ( (fd = socket(PF_INET, SOCK_STREAM, 0)) < 0 ) - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not create socket: %s", error_str); - goto error; - } - - // set non-blocking mode - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - for (;;) { - GST_DEBUG ("Attempting to listen on port %d.....",port); - memset(&myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; - myaddr.sin_port = htons (port); - // bind - if (bind(fd, (struct sockaddr *) &myaddr, sizeof(myaddr)) != 0) - { - if (port != 0 && errno == EADDRINUSE) - { - port++; - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not bind socket: %s", error_str); - goto error; - } - } else { - /* Listen */ - if (listen(fd, 3) != 0) - { - if (port != 0 && errno == EADDRINUSE) - { - port++; - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not listen on socket: %s", error_str); - goto error; - } - } - else - { - goto done; - } - } - } - - done: - - if (getsockname (fd, (struct sockaddr *) &myaddr, &myaddr_len) < 0) { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not get the socket name: %s", error_str); - goto error; - } - port = ntohs (myaddr.sin_port); - add_pollfd_locked (self, fd, accept_connection_cb, TRUE, TRUE, FALSE); - - GST_DEBUG ("Listening on port %d", port); - - self->local_recipient_id = g_strdup_printf ("%d", - g_random_int_range (100, 199)); - session_id = g_strdup_printf ("%u", self->session_id); - - FS_MSN_CONNECTION_UNLOCK (self); - - for (item = addresses; - item; - item = g_list_next (item)) - { - candidate = fs_candidate_new (self->local_recipient_id, 1, - FS_CANDIDATE_TYPE_HOST, FS_NETWORK_PROTOCOL_TCP, item->data, port); - candidate->username = g_strdup (session_id); - - g_signal_emit (self, signals[SIGNAL_NEW_LOCAL_CANDIDATE], 0, candidate); - - fs_candidate_destroy (candidate); - } - - g_free (session_id); - - g_list_foreach (addresses, (GFunc) g_free, NULL); - g_list_free (addresses); - - return TRUE; - - error: - if (fd >= 0) - close (fd); - g_list_foreach (addresses, (GFunc) g_free, NULL); - g_list_free (addresses); - FS_MSN_CONNECTION_UNLOCK (self); - return FALSE; -} - -static gboolean -fs_msn_connection_attempt_connection_locked (FsMsnConnection *connection, - FsCandidate *candidate, - GError **error) -{ - FsMsnConnection *self = FS_MSN_CONNECTION (connection); - gint fd = -1; - gint ret; - struct sockaddr_in theiraddr; - memset(&theiraddr, 0, sizeof(theiraddr)); - - - if ( (fd = socket(PF_INET, SOCK_STREAM, 0)) == -1 ) - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not create socket: %s", error_str); - return FALSE; - } - - // set non-blocking mode - fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); - - theiraddr.sin_family = AF_INET; - theiraddr.sin_addr.s_addr = inet_addr (candidate->ip); - theiraddr.sin_port = htons (candidate->port); - - GST_DEBUG ("Attempting connection to %s %d on socket %d", candidate->ip, - candidate->port, fd); - // this is non blocking, the return value isn't too usefull - ret = connect (fd, (struct sockaddr *) &theiraddr, sizeof (theiraddr)); - if (ret < 0 && errno != EINPROGRESS) - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - g_set_error (error, FS_ERROR, FS_ERROR_NETWORK, - "Could not connect socket: %s", error_str); - close (fd); - return FALSE; - } - - FS_MSN_CONNECTION_LOCK (self); - add_pollfd_locked (self, fd, successful_connection_cb, TRUE, TRUE, FALSE); - FS_MSN_CONNECTION_UNLOCK (self); - - return TRUE; -} - -static void -accept_connection_cb (FsMsnConnection *self, FsMsnPollFD *pollfd) -{ - struct sockaddr_in in; - int fd = -1; - socklen_t n = sizeof (in); - - if (gst_poll_fd_has_error (self->poll, &pollfd->pollfd) || - gst_poll_fd_has_closed (self->poll, &pollfd->pollfd)) - { - GST_WARNING ("Error in accept socket : %d", pollfd->pollfd.fd); - goto error; - } - - if ((fd = accept(pollfd->pollfd.fd, - (struct sockaddr*) &in, &n)) == -1) - { - GST_ERROR ("Error while running accept() %d", errno); - return; - } - - FS_MSN_CONNECTION_LOCK (self); - add_pollfd_locked (self, fd, connection_cb, TRUE, FALSE, TRUE); - FS_MSN_CONNECTION_UNLOCK (self); - - return; - - /* Error */ - error: - GST_WARNING ("Got error from fd %d, closing", fd); - // find, shutdown and remove channel from fdlist - shutdown_fd (self, pollfd, TRUE); - - return; -} - - -static void -successful_connection_cb (FsMsnConnection *self, FsMsnPollFD *pollfd) -{ - gint error; - socklen_t option_len; - - GST_DEBUG ("handler called on fd %d", pollfd->pollfd.fd); - - errno = 0; - if (gst_poll_fd_has_error (self->poll, &pollfd->pollfd) || - gst_poll_fd_has_closed (self->poll, &pollfd->pollfd)) - { - GST_WARNING ("connecton closed or error"); - goto error; - } - - option_len = sizeof(error); - - /* Get the error option */ - if (getsockopt(pollfd->pollfd.fd, SOL_SOCKET, SO_ERROR, (void*) &error, &option_len) < 0) - { - g_warning ("getsockopt() failed"); - goto error; - } - - /* Check if there is an error */ - if (error) - { - GST_WARNING ("getsockopt gave an error : %d", error); - goto error; - } - - pollfd->callback = connection_cb; - - GST_DEBUG ("connection succeeded on socket %p", pollfd); - return; - - /* Error */ - error: - GST_WARNING ("Got error from fd %d, closing", pollfd->pollfd.fd); - // find, shutdown and remove channel from fdlist - shutdown_fd (self, pollfd, TRUE); - - return; -} - - -static void -connection_cb (FsMsnConnection *self, FsMsnPollFD *pollfd) -{ - gboolean success = FALSE; - - GST_DEBUG ("handler called on fd:%d server: %d status:%d r:%d w:%d", - pollfd->pollfd.fd, - pollfd->server, pollfd->status, - gst_poll_fd_can_read (self->poll, &pollfd->pollfd), - gst_poll_fd_can_write (self->poll, &pollfd->pollfd)); - - if (gst_poll_fd_has_error (self->poll, &pollfd->pollfd) || - gst_poll_fd_has_closed (self->poll, &pollfd->pollfd)) - { - GST_WARNING ("connecton closed or error (error: %d closed: %d)", - gst_poll_fd_has_error (self->poll, &pollfd->pollfd), - gst_poll_fd_has_closed (self->poll, &pollfd->pollfd)); - goto error; - } - - if (gst_poll_fd_can_read (self->poll, &pollfd->pollfd)) - { - switch (pollfd->status) - { - case FS_MSN_STATUS_AUTH: - if (pollfd->server) - { - gchar str[35] = {0}; - gchar check[35] = {0}; - - if (recv (pollfd->pollfd.fd, str, 34, 0) == 34) - { - GST_DEBUG ("Got %s, checking if it's auth", str); - FS_MSN_CONNECTION_LOCK(self); - snprintf(check, 35, "recipientid=%s&sessionid=%d\r\n\r\n", - self->local_recipient_id, self->session_id); - FS_MSN_CONNECTION_UNLOCK(self); - if (strncmp (str, check, 35) == 0) - { - GST_DEBUG ("Authentication successful"); - pollfd->status = FS_MSN_STATUS_CONNECTED; - pollfd->want_write = TRUE; - gst_poll_fd_ctl_write (self->poll, &pollfd->pollfd, TRUE); - } - else - { - GST_WARNING ("Authentication failed check=%s", check); - goto error; - } - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("auth: %s", error_str); - goto error; - } - - } else { - GST_ERROR ("shouldn't receive data when client on AUTH state"); - goto error; - } - break; - case FS_MSN_STATUS_CONNECTED: - if (!pollfd->server) - { - gchar str[14] = {0}; - ssize_t size; - - size = recv (pollfd->pollfd.fd, str, 13, MSG_PEEK); - if (size > 0) - { - GST_DEBUG ("Got %s, checking if it's connected", str); - if (size == 13 && strcmp (str, "connected\r\n\r\n") == 0) - { - GST_DEBUG ("connection successful"); - if (recv (pollfd->pollfd.fd, str, 13, 0) != 13) - { - GST_WARNING ("Could not read 13 bytes that had previously" - " been peeked at!"); - goto error; - } - pollfd->status = FS_MSN_STATUS_CONNECTED2; - pollfd->want_write = TRUE; - gst_poll_fd_ctl_write (self->poll, &pollfd->pollfd, TRUE); - } - else if (!self->producer) - { - GST_DEBUG ("connection successful"); - pollfd->status = FS_MSN_STATUS_SEND_RECEIVE; - success = TRUE; - } - else - { - GST_WARNING ("connected failed"); - goto error; - } - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("recv: %s", error_str); - goto error; - } - } else { - GST_ERROR ("shouldn't receive data when server on CONNECTED state"); - goto error; - } - break; - case FS_MSN_STATUS_CONNECTED2: - if (pollfd->server) - { - gchar str[14] = {0}; - ssize_t size; - - size = recv (pollfd->pollfd.fd, str, 13, MSG_PEEK); - if (size > 0) - { - GST_DEBUG ("Got %s, checking if it's connected", str); - if (size == 13 && strcmp (str, "connected\r\n\r\n") == 0) - { - GST_DEBUG ("connection successful"); - if (recv (pollfd->pollfd.fd, str, 13, 0) != 13) - { - GST_WARNING ("Could not read 13 bytes that had previously" - " been peeked at!"); - - goto error; - } - pollfd->status = FS_MSN_STATUS_SEND_RECEIVE; - success = TRUE; - } - else if (!self->producer) - { - GST_DEBUG ("connection successful"); - pollfd->status = FS_MSN_STATUS_SEND_RECEIVE; - success = TRUE; - } - else - { - GST_WARNING ("connected failed"); - goto error; - } - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("recv: %s", error_str); - goto error; - } - - } else { - GST_ERROR ("shouldn't receive data when client on CONNECTED2 state"); - goto error; - } - break; - default: - GST_ERROR ("Invalid status %d", pollfd->status); - goto error; - break; - - } - } - else if (gst_poll_fd_can_write (self->poll, &pollfd->pollfd)) - { - pollfd->want_write = FALSE; - gst_poll_fd_ctl_write (self->poll, &pollfd->pollfd, FALSE); - switch (pollfd->status) - { - case FS_MSN_STATUS_AUTH: - if (!pollfd->server) - { - gchar *str; - FS_MSN_CONNECTION_LOCK(self); - str = g_strdup_printf("recipientid=%s&sessionid=%d\r\n\r\n", - self->remote_recipient_id, self->session_id); - FS_MSN_CONNECTION_UNLOCK(self); - if (send(pollfd->pollfd.fd, str, strlen (str), 0) != -1) - { - GST_DEBUG ("Sent %s", str); - pollfd->status = FS_MSN_STATUS_CONNECTED; - g_free (str); - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("auth send: %s", error_str); - g_free (str); - goto error; - } - - } - break; - case FS_MSN_STATUS_CONNECTED: - if (pollfd->server) - { - - if (send(pollfd->pollfd.fd, "connected\r\n\r\n", 13, 0) != -1) - { - GST_DEBUG ("sent connected"); - if (self->producer) - { - pollfd->status = FS_MSN_STATUS_SEND_RECEIVE; - success = TRUE; - } - else - { - pollfd->status = FS_MSN_STATUS_CONNECTED2; - } - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("sending connected: %s", error_str); - goto error; - } - } else { - GST_DEBUG ("shouldn't receive data when server on CONNECTED state"); - goto error; - } - break; - case FS_MSN_STATUS_CONNECTED2: - if (!pollfd->server) - { - - if (send(pollfd->pollfd.fd, "connected\r\n\r\n", 13, 0) != -1) - { - GST_DEBUG ("sent connected"); - pollfd->status = FS_MSN_STATUS_SEND_RECEIVE; - success = TRUE; - } - else - { - gchar error_str[256]; - strerror_r (errno, error_str, 256); - GST_WARNING ("sending connected: %s", error_str); - goto error; - } - } else { - GST_ERROR ("shouldn't receive data when client on CONNECTED2 state"); - goto error; - } - break; - default: - GST_ERROR ("Invalid status %d", pollfd->status); - goto error; - break; - } - } - - if (success) { - // success! we need to shutdown/close all other channels - shutdown_fd (self, pollfd, FALSE); - - g_signal_emit (self, signals[SIGNAL_CONNECTED], 0, pollfd->pollfd.fd); - - pollfd->want_read = FALSE; - pollfd->want_write = FALSE; - gst_poll_fd_ctl_read (self->poll, &pollfd->pollfd, FALSE); - gst_poll_fd_ctl_write (self->poll, &pollfd->pollfd, FALSE); - } - - return; - error: - /* Error */ - GST_WARNING ("Got error from fd %d, closing", pollfd->pollfd.fd); - shutdown_fd (self, pollfd, TRUE); - - FS_MSN_CONNECTION_LOCK (self); - success = (self->pollfds->len > 1); - FS_MSN_CONNECTION_UNLOCK (self); - - if (!success) - g_signal_emit (self, signals[SIGNAL_CONNECTION_FAILED], 0); - - return; -} - -static gpointer -connection_polling_thread (gpointer data) -{ - FsMsnConnection *self = data; - gint ret; - GstClockTime timeout; - GstPoll * poll; - - FS_MSN_CONNECTION_LOCK(self); - timeout = self->poll_timeout; - poll = self->poll; - GST_DEBUG ("poll waiting %d", self->pollfds->len); - FS_MSN_CONNECTION_UNLOCK(self); - - while ((ret = gst_poll_wait (poll, timeout)) >= 0) - { - GST_DEBUG ("gst_poll_wait returned : %d", ret); - FS_MSN_CONNECTION_LOCK(self); - if (ret > 0) - { - gint i; - - for (i = 0; i < self->pollfds->len; i++) - { - FsMsnPollFD *pollfd = NULL; - - pollfd = g_ptr_array_index(self->pollfds, i); - - GST_DEBUG ("ret %d - i = %d, len = %d", ret, i, self->pollfds->len); - - GST_DEBUG ("%p - error %d, close %d, read %d-%d, write %d-%d", - pollfd, - gst_poll_fd_has_error (poll, &pollfd->pollfd), - gst_poll_fd_has_closed (poll, &pollfd->pollfd), - pollfd->want_read, - gst_poll_fd_can_read (poll, &pollfd->pollfd), - pollfd->want_write, - gst_poll_fd_can_write (poll, &pollfd->pollfd)); - - if (gst_poll_fd_has_error (poll, &pollfd->pollfd) || - gst_poll_fd_has_closed (poll, &pollfd->pollfd)) - { - pollfd->callback (self, pollfd); - shutdown_fd_locked (self, pollfd, TRUE); - i--; - continue; - } - if ((pollfd->want_read && - gst_poll_fd_can_read (poll, &pollfd->pollfd)) || - (pollfd->want_write && - gst_poll_fd_can_write (poll, &pollfd->pollfd))) - { - pollfd->callback (self, pollfd); - } - - } - } - timeout = self->poll_timeout; - FS_MSN_CONNECTION_UNLOCK(self); - } - - return NULL; -} - - -static void -shutdown_fd (FsMsnConnection *self, FsMsnPollFD *pollfd, gboolean equal) -{ - FS_MSN_CONNECTION_LOCK (self); - shutdown_fd_locked (self, pollfd, equal); - FS_MSN_CONNECTION_UNLOCK (self); -} - -static void -shutdown_fd_locked (FsMsnConnection *self, FsMsnPollFD *pollfd, gboolean equal) -{ - gint i; - guint closed = 0; - - for (i = 0; i < self->pollfds->len; i++) - { - FsMsnPollFD *p = g_ptr_array_index(self->pollfds, i); - if ((equal && p == pollfd) || (!equal && p != pollfd)) - { - GST_DEBUG ("Shutting down p %p (fd %d)", p, p->pollfd.fd); - - if (!gst_poll_fd_has_closed (self->poll, &p->pollfd)) - close (p->pollfd.fd); - if (!gst_poll_remove_fd (self->poll, &p->pollfd)) - GST_WARNING ("Could not remove pollfd %p", p); - g_ptr_array_remove_index_fast (self->pollfds, i); - g_slice_free (FsMsnPollFD, p); - closed++; - i--; - } - } - - if (closed) - gst_poll_restart (self->poll); - else - GST_WARNING ("Could find pollfd to remove"); -} - -static FsMsnPollFD * -add_pollfd_locked (FsMsnConnection *self, int fd, PollFdCallback callback, - gboolean read, gboolean write, gboolean server) -{ - FsMsnPollFD *pollfd = g_slice_new0 (FsMsnPollFD); - gst_poll_fd_init (&pollfd->pollfd); - pollfd->pollfd.fd = fd; - pollfd->server = server; - pollfd->want_read = read; - pollfd->want_write = write; - pollfd->status = FS_MSN_STATUS_AUTH; - - gst_poll_add_fd (self->poll, &pollfd->pollfd); - - gst_poll_fd_ctl_read (self->poll, &pollfd->pollfd, read); - gst_poll_fd_ctl_write (self->poll, &pollfd->pollfd, write); - pollfd->callback = callback; - - GST_DEBUG ("ADD_POLLFD %p (%p) - error %d, close %d, read %d-%d, write %d-%d", - self->pollfds, pollfd, - gst_poll_fd_has_error (self->poll, &pollfd->pollfd), - gst_poll_fd_has_closed (self->poll, &pollfd->pollfd), - pollfd->want_read, - gst_poll_fd_can_read (self->poll, &pollfd->pollfd), - pollfd->want_write, - gst_poll_fd_can_write (self->poll, &pollfd->pollfd)); - - g_ptr_array_add (self->pollfds, pollfd); - gst_poll_restart (self->poll); - return pollfd; -} |