webrtcbin: Add settings for HTTP proxy
authorJohan Sternerup <johast@axis.com>
Mon, 31 Aug 2020 12:04:54 +0000 (14:04 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 18 Nov 2022 15:00:58 +0000 (15:00 +0000)
Pass this to libnice which has a simple HTTP 1.0 proxy with basic
authentication only.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/2867>

subprojects/gst-plugins-bad/docs/plugins/gst_plugins_cache.json
subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c
subprojects/gst-plugins-bad/gst-libs/gst/webrtc/ice.c
subprojects/gst-plugins-bad/gst-libs/gst/webrtc/ice.h
subprojects/gst-plugins-bad/gst-libs/gst/webrtc/nice/nice.c

index 243de9f..30a8ccf 100644 (file)
                         "type": "GstWebRTCSessionDescription",
                         "writable": false
                     },
+                    "http-proxy": {
+                        "blurb": "A HTTP proxy for use with TURN/TCP of the form http://[username:password@]hostname[:port]",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "NULL",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gchararray",
+                        "writable": true
+                    },
                     "ice-agent": {
                         "blurb": "The WebRTC ICE agent",
                         "conditionally-available": false,
index 5d59ee6..870b0b2 100644 (file)
@@ -533,6 +533,7 @@ enum
   PROP_ICE_AGENT,
   PROP_LATENCY,
   PROP_SCTP_TRANSPORT,
+  PROP_HTTP_PROXY
 };
 
 static guint gst_webrtc_bin_signals[LAST_SIGNAL] = { 0 };
@@ -8058,6 +8059,10 @@ gst_webrtc_bin_set_property (GObject * object, guint prop_id,
     case PROP_ICE_AGENT:
       webrtc->priv->ice = g_value_get_object (value);
       break;
+    case PROP_HTTP_PROXY:
+      gst_webrtc_ice_set_http_proxy (webrtc->priv->ice,
+          g_value_get_string (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -8135,6 +8140,10 @@ gst_webrtc_bin_get_property (GObject * object, guint prop_id,
     case PROP_SCTP_TRANSPORT:
       g_value_set_object (value, webrtc->priv->sctp_transport);
       break;
+    case PROP_HTTP_PROXY:
+      g_value_take_string (value,
+          gst_webrtc_ice_get_http_proxy (webrtc->priv->ice));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -8420,6 +8429,21 @@ gst_webrtc_bin_class_init (GstWebRTCBinClass * klass)
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
   /**
+   * GstWebRTCBin:http-proxy:
+   *
+   * A HTTP proxy for use with TURN/TCP of the form
+   * http://[username:password@]hostname[:port]
+   *
+   * Since: 1.22
+   */
+  g_object_class_install_property (gobject_class,
+      PROP_HTTP_PROXY,
+      g_param_spec_string ("http-proxy", "HTTP Proxy",
+          "A HTTP proxy for use with TURN/TCP of the form "
+          "http://[username:password@]hostname[:port]",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
    * GstWebRTCBin:sctp-transport:
    *
    * The WebRTC SCTP Transport
index f9ae663..2328d0b 100644 (file)
@@ -452,6 +452,45 @@ gst_webrtc_ice_get_turn_server (GstWebRTCICE * ice)
   return GST_WEBRTC_ICE_GET_CLASS (ice)->get_turn_server (ice);
 }
 
+/**
+ * gst_webrtc_ice_set_http_proxy:
+ * @ice: The #GstWebRTCICE
+ * @uri: (transfer none): URI of the HTTP proxy of the form
+ *   http://[username:password@]hostname[:port]
+ *
+ * Set HTTP Proxy to be used when connecting to TURN server.
+ *
+ * Since: 1.22
+ */
+void
+gst_webrtc_ice_set_http_proxy (GstWebRTCICE * ice, const gchar * uri_s)
+{
+  g_return_if_fail (GST_IS_WEBRTC_ICE (ice));
+  g_assert (GST_WEBRTC_ICE_GET_CLASS (ice)->set_http_proxy);
+
+  GST_WEBRTC_ICE_GET_CLASS (ice)->set_http_proxy (ice, uri_s);
+}
+
+/**
+ * gst_webrtc_ice_get_http_proxy:
+ * @ice: The #GstWebRTCICE
+ *
+ * Returns: (transfer full): URI of the HTTP proxy of the form
+ *   http://[username:password@]hostname[:port]
+ *
+ * Get HTTP Proxy to be used when connecting to TURN server.
+ *
+ * Since: 1.22
+ */
+gchar *
+gst_webrtc_ice_get_http_proxy (GstWebRTCICE * ice)
+{
+  g_return_val_if_fail (GST_IS_WEBRTC_ICE (ice), NULL);
+  g_assert (GST_WEBRTC_ICE_GET_CLASS (ice)->get_http_proxy);
+
+  return GST_WEBRTC_ICE_GET_CLASS (ice)->get_http_proxy (ice);
+}
+
 
 static void
 gst_webrtc_ice_set_property (GObject * object, guint prop_id,
@@ -516,6 +555,8 @@ gst_webrtc_ice_class_init (GstWebRTCICEClass * klass)
   klass->get_stun_server = NULL;
   klass->set_turn_server = NULL;
   klass->get_turn_server = NULL;
+  klass->get_http_proxy = NULL;
+  klass->set_http_proxy = NULL;
   klass->set_tos = NULL;
   klass->set_on_ice_candidate = NULL;
   klass->get_local_candidates = NULL;
index 38e8bf6..f67889b 100644 (file)
@@ -106,6 +106,33 @@ struct _GstWebRTCICEClass {
   void (*set_turn_server)                              (GstWebRTCICE * ice,
                                                         const gchar * uri);
   gchar * (*get_turn_server)                           (GstWebRTCICE * ice);
+
+  /**
+   * GstWebRTCICEClass::set_http_proxy:
+   * @ice: a #GstWebRTCICE
+   * @uri: (transfer none): URI of the HTTP proxy of the form
+   *   http://[username:password@]hostname[:port]
+   *
+   * Set HTTP Proxy to be used when connecting to TURN server.
+   *
+   * Since: 1.22
+   */
+  void (*set_http_proxy)                               (GstWebRTCICE * ice,
+                                                        const gchar * uri);
+
+  /**
+   * GstWebRTCICEClass::get_http_proxy:
+   * @ice: a #GstWebRTCICE
+   *
+   * Get HTTP Proxy to be used when connecting to TURN server.
+   *
+   * Returns: (transfer full): URI of the HTTP proxy of the form
+   *   http://[username:password@]hostname[:port]
+   *
+   * Since: 1.22
+   */
+  gchar * (*get_http_proxy)                            (GstWebRTCICE * ice);
+
   void (*set_tos)                                      (GstWebRTCICE * ice,
                                                         GstWebRTCICEStream * stream,
                                                         guint tos);
@@ -187,6 +214,13 @@ GST_WEBRTC_API
 gchar *                     gst_webrtc_ice_get_turn_server          (GstWebRTCICE * ice);
 
 GST_WEBRTC_API
+void                        gst_webrtc_ice_set_http_proxy           (GstWebRTCICE * ice,
+                                                                     const gchar * uri);
+
+GST_WEBRTC_API
+gchar *                     gst_webrtc_ice_get_http_proxy           (GstWebRTCICE * ice);
+
+GST_WEBRTC_API
 void                        gst_webrtc_ice_set_on_ice_candidate     (GstWebRTCICE * ice,
                                                                      GstWebRTCICEOnCandidateFunc func,
                                                                      gpointer user_data,
index ce1e430..defc97c 100644 (file)
@@ -34,6 +34,8 @@
     NICE_VERSION_MICRO >= (micro)))
 #endif
 
+#define HTTP_PROXY_PORT_DEFAULT 3128
+
 /* XXX:
  *
  * - are locally generated remote candidates meant to be readded to libnice?
@@ -74,6 +76,8 @@ struct _GstWebRTCNicePrivate
   GstUri *turn_server;
 
   GHashTable *turn_servers;
+
+  GstUri *http_proxy;
 };
 
 #define gst_webrtc_nice_parent_class parent_class
@@ -1391,6 +1395,106 @@ out:
 }
 
 static void
+on_http_proxy_resolved (GstWebRTCICE * ice, GAsyncResult * res,
+    gpointer user_data)
+{
+  GstWebRTCNice *nice = GST_WEBRTC_NICE (ice);
+  GstUri *uri = user_data;
+  GList *addresses;
+  GError *error = NULL;
+  const gchar *userinfo;
+  gchar *user = NULL;
+  gchar *pass = NULL;
+  gchar *ip = NULL;
+  guint port = GST_URI_NO_PORT;
+
+  if (!(addresses = resolve_host_finish (nice, res, &error))) {
+    GST_WARNING_OBJECT (ice, "Failed to resolve http proxy: %s",
+        error->message);
+    g_clear_error (&error);
+    return;
+  }
+
+  /* XXX: only the first IP is used */
+  ip = g_inet_address_to_string (addresses->data);
+
+  if (!ip) {
+    GST_ERROR_OBJECT (ice, "failed to resolve host for proxy");
+    gst_uri_unref (uri);
+    return;
+  }
+
+  port = gst_uri_get_port (uri);
+  if (port == GST_URI_NO_PORT) {
+    port = HTTP_PROXY_PORT_DEFAULT;
+    GST_DEBUG_OBJECT (ice, "Proxy server has no port, assuming %u",
+        HTTP_PROXY_PORT_DEFAULT);
+  }
+
+  userinfo = gst_uri_get_userinfo (uri);
+  _parse_userinfo (userinfo, &user, &pass);
+
+  g_object_set (nice->priv->nice_agent,
+      "proxy-ip", ip, "proxy-port", port, "proxy-type", NICE_PROXY_TYPE_HTTP,
+      "proxy-username", user, "proxy-password", pass, NULL);
+
+  g_free (ip);
+  g_free (user);
+  g_free (pass);
+}
+
+static GstUri *
+_set_http_proxy (GstWebRTCICE * ice, const gchar * s)
+{
+  GstWebRTCNice *nice = GST_WEBRTC_NICE (ice);
+  GstUri *uri = gst_uri_from_string_escaped (s);
+  const gchar *msg =
+      "must be of the form http://[username:password@]<host>[:<port>]";
+  const gchar *host = NULL;
+  const gchar *userinfo;
+  gchar *user = NULL, *pass = NULL;
+
+  GST_DEBUG_OBJECT (ice, "setting http proxy %s", s);
+
+  if (!uri) {
+    GST_ERROR_OBJECT (ice, "Couldn't parse http proxy uri '%s', %s", s, msg);
+    return NULL;
+  }
+
+  if (g_strcmp0 (gst_uri_get_scheme (uri), "http") != 0) {
+    GST_ERROR_OBJECT (ice,
+        "Couldn't parse uri scheme for http proxy server '%s', %s", s, msg);
+    gst_uri_unref (uri);
+    return NULL;
+  }
+
+  host = gst_uri_get_host (uri);
+  if (!host) {
+    GST_ERROR_OBJECT (ice, "http proxy server '%s' has no host, %s", s, msg);
+    gst_uri_unref (uri);
+    return NULL;
+  }
+
+  userinfo = gst_uri_get_userinfo (uri);
+  _parse_userinfo (userinfo, &user, &pass);
+  if ((pass && pass[0] != '\0') && (!user || user[0] == '\0')) {
+    GST_ERROR_OBJECT (ice,
+        "Password specified without user for http proxy '%s', %s", s, msg);
+    uri = NULL;
+    goto out;
+  }
+
+  resolve_host_async (nice, host, (GAsyncReadyCallback) on_http_proxy_resolved,
+      gst_uri_ref (uri), (GDestroyNotify) gst_uri_unref);
+
+out:
+  g_free (user);
+  g_free (pass);
+
+  return uri;
+}
+
+static void
 gst_webrtc_nice_set_stun_server (GstWebRTCICE * ice, const gchar * uri_s)
 {
   GstUri *uri = gst_uri_from_string_escaped (uri_s);
@@ -1444,6 +1548,30 @@ gst_webrtc_nice_get_turn_server (GstWebRTCICE * ice)
 }
 
 static void
+gst_webrtc_nice_set_http_proxy (GstWebRTCICE * ice, const gchar * http_proxy)
+{
+  GstWebRTCNice *nice = GST_WEBRTC_NICE (ice);
+  GstUri *uri = _set_http_proxy (ice, http_proxy);
+
+  if (uri) {
+    if (nice->priv->http_proxy)
+      gst_uri_unref (nice->priv->http_proxy);
+    nice->priv->http_proxy = uri;
+  }
+}
+
+static gchar *
+gst_webrtc_nice_get_http_proxy (GstWebRTCICE * ice)
+{
+  GstWebRTCNice *nice = GST_WEBRTC_NICE (ice);
+
+  if (nice->priv->http_proxy)
+    return gst_uri_to_string (nice->priv->http_proxy);
+  else
+    return NULL;
+}
+
+static void
 gst_webrtc_nice_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
@@ -1526,6 +1654,8 @@ gst_webrtc_nice_finalize (GObject * object)
     gst_uri_unref (ice->priv->turn_server);
   if (ice->priv->stun_server)
     gst_uri_unref (ice->priv->stun_server);
+  if (ice->priv->http_proxy)
+    gst_uri_unref (ice->priv->http_proxy);
 
   g_mutex_clear (&ice->priv->lock);
   g_cond_clear (&ice->priv->cond);
@@ -1573,6 +1703,7 @@ gst_webrtc_nice_class_init (GstWebRTCNiceClass * klass)
   gst_webrtc_ice_class->get_is_controller = gst_webrtc_nice_get_is_controller;
   gst_webrtc_ice_class->get_stun_server = gst_webrtc_nice_get_stun_server;
   gst_webrtc_ice_class->get_turn_server = gst_webrtc_nice_get_turn_server;
+  gst_webrtc_ice_class->get_http_proxy = gst_webrtc_nice_get_http_proxy;
   gst_webrtc_ice_class->set_force_relay = gst_webrtc_nice_set_force_relay;
   gst_webrtc_ice_class->set_is_controller = gst_webrtc_nice_set_is_controller;
   gst_webrtc_ice_class->set_local_credentials =
@@ -1582,6 +1713,7 @@ gst_webrtc_nice_class_init (GstWebRTCNiceClass * klass)
   gst_webrtc_ice_class->set_stun_server = gst_webrtc_nice_set_stun_server;
   gst_webrtc_ice_class->set_tos = gst_webrtc_nice_set_tos;
   gst_webrtc_ice_class->set_turn_server = gst_webrtc_nice_set_turn_server;
+  gst_webrtc_ice_class->set_http_proxy = gst_webrtc_nice_set_http_proxy;
   gst_webrtc_ice_class->set_on_ice_candidate =
       gst_webrtc_nice_set_on_ice_candidate;
   gst_webrtc_ice_class->get_local_candidates =