static gpointer delayed_control (gpointer data) { GstPoll *set = data; GstPollFD fd = GST_POLL_FD_INIT; fd.fd = 1; THREAD_START (); g_usleep (500000); gst_poll_add_fd (set, &fd); gst_poll_fd_ctl_write (set, &fd, TRUE); gst_poll_restart (set); THREAD_SYNCHRONIZE (); g_usleep (500000); gst_poll_add_fd (set, &fd); gst_poll_fd_ctl_write (set, &fd, TRUE); gst_poll_restart (set); return NULL; }
static gboolean gst_fd_sink_start (GstBaseSink * basesink) { GstFdSink *fdsink; GstPollFD fd = GST_POLL_FD_INIT; fdsink = GST_FD_SINK (basesink); if (!gst_fd_sink_check_fd (fdsink, fdsink->fd, NULL)) return FALSE; if ((fdsink->fdset = gst_poll_new (TRUE)) == NULL) goto socket_pair; fd.fd = fdsink->fd; gst_poll_add_fd (fdsink->fdset, &fd); gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE); fdsink->bytes_written = 0; fdsink->current_pos = 0; fdsink->seekable = gst_fd_sink_do_seek (fdsink, 0); GST_INFO_OBJECT (fdsink, "seeking supported: %d", fdsink->seekable); return TRUE; /* ERRORS */ socket_pair: { GST_ELEMENT_ERROR (fdsink, RESOURCE, OPEN_READ_WRITE, (NULL), GST_ERROR_SYSTEM); return FALSE; } }
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 void put_chunk (GstPluginLoader * l, GstRegistryChunk * chunk, guint * pos) { guint padsize = 0; guint len; guint8 *out; /* Might need to align the chunk */ if (chunk->align && ((*pos) % ALIGNMENT) != 0) padsize = ALIGNMENT - ((*pos) % ALIGNMENT); len = padsize + chunk->size; if (G_UNLIKELY (l->tx_buf_write + len >= l->tx_buf_size)) { guint new_size = MAX (l->tx_buf_write + len, l->tx_buf_size + l->tx_buf_size / 4) + BUF_GROW_EXTRA; GST_LOG ("Expanding tx buf from %d to %d for chunk of size %d", l->tx_buf_size, new_size, chunk->size); l->tx_buf_size = new_size; l->tx_buf = g_realloc (l->tx_buf, l->tx_buf_size); } out = l->tx_buf + l->tx_buf_write; /* Clear the padding */ if (padsize) memset (out, 0, padsize); memcpy (out + padsize, chunk->data, chunk->size); l->tx_buf_write += len; *pos += len; gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE); };
static void put_packet (GstPluginLoader * l, guint type, guint32 tag, const guint8 * payload, guint32 payload_len) { guint8 *out; guint len = payload_len + HEADER_SIZE; if (l->tx_buf_write + len >= l->tx_buf_size) { GST_LOG ("Expanding tx buf from %d to %d for packet of size %d", l->tx_buf_size, l->tx_buf_write + len + BUF_GROW_EXTRA, len); l->tx_buf_size = l->tx_buf_write + len + BUF_GROW_EXTRA; l->tx_buf = g_realloc (l->tx_buf, l->tx_buf_size); } out = l->tx_buf + l->tx_buf_write; /* one byte packet type */ out[0] = type; /* 3 byte packet tag number */ GST_WRITE_UINT24_BE (out + 1, tag); /* 4 bytes packet length */ GST_WRITE_UINT32_BE (out + 4, payload_len); /* payload */ memcpy (out + HEADER_SIZE, payload, payload_len); /* Write magic into the header */ GST_WRITE_UINT32_BE (out + 8, HEADER_MAGIC); l->tx_buf_write += len; gst_poll_fd_ctl_write (l->fdset, &l->fd_w, TRUE); }
static gboolean gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd) { if (new_fd < 0) return FALSE; if (!gst_fd_sink_check_fd (fdsink, new_fd)) goto invalid; /* assign the fd */ GST_OBJECT_LOCK (fdsink); if (fdsink->fdset) { GstPollFD fd = GST_POLL_FD_INIT; fd.fd = fdsink->fd; gst_poll_remove_fd (fdsink->fdset, &fd); fd.fd = new_fd; gst_poll_add_fd (fdsink->fdset, &fd); gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE); } fdsink->fd = new_fd; g_free (fdsink->uri); fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); GST_OBJECT_UNLOCK (fdsink); return TRUE; invalid: { return FALSE; } }
static gboolean write_one (GstPluginLoader * l) { guint8 *out; guint32 to_write, magic; int res; if (l->tx_buf_read + HEADER_SIZE > l->tx_buf_write) return FALSE; out = l->tx_buf + l->tx_buf_read; magic = GST_READ_UINT32_BE (out + 8); if (magic != HEADER_MAGIC) { GST_ERROR ("Packet magic number is missing. Memory corruption detected"); goto fail_and_cleanup; } to_write = GST_READ_UINT32_BE (out + 4) + HEADER_SIZE; /* Check that the magic is intact, and the size is sensible */ if (to_write > l->tx_buf_size) { GST_ERROR ("Indicated packet size is too large. Corruption detected"); goto fail_and_cleanup; } l->tx_buf_read += to_write; GST_LOG ("Writing packet of size %d bytes to fd %d", to_write, l->fd_w.fd); do { res = write (l->fd_w.fd, out, to_write); if (G_UNLIKELY (res < 0)) { if (errno == EAGAIN || errno == EINTR) continue; /* Failed to write -> child died */ goto fail_and_cleanup; } to_write -= res; out += res; } while (to_write > 0); if (l->tx_buf_read == l->tx_buf_write) { gst_poll_fd_ctl_write (l->fdset, &l->fd_w, FALSE); l->tx_buf_read = l->tx_buf_write = 0; } return TRUE; fail_and_cleanup: plugin_loader_cleanup_child (l); return FALSE; }
/* This function gets called by libcurl after the socket() call but before * the connect() call. */ static int gst_curl_base_sink_transfer_socket_cb (void *clientp, curl_socket_t curlfd, curlsocktype socket_type) { GstCurlBaseSink *sink; gboolean ret = TRUE; sink = (GstCurlBaseSink *) clientp; g_assert (sink); if (curlfd < 0) { /* signal an unrecoverable error to the library which will close the socket and return CURLE_COULDNT_CONNECT */ GST_DEBUG_OBJECT (sink, "no curlfd"); return 1; } GST_OBJECT_LOCK (sink); sink->socket_type = socket_type; if (sink->fd.fd != curlfd) { if (sink->fd.fd > 0 && sink->socket_type != CURLSOCKTYPE_ACCEPT) { ret &= gst_poll_remove_fd (sink->fdset, &sink->fd); } sink->fd.fd = curlfd; ret &= gst_poll_add_fd (sink->fdset, &sink->fd); ret &= gst_poll_fd_ctl_write (sink->fdset, &sink->fd, TRUE); ret &= gst_poll_fd_ctl_read (sink->fdset, &sink->fd, TRUE); } GST_DEBUG_OBJECT (sink, "fd: %d", sink->fd.fd); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_OBJECT_UNLOCK (sink); /* success */ return ret ? 0 : 1; }
static gboolean gst_fd_sink_update_fd (GstFdSink * fdsink, int new_fd, GError ** error) { if (new_fd < 0) { g_set_error (error, GST_URI_ERROR, GST_URI_ERROR_BAD_REFERENCE, "File descriptor %d is not valid", new_fd); return FALSE; } if (!gst_fd_sink_check_fd (fdsink, new_fd, error)) goto invalid; /* assign the fd */ GST_OBJECT_LOCK (fdsink); if (fdsink->fdset) { GstPollFD fd = GST_POLL_FD_INIT; fd.fd = fdsink->fd; gst_poll_remove_fd (fdsink->fdset, &fd); fd.fd = new_fd; gst_poll_add_fd (fdsink->fdset, &fd); gst_poll_fd_ctl_write (fdsink->fdset, &fd, TRUE); } fdsink->fd = new_fd; g_free (fdsink->uri); fdsink->uri = g_strdup_printf ("fd://%d", fdsink->fd); GST_OBJECT_UNLOCK (fdsink); return TRUE; invalid: { return FALSE; } }
/* This function gets called by libcurl after the socket() call but before * the connect() call. */ static int gst_curl_base_sink_transfer_socket_cb (void *clientp, curl_socket_t curlfd, curlsocktype G_GNUC_UNUSED purpose) { GstCurlBaseSink *sink; gboolean ret = TRUE; sink = (GstCurlBaseSink *) clientp; g_assert (sink); if (curlfd < 0) { /* signal an unrecoverable error to the library which will close the socket and return CURLE_COULDNT_CONNECT */ return 1; } gst_poll_fd_init (&sink->fd); sink->fd.fd = curlfd; ret = ret && gst_poll_add_fd (sink->fdset, &sink->fd); ret = ret && gst_poll_fd_ctl_write (sink->fdset, &sink->fd, TRUE); ret = ret && gst_poll_fd_ctl_read (sink->fdset, &sink->fd, TRUE); GST_DEBUG ("fd: %d", sink->fd.fd); GST_OBJECT_LOCK (sink); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_OBJECT_UNLOCK (sink); /* success */ if (ret) { return 0; } else { return 1; } }
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); }
/** * gst_v4l2_buffer_pool_new: * @obj: the v4l2 object owning the pool * * Construct a new buffer pool. * * Returns: the new pool, use gst_object_unref() to free resources */ GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps) { GstV4l2BufferPool *pool; GstStructure *config; gchar *name, *parent_name; gint fd; fd = v4l2_dup (obj->video_fd); if (fd < 0) goto dup_failed; /* setting a significant unique name */ parent_name = gst_object_get_name (GST_OBJECT (obj->element)); name = g_strconcat (parent_name, ":", "pool:", V4L2_TYPE_IS_OUTPUT (obj->type) ? "sink" : "src", NULL); g_free (parent_name); pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, "name", name, NULL); g_free (name); gst_poll_fd_init (&pool->pollfd); pool->pollfd.fd = fd; gst_poll_add_fd (pool->poll, &pool->pollfd); if (V4L2_TYPE_IS_OUTPUT (obj->type)) gst_poll_fd_ctl_write (pool->poll, &pool->pollfd, TRUE); else gst_poll_fd_ctl_read (pool->poll, &pool->pollfd, TRUE); pool->video_fd = fd; pool->obj = obj; pool->can_poll_device = TRUE; pool->vallocator = gst_v4l2_allocator_new (GST_OBJECT (pool), obj->video_fd, &obj->format); if (pool->vallocator == NULL) goto allocator_failed; gst_object_ref (obj->element); config = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool)); gst_buffer_pool_config_set_params (config, caps, obj->info.size, 0, 0); /* This will simply set a default config, but will not configure the pool * because min and max are not valid */ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), config); return GST_BUFFER_POOL (pool); /* ERRORS */ dup_failed: { GST_ERROR ("failed to dup fd %d (%s)", errno, g_strerror (errno)); return NULL; } allocator_failed: { GST_ERROR_OBJECT (pool, "Failed to create V4L2 allocator"); return NULL; } }