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);
}
示例#6
0
/* 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);
}
示例#10
0
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);
}