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; }
static gboolean exchange_packets (GstPluginLoader * l) { gint res; /* Wait for activity on our FDs */ do { do { res = gst_poll_wait (l->fdset, GST_SECOND); } while (res == -1 && (errno == EINTR || errno == EAGAIN)); if (res < 0) return FALSE; GST_LOG ("Poll res = %d. %d bytes pending for write", res, l->tx_buf_write - l->tx_buf_read); if (!l->rx_done) { if (gst_poll_fd_has_error (l->fdset, &l->fd_r) || gst_poll_fd_has_closed (l->fdset, &l->fd_r)) { GST_LOG ("read fd %d closed/errored", l->fd_r.fd); goto fail_and_cleanup; } if (gst_poll_fd_can_read (l->fdset, &l->fd_r)) { if (!read_one (l)) goto fail_and_cleanup; } } if (l->tx_buf_read < l->tx_buf_write) { if (gst_poll_fd_has_error (l->fdset, &l->fd_w) || gst_poll_fd_has_closed (l->fdset, &l->fd_r)) { GST_ERROR ("write fd %d closed/errored", l->fd_w.fd); goto fail_and_cleanup; } if (gst_poll_fd_can_write (l->fdset, &l->fd_w)) { if (!write_one (l)) goto fail_and_cleanup; } } } while (l->tx_buf_read < l->tx_buf_write); return TRUE; fail_and_cleanup: plugin_loader_cleanup_child (l); return FALSE; }
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 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"); recv (pollfd->pollfd.fd, str, 13, 0); 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"); recv (pollfd->pollfd.fd, str, 13, 0); 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 void mess_some_more (void) { GList *walk; gint random; gint removed = 0; g_mutex_lock (fdlock); for (walk = fds; walk;) { GstPollFD *fd = (GstPollFD *) walk->data; walk = g_list_next (walk); random = (gint) (10.0 * rand () / (RAND_MAX + 1.0)); switch (random) { case 0: { /* GstPollFD *newfd = g_new0 (GstPollFD, 1); gst_poll_add_fd (set, newfd); fds = g_list_prepend (fds, newfd); */ break; } case 1: if ((gint) (10.0 * rand () / (RAND_MAX + 1.0)) < 2) { gst_poll_remove_fd (set, fd); fds = g_list_remove (fds, fd); g_free (fd); removed++; } break; case 2: gst_poll_fd_ctl_write (set, fd, TRUE); break; case 3: gst_poll_fd_ctl_write (set, fd, FALSE); break; case 4: gst_poll_fd_ctl_read (set, fd, TRUE); break; case 5: gst_poll_fd_ctl_read (set, fd, FALSE); break; case 6: gst_poll_fd_has_closed (set, fd); break; case 7: gst_poll_fd_has_error (set, fd); break; case 8: gst_poll_fd_can_read (set, fd); break; case 9: gst_poll_fd_can_write (set, fd); break; default: g_assert_not_reached (); break; } } if (g_list_length (fds) < 900) { random = removed + (gint) (2.0 * rand () / (RAND_MAX + 1.0)); while (random) { GstPollFD *newfd = g_new0 (GstPollFD, 1); gst_poll_add_fd (set, newfd); fds = g_list_prepend (fds, newfd); random--; } } g_mutex_unlock (fdlock); }