static GstFlowReturn gst_curl_base_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstCurlBaseSink *sink = GST_CURL_BASE_SINK (bsink); GstMapInfo map; guint8 *data; size_t size; GstFlowReturn ret; GST_LOG ("enter render"); sink = GST_CURL_BASE_SINK (bsink); gst_buffer_map (buf, &map, GST_MAP_READ); data = map.data; size = map.size; GST_OBJECT_LOCK (sink); /* check if the transfer thread has encountered problems while the * pipeline thread was working elsewhere */ if (sink->flow_ret != GST_FLOW_OK) { goto done; } g_assert (sink->transfer_cond->data_available == FALSE); /* if there is no transfer thread created, lets create one */ if (sink->transfer_thread == NULL) { if (!gst_curl_base_sink_transfer_start_unlocked (sink)) { sink->flow_ret = GST_FLOW_ERROR; goto done; } } /* make data available for the transfer thread and notify */ sink->transfer_buf->ptr = data; sink->transfer_buf->len = size; sink->transfer_buf->offset = 0; gst_curl_base_sink_transfer_thread_notify_unlocked (sink); /* wait for the transfer thread to send the data. This will be notified * either when transfer is completed by the curl read callback or by * the thread function if an error has occured. */ gst_curl_base_sink_wait_for_transfer_thread_to_send_unlocked (sink); done: ret = sink->flow_ret; GST_OBJECT_UNLOCK (sink); gst_buffer_unmap (buf, &map); GST_LOG ("exit render"); return ret; }
static void gst_curl_base_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstCurlBaseSink *sink; g_return_if_fail (GST_IS_CURL_BASE_SINK (object)); sink = GST_CURL_BASE_SINK (object); switch (prop_id) { case PROP_LOCATION: g_value_set_string (value, sink->url); break; case PROP_USER_NAME: g_value_set_string (value, sink->user); break; case PROP_USER_PASSWD: g_value_set_string (value, sink->passwd); break; case PROP_FILE_NAME: g_value_set_string (value, sink->file_name); break; case PROP_TIMEOUT: g_value_set_int (value, sink->timeout); break; case PROP_QOS_DSCP: g_value_set_int (value, sink->qos_dscp); break; default: GST_DEBUG_OBJECT (sink, "invalid property id"); break; } }
static gboolean gst_curl_base_sink_start (GstBaseSink * bsink) { GstCurlBaseSink *sink; sink = GST_CURL_BASE_SINK (bsink); /* reset flags */ sink->transfer_cond->data_sent = FALSE; sink->transfer_cond->data_available = FALSE; sink->transfer_cond->wait_for_response = FALSE; sink->transfer_thread_close = FALSE; sink->new_file = TRUE; sink->flow_ret = GST_FLOW_OK; if ((sink->fdset = gst_poll_new (TRUE)) == NULL) { GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("gst_poll_new failed: %s", g_strerror (errno)), (NULL)); return FALSE; } gst_poll_fd_init (&sink->fd); return TRUE; }
static gboolean gst_curl_base_sink_event (GstBaseSink * bsink, GstEvent * event) { GstCurlBaseSink *sink = GST_CURL_BASE_SINK (bsink); GstCurlBaseSinkClass *klass = GST_CURL_BASE_SINK_GET_CLASS (sink); switch (event->type) { case GST_EVENT_EOS: GST_DEBUG_OBJECT (sink, "received EOS"); gst_curl_base_sink_transfer_thread_close (sink); gst_curl_base_sink_wait_for_response (sink); break; case GST_EVENT_CAPS: if (klass->set_mime_type) { GstCaps *caps; gst_event_parse_caps (event, &caps); klass->set_mime_type (sink, caps); } break; default: break; } return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); }
static void gst_curl_base_sink_finalize (GObject * gobject) { GstCurlBaseSink *this = GST_CURL_BASE_SINK (gobject); GST_DEBUG ("finalizing curlsink"); if (this->transfer_thread != NULL) { g_thread_join (this->transfer_thread); } gst_curl_base_sink_transfer_cleanup (this); g_cond_clear (&this->transfer_cond->cond); g_free (this->transfer_cond); g_free (this->transfer_buf); g_free (this->url); g_free (this->user); g_free (this->passwd); g_free (this->file_name); if (this->fdset != NULL) { gst_poll_free (this->fdset); this->fdset = NULL; } G_OBJECT_CLASS (parent_class)->finalize (gobject); }
/* A 'curl_sshkey_cb' callback function. It gets called when the known_host * matching has been done, to allow the application to act and decide for * libcurl how to proceed. * The callback will only be called if CURLOPT_SSH_KNOWNHOSTS is also set! * NOTE: * * use CURLOPT_SSH_KEYFUNCTION to install the callback func * * use CURLOPT_SSH_KEYDATA to pass in the actual "*clientp" */ static gint curl_ssh_sink_sshkey_cb (CURL * easy_handle, /* easy handle */ const struct curl_khkey *knownkey, /* known - key from known_hosts */ const struct curl_khkey *foundkey, /* found - key from remote end */ enum curl_khmatch match, /* libcurl's view on the keys */ void *clientp) { GstCurlSshSink *sink = (GstCurlSshSink *) clientp; /* the default action to be taken upon pub key matching */ guint res_action = CURLKHSTAT_REJECT; switch (match) { case CURLKHMATCH_OK: res_action = CURLKHSTAT_FINE; GST_INFO_OBJECT (sink, "Remote public host key is matching known_hosts, OK to proceed."); break; case CURLKHMATCH_MISMATCH: GST_WARNING_OBJECT (sink, "Remote public host key mismatch in known_hosts, aborting " "connection."); /* Reject the connection. The old mismatching key has to be manually * removed from 'known_hosts' before being able to connect again to * the respective host. */ break; case CURLKHMATCH_MISSING: GST_OBJECT_LOCK (sink); if (sink->ssh_accept_unknownhost == TRUE) { /* the key was not found in known_hosts but the user chose to * accept it */ res_action = CURLKHSTAT_FINE_ADD_TO_FILE; GST_INFO_OBJECT (sink, "Accepting and adding new public host key to " "known_hosts."); } else { /* the key was not found in known_hosts and the user chose not * to accept connections to unknown hosts */ GST_WARNING_OBJECT (sink, "Remote public host key is unknown, rejecting connection."); } GST_OBJECT_UNLOCK (sink); break; default: /* something went wrong, we got some bogus key match result */ GST_CURL_BASE_SINK (sink)->error = g_strdup ("libcurl internal error during known_host matching"); break; } return res_action; }
static gboolean gst_curl_base_sink_unlock_stop (GstBaseSink * bsink) { GstCurlBaseSink *sink; sink = GST_CURL_BASE_SINK (bsink); GST_LOG_OBJECT (sink, "No longer flushing"); gst_poll_set_flushing (sink->fdset, FALSE); return TRUE; }
static gboolean gst_curl_base_sink_stop (GstBaseSink * bsink) { GstCurlBaseSink *sink = GST_CURL_BASE_SINK (bsink); gst_curl_base_sink_transfer_thread_close (sink); if (sink->fdset != NULL) { gst_poll_free (sink->fdset); sink->fdset = NULL; } return TRUE; }
static gboolean gst_curl_smtp_sink_event (GstBaseSink * bsink, GstEvent * event) { GstCurlBaseSink *bcsink = GST_CURL_BASE_SINK (bsink); GstCurlSmtpSink *sink = GST_CURL_SMTP_SINK (bsink); switch (event->type) { case GST_EVENT_EOS: GST_DEBUG_OBJECT (sink, "received EOS"); gst_curl_base_sink_set_live (bcsink, FALSE); GST_OBJECT_LOCK (sink); sink->eos = TRUE; GST_OBJECT_UNLOCK (sink); if (sink->base64_chunk != NULL) add_final_boundary_unlocked (sink); gst_curl_base_sink_transfer_thread_notify_unlocked (bcsink); GST_OBJECT_LOCK (sink); if (sink->base64_chunk != NULL && bcsink->flow_ret == GST_FLOW_OK) { gst_curl_smtp_sink_wait_for_transfer_end_unlocked (sink); } GST_OBJECT_UNLOCK (sink); gst_curl_base_sink_transfer_thread_close (bcsink); break; default: break; } return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); }
static gboolean gst_curl_smtp_sink_event (GstBaseSink * bsink, GstEvent * event) { GstCurlBaseSink *bcsink = GST_CURL_BASE_SINK (bsink); GstCurlSmtpSink *sink = GST_CURL_SMTP_SINK (bsink); GByteArray *array; gchar *boundary_end; switch (event->type) { case GST_EVENT_EOS: GST_DEBUG_OBJECT (sink, "received EOS"); gst_curl_base_sink_set_live (bcsink, FALSE); GST_OBJECT_LOCK (sink); sink->eos = TRUE; GST_OBJECT_UNLOCK (sink); if (sink->base64_chunk != NULL) { gsize len; gint save, state; gchar *data_out; array = sink->base64_chunk->chunk_array; g_assert (array); GST_DEBUG ("adding final boundary"); /* it will need up to 5 bytes if line-breaking is enabled * additional byte is needed for <CR> as it is not automatically added by glib */ data_out = g_malloc (6); save = sink->base64_chunk->save; state = sink->base64_chunk->state; len = g_base64_encode_close (TRUE, data_out, &state, &save); /* workaround */ data_out[len - 1] = '\r'; data_out[len] = '\n'; /* +1 for CR */ g_byte_array_append (array, (guint8 *) data_out, (guint) (len + 1)); g_free (data_out); boundary_end = g_strdup_printf ("\r\n%s\r\n", BOUNDARY_STRING_END); g_byte_array_append (array, (guint8 *) boundary_end, strlen (boundary_end)); g_free (boundary_end); } gst_curl_base_sink_transfer_thread_notify_unlocked (bcsink); GST_OBJECT_LOCK (sink); if (sink->base64_chunk != NULL && bcsink->flow_ret == GST_FLOW_OK) { gst_curl_smtp_sink_wait_for_transfer_end_unlocked (sink); } GST_OBJECT_UNLOCK (sink); gst_curl_base_sink_transfer_thread_close (bcsink); break; default: break; } return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); }
static void gst_curl_base_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { GstCurlBaseSink *sink; GstState cur_state; g_return_if_fail (GST_IS_CURL_BASE_SINK (object)); sink = GST_CURL_BASE_SINK (object); gst_element_get_state (GST_ELEMENT (sink), &cur_state, NULL, 0); if (cur_state != GST_STATE_PLAYING && cur_state != GST_STATE_PAUSED) { GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_LOCATION: g_free (sink->url); sink->url = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "url set to %s", sink->url); break; case PROP_USER_NAME: g_free (sink->user); sink->user = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "user set to %s", sink->user); break; case PROP_USER_PASSWD: g_free (sink->passwd); sink->passwd = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "passwd set to %s", sink->passwd); break; case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_DEBUG_OBJECT (sink, "invalid property id %d", prop_id); break; } GST_OBJECT_UNLOCK (sink); return; } /* in PLAYING or PAUSED state */ GST_OBJECT_LOCK (sink); switch (prop_id) { case PROP_FILE_NAME: g_free (sink->file_name); sink->file_name = g_value_dup_string (value); GST_DEBUG_OBJECT (sink, "file_name set to %s", sink->file_name); gst_curl_base_sink_new_file_notify_unlocked (sink); break; case PROP_TIMEOUT: sink->timeout = g_value_get_int (value); GST_DEBUG_OBJECT (sink, "timeout set to %d", sink->timeout); break; case PROP_QOS_DSCP: sink->qos_dscp = g_value_get_int (value); gst_curl_base_sink_setup_dscp_unlocked (sink); GST_DEBUG_OBJECT (sink, "dscp set to %d", sink->qos_dscp); break; default: GST_WARNING_OBJECT (sink, "cannot set property when PLAYING"); break; } GST_OBJECT_UNLOCK (sink); }