[vlc-commits] HTTP low-level transport I/O helpers

Rémi Denis-Courmont git at videolan.org
Sun Dec 13 17:20:28 CET 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Nov  8 21:56:36 2015 +0200| [aa4b63ee9ca672b5d945ea8a5a9b2b734f436f2e] | committer: Rémi Denis-Courmont

HTTP low-level transport I/O helpers

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=aa4b63ee9ca672b5d945ea8a5a9b2b734f436f2e
---

 modules/access/http/transport.c |  273 +++++++++++++++++++++++++++++++++++++++
 modules/access/http/transport.h |   41 ++++++
 2 files changed, 314 insertions(+)

diff --git a/modules/access/http/transport.c b/modules/access/http/transport.c
new file mode 100644
index 0000000..2a93a2f
--- /dev/null
+++ b/modules/access/http/transport.c
@@ -0,0 +1,273 @@
+/*****************************************************************************
+ * transport.c: HTTP/TLS TCP transport layer
+ *****************************************************************************
+ * Copyright © 2015 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#ifdef HAVE_POLL
+#include <poll.h>
+#endif
+#include <fcntl.h>
+#include <vlc_common.h>
+#include <vlc_network.h>
+#include <vlc_tls.h>
+
+#include "transport.h"
+
+/**
+ * Receives TLS data.
+ *
+ * Receives bytes from the peer through a TLS session.
+ * @note This may be a cancellation point.
+ * The caller is responsible for serializing reads on a given connection.
+ */
+ssize_t vlc_https_recv(vlc_tls_t *tls, void *buf, size_t len)
+{
+    struct pollfd ufd;
+    size_t count = 0;
+
+    ufd.fd = tls->fd;
+    ufd.events = POLLIN;
+
+    while (count < len)
+    {
+        int canc = vlc_savecancel();
+        ssize_t val = tls->sock.pf_recv(tls, (char *)buf + count, len - count);
+
+        vlc_restorecancel(canc);
+
+        if (val == 0)
+            break;
+
+        if (val >= 0)
+        {
+            count += val;
+            continue;
+        }
+
+        if (errno != EINTR && errno != EAGAIN)
+            return -1;
+
+        poll(&ufd, 1, -1);
+    }
+
+    return count;
+}
+
+ssize_t vlc_http_recv(int fd, void *buf, size_t len)
+{
+    unsigned count = 0;
+
+    while (count < len)
+    {
+        ssize_t val = recv(fd, (char *)buf + count, len - count, MSG_WAITALL);
+        if (val == 0)
+            break;
+
+        if (val >= 0)
+        {
+            count += val;
+            continue;
+        }
+
+        if (errno != EINTR)
+            return -1;
+    }
+
+    return count;
+}
+
+/**
+ * Sends bytes to a connection.
+ * @note This may be a cancellation point.
+ * The caller is responsible for serializing writes on a given connection.
+ */
+ssize_t vlc_https_send(vlc_tls_t *tls, const void *buf, size_t len)
+{
+    struct pollfd ufd;
+    size_t count = 0;
+
+    ufd.fd = tls->fd;
+    ufd.events = POLLOUT;
+
+    while (count < len)
+    {
+        int canc = vlc_savecancel();
+        ssize_t val = tls->sock.pf_send(tls, (char *)buf + count, len - count);
+
+        vlc_restorecancel(canc);
+
+        if (val > 0)
+        {
+            count += val;
+            continue;
+        }
+
+        if (val == 0)
+            break;
+
+        if (errno != EINTR && errno != EAGAIN)
+            return -1;
+
+        poll(&ufd, 1, -1);
+    }
+
+    return count;
+}
+
+ssize_t vlc_http_send(int fd, const void *buf, size_t len)
+{
+    size_t count = 0;
+
+    while (count < len)
+    {
+        ssize_t val = send(fd, buf, len, MSG_NOSIGNAL);
+        if (val > 0)
+        {
+            count += val;
+            continue;
+        }
+
+        if (val == 0)
+            break;
+
+        if (errno != EINTR)
+            return -1;
+    }
+
+    return count;
+}
+
+static void cleanup_addrinfo(void *data)
+{
+    freeaddrinfo(data);
+}
+
+static void cleanup_fd(void *data)
+{
+    net_Close((intptr_t)data);
+}
+
+static int vlc_tcp_connect(vlc_object_t *obj, const char *name, unsigned port)
+{
+    struct addrinfo hints =
+    {
+        .ai_socktype = SOCK_STREAM,
+        .ai_protocol = IPPROTO_TCP,
+    }, *res;
+
+    assert(name != NULL);
+    msg_Dbg(obj, "resolving %s ...", name);
+
+    int val = vlc_getaddrinfo(name, port, &hints, &res);
+    if (val != 0)
+    {   /* TODO: C locale for gai_strerror() */
+        msg_Err(obj, "cannot resolve %s port %u: %s", name, port,
+                gai_strerror(val));
+        return -1;
+    }
+
+    int fd = -1;
+
+    vlc_cleanup_push(cleanup_addrinfo, res);
+    msg_Dbg(obj, "connecting to %s port %u ...", name, port);
+
+    for (const struct addrinfo *p = res; p != NULL; p = p->ai_next)
+    {
+        fd = vlc_socket(p->ai_family, p->ai_socktype, p->ai_protocol, false);
+        if (fd == -1)
+        {
+            msg_Warn(obj, "cannot create socket: %s", vlc_strerror_c(errno));
+            continue;
+        }
+
+        vlc_cleanup_push(cleanup_fd, (void *)(intptr_t)fd);
+        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
+
+        val = connect(fd, p->ai_addr, p->ai_addrlen);
+        vlc_cleanup_pop();
+
+        if (val == 0)
+            break; /* success! */
+
+        msg_Err(obj, "cannot connect to %s port %u: %s", name, port,
+                vlc_strerror_c(errno));
+        net_Close(fd);
+        fd = -1;
+    }
+
+    vlc_cleanup_pop();
+    freeaddrinfo(res);
+    return fd;
+}
+
+vlc_tls_t *vlc_https_connect(vlc_tls_creds_t *creds, const char *name,
+                             unsigned port, bool *restrict two)
+{
+    if (port == 0)
+        port = 443;
+
+    int fd = vlc_tcp_connect(VLC_OBJECT(creds), name, port);
+    if (fd == -1)
+        return NULL;
+
+#ifndef _WIN32
+    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+#else
+    ioctlsocket(fd, FIONBIO, &(unsigned long){ 1 });
+#endif
+
+    /* TLS with ALPN */
+    const char *alpn[] = { "h2", "http/1.1", NULL };
+    char *alp;
+
+    vlc_tls_t *tls = vlc_tls_ClientSessionCreate(creds, fd, name, "https",
+                                                 alpn, &alp);
+    if (tls == NULL)
+    {
+        net_Close(fd);
+        return NULL;
+    }
+
+    *two = (alp != NULL) && !strcmp(alp, "h2");
+    free(alp);
+    return tls;
+}
+
+void vlc_http_disconnect(int fd)
+{
+    shutdown(fd, SHUT_RDWR);
+    net_Close(fd);
+}
+
+void vlc_https_disconnect(vlc_tls_t *tls)
+{
+    int canc = vlc_savecancel();
+    int fd = tls->fd;
+
+    vlc_tls_SessionDelete(tls);
+    vlc_http_disconnect(fd);
+    vlc_restorecancel(canc);
+}
diff --git a/modules/access/http/transport.h b/modules/access/http/transport.h
new file mode 100644
index 0000000..9873aae
--- /dev/null
+++ b/modules/access/http/transport.h
@@ -0,0 +1,41 @@
+/*****************************************************************************
+ * transport.h: HTTP/TLS TCP transport layer declarations
+ *****************************************************************************
+ * Copyright © 2015 Rémi Denis-Courmont
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifndef VLC_HTTP_TRANSPORT_H
+#define VLC_HTTP_TRANSPORT_H 1
+
+#include <stddef.h>
+#include <stdbool.h>
+
+struct vlc_tls;
+struct vlc_tls_creds;
+
+ssize_t vlc_http_recv(int fd, void *buf, size_t len);
+ssize_t vlc_https_recv(struct vlc_tls *tls, void *buf, size_t len);
+ssize_t vlc_http_send(int fd, const void *buf, size_t len);
+ssize_t vlc_https_send(struct vlc_tls *tls, const void *buf, size_t len);
+
+struct vlc_tls *vlc_https_connect(struct vlc_tls_creds *creds,
+                                  const char *name, unsigned port,
+                                  bool *restrict two);
+void vlc_http_disconnect(int fd);
+void vlc_https_disconnect(struct vlc_tls *tls);
+
+#endif



More information about the vlc-commits mailing list