[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