[vlc-commits] network: split TLS and generic/TCP stream support
Rémi Denis-Courmont
git at videolan.org
Wed Mar 14 21:45:04 CET 2018
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed Mar 14 21:46:52 2018 +0200| [a51521757439e4dd40be8d82c41707d571dc7220] | committer: Rémi Denis-Courmont
network: split TLS and generic/TCP stream support
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=a51521757439e4dd40be8d82c41707d571dc7220
---
src/Makefile.am | 1 +
src/network/stream.c | 449 +++++++++++++++++++++++++++++++++++++++++++++++++++
src/network/tls.c | 411 +---------------------------------------------
3 files changed, 452 insertions(+), 409 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index d41f24a0c7..baacf5233f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -304,6 +304,7 @@ libvlccore_la_SOURCES = \
network/tcp.c \
network/udp.c \
network/rootbind.c \
+ network/stream.c \
network/tls.c \
text/charset.c \
text/memstream.c \
diff --git a/src/network/stream.c b/src/network/stream.c
new file mode 100644
index 0000000000..90744ac0f0
--- /dev/null
+++ b/src/network/stream.c
@@ -0,0 +1,449 @@
+/*****************************************************************************
+ * stream.c
+ *****************************************************************************
+ * Copyright © 2004-2016 Rémi Denis-Courmont
+ * $Id$
+ *
+ * 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.
+ *****************************************************************************/
+
+/**
+ * @ingroup transport
+ * @file
+ * Transport-layer stream abstraction
+ *
+ * This file implements the transport-layer stream (vlc_tls) abstraction.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_POLL
+# include <poll.h>
+#endif
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef HAVE_SYS_UIO_H
+# include <sys/uio.h>
+#endif
+#ifdef HAVE_NETINET_TCP_H
+# include <netinet/tcp.h>
+#endif
+#ifndef SOL_TCP
+# define SOL_TCP IPPROTO_TCP
+#endif
+
+#include <vlc_common.h>
+#include <vlc_tls.h>
+#include <vlc_interrupt.h>
+
+ssize_t vlc_tls_Read(vlc_tls_t *session, void *buf, size_t len, bool waitall)
+{
+ struct pollfd ufd;
+ struct iovec iov;
+
+ ufd.fd = vlc_tls_GetFD(session);
+ ufd.events = POLLIN;
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ for (size_t rcvd = 0;;)
+ {
+ if (vlc_killed())
+ {
+ errno = EINTR;
+ return -1;
+ }
+
+ ssize_t val = session->readv(session, &iov, 1);
+ if (val > 0)
+ {
+ if (!waitall)
+ return val;
+ iov.iov_base = (char *)iov.iov_base + val;
+ iov.iov_len -= val;
+ rcvd += val;
+ }
+ if (iov.iov_len == 0 || val == 0)
+ return rcvd;
+ if (val == -1)
+ {
+ if (vlc_killed())
+ return -1;
+ if (errno != EINTR && errno != EAGAIN)
+ return rcvd ? (ssize_t)rcvd : -1;
+ }
+
+ vlc_poll_i11e(&ufd, 1, -1);
+ }
+}
+
+ssize_t vlc_tls_Write(vlc_tls_t *session, const void *buf, size_t len)
+{
+ struct pollfd ufd;
+ struct iovec iov;
+
+ ufd.fd = vlc_tls_GetFD(session);
+ ufd.events = POLLOUT;
+ iov.iov_base = (void *)buf;
+ iov.iov_len = len;
+
+ for (size_t sent = 0;;)
+ {
+ if (vlc_killed())
+ {
+ errno = EINTR;
+ return -1;
+ }
+
+ ssize_t val = session->writev(session, &iov, 1);
+ if (val > 0)
+ {
+ iov.iov_base = ((char *)iov.iov_base) + val;
+ iov.iov_len -= val;
+ sent += val;
+ }
+ if (iov.iov_len == 0 || val == 0)
+ return sent;
+ if (val == -1)
+ {
+ if (vlc_killed())
+ return -1;
+ if (errno != EINTR && errno != EAGAIN)
+ return sent ? (ssize_t)sent : -1;
+ }
+
+ vlc_poll_i11e(&ufd, 1, -1);
+ }
+}
+
+char *vlc_tls_GetLine(vlc_tls_t *session)
+{
+ char *line = NULL;
+ size_t linelen = 0, linesize = 0;
+
+ do
+ {
+ if (linelen == linesize)
+ {
+ linesize += 1024;
+
+ char *newline = realloc(line, linesize);
+ if (unlikely(newline == NULL))
+ goto error;
+ line = newline;
+ }
+
+ if (vlc_tls_Read(session, line + linelen, 1, false) <= 0)
+ goto error;
+ }
+ while (line[linelen++] != '\n');
+
+ if (linelen >= 2 && line[linelen - 2] == '\r')
+ line[linelen - 2] = '\0';
+ return line;
+
+error:
+ free(line);
+ return NULL;
+}
+
+typedef struct vlc_tls_socket
+{
+ struct vlc_tls tls;
+ int fd;
+ socklen_t peerlen;
+ struct sockaddr peer[];
+} vlc_tls_socket_t;
+
+static int vlc_tls_SocketGetFD(vlc_tls_t *tls)
+{
+ vlc_tls_socket_t *sock = (struct vlc_tls_socket *)tls;
+
+ return sock->fd;
+}
+
+static ssize_t vlc_tls_SocketRead(vlc_tls_t *tls, struct iovec *iov,
+ unsigned count)
+{
+ struct msghdr msg =
+ {
+ .msg_iov = iov,
+ .msg_iovlen = count,
+ };
+
+ return recvmsg(vlc_tls_SocketGetFD(tls), &msg, 0);
+}
+
+static ssize_t vlc_tls_SocketWrite(vlc_tls_t *tls, const struct iovec *iov,
+ unsigned count)
+{
+ const struct msghdr msg =
+ {
+ .msg_iov = (struct iovec *)iov,
+ .msg_iovlen = count,
+ };
+
+ return sendmsg(vlc_tls_SocketGetFD(tls), &msg, MSG_NOSIGNAL);
+}
+
+static int vlc_tls_SocketShutdown(vlc_tls_t *tls, bool duplex)
+{
+ return shutdown(vlc_tls_SocketGetFD(tls), duplex ? SHUT_RDWR : SHUT_WR);
+}
+
+static void vlc_tls_SocketClose(vlc_tls_t *tls)
+{
+ net_Close(vlc_tls_SocketGetFD(tls));
+ free(tls);
+}
+
+static vlc_tls_t *vlc_tls_SocketAlloc(int fd,
+ const struct sockaddr *restrict peer,
+ socklen_t peerlen)
+{
+ vlc_tls_socket_t *sock = malloc(sizeof (*sock) + peerlen);
+ if (unlikely(sock == NULL))
+ return NULL;
+
+ vlc_tls_t *tls = &sock->tls;
+
+ tls->get_fd = vlc_tls_SocketGetFD;
+ tls->readv = vlc_tls_SocketRead;
+ tls->writev = vlc_tls_SocketWrite;
+ tls->shutdown = vlc_tls_SocketShutdown;
+ tls->close = vlc_tls_SocketClose;
+ tls->p = NULL;
+
+ sock->fd = fd;
+ sock->peerlen = peerlen;
+ if (peerlen > 0)
+ memcpy(sock->peer, peer, peerlen);
+ return tls;
+}
+
+vlc_tls_t *vlc_tls_SocketOpen(int fd)
+{
+ return vlc_tls_SocketAlloc(fd, NULL, 0);
+}
+
+int vlc_tls_SocketPair(int family, int protocol, vlc_tls_t *pair[2])
+{
+ int fds[2];
+
+ if (vlc_socketpair(family, SOCK_STREAM, protocol, fds, true))
+ return -1;
+
+ for (size_t i = 0; i < 2; i++)
+ {
+ setsockopt(fds[i], SOL_SOCKET, SO_REUSEADDR,
+ &(int){ 1 }, sizeof (int));
+
+ pair[i] = vlc_tls_SocketAlloc(fds[i], NULL, 0);
+ if (unlikely(pair[i] == NULL))
+ {
+ net_Close(fds[i]);
+ if (i)
+ vlc_tls_SessionDelete(pair[0]);
+ else
+ net_Close(fds[1]);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Allocates an unconnected transport layer socket.
+ */
+static vlc_tls_t *vlc_tls_SocketAddrInfo(const struct addrinfo *restrict info)
+{
+ int fd = vlc_socket(info->ai_family, info->ai_socktype, info->ai_protocol,
+ true /* nonblocking */);
+ if (fd == -1)
+ return NULL;
+
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
+
+ if (info->ai_socktype == SOCK_STREAM && info->ai_protocol == IPPROTO_TCP)
+ setsockopt(fd, SOL_TCP, TCP_NODELAY, &(int){ 1 }, sizeof (int));
+
+ vlc_tls_t *sk = vlc_tls_SocketAlloc(fd, info->ai_addr, info->ai_addrlen);
+ if (unlikely(sk == NULL))
+ net_Close(fd);
+ return sk;
+}
+
+/**
+ * Waits for pending transport layer socket connection.
+ */
+static int vlc_tls_WaitConnect(vlc_tls_t *tls)
+{
+ const int fd = vlc_tls_GetFD(tls);
+ struct pollfd ufd;
+
+ ufd.fd = fd;
+ ufd.events = POLLOUT;
+
+ do
+ {
+ if (vlc_killed())
+ {
+ errno = EINTR;
+ return -1;
+ }
+ }
+ while (vlc_poll_i11e(&ufd, 1, -1) <= 0);
+
+ int val;
+ socklen_t len = sizeof (val);
+
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len))
+ return -1;
+
+ if (val != 0)
+ {
+ errno = val;
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Connects a transport layer socket.
+ */
+static ssize_t vlc_tls_Connect(vlc_tls_t *tls)
+{
+ const vlc_tls_socket_t *sock = (vlc_tls_socket_t *)tls;
+
+ if (connect(sock->fd, sock->peer, sock->peerlen) == 0)
+ return 0;
+#ifndef _WIN32
+ if (errno != EINPROGRESS)
+ return -1;
+#else
+ if (WSAGetLastError() != WSAEWOULDBLOCK)
+ return -1;
+#endif
+ return vlc_tls_WaitConnect(tls);
+}
+
+/* Callback for combined connection establishment and initial send */
+static ssize_t vlc_tls_ConnectWrite(vlc_tls_t *tls,
+ const struct iovec *iov,unsigned count)
+{
+#ifdef MSG_FASTOPEN
+ vlc_tls_socket_t *sock = (vlc_tls_socket_t *)tls;
+ const struct msghdr msg =
+ {
+ .msg_name = sock->peer,
+ .msg_namelen = sock->peerlen,
+ .msg_iov = (struct iovec *)iov,
+ .msg_iovlen = count,
+ };
+ ssize_t ret;
+
+ /* Next time, write directly. Do not retry to connect. */
+ tls->writev = vlc_tls_SocketWrite;
+
+ ret = sendmsg(vlc_tls_SocketGetFD(tls), &msg, MSG_NOSIGNAL|MSG_FASTOPEN);
+ if (ret >= 0)
+ { /* Fast open in progress */
+ return ret;
+ }
+
+ if (errno == EINPROGRESS)
+ {
+ if (vlc_tls_WaitConnect(tls))
+ return -1;
+ }
+ else
+ if (errno != EOPNOTSUPP)
+ return -1;
+ /* Fast open not supported or disabled... fallback to normal mode */
+#else
+ tls->writev = vlc_tls_SocketWrite;
+#endif
+
+ if (vlc_tls_Connect(tls))
+ return -1;
+
+ return vlc_tls_SocketWrite(tls, iov, count);
+}
+
+vlc_tls_t *vlc_tls_SocketOpenAddrInfo(const struct addrinfo *restrict info,
+ bool defer_connect)
+{
+ vlc_tls_t *sock = vlc_tls_SocketAddrInfo(info);
+ if (sock == NULL)
+ return NULL;
+
+ if (defer_connect)
+ { /* The socket is not connected yet.
+ * The connection will be triggered on the first send. */
+ sock->writev = vlc_tls_ConnectWrite;
+ }
+ else
+ {
+ if (vlc_tls_Connect(sock))
+ {
+ vlc_tls_SessionDelete(sock);
+ sock = NULL;
+ }
+ }
+ return sock;
+}
+
+vlc_tls_t *vlc_tls_SocketOpenTCP(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_i11e(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 NULL;
+ }
+
+ msg_Dbg(obj, "connecting to %s port %u ...", name, port);
+
+ /* TODO: implement RFC8305 */
+ for (const struct addrinfo *p = res; p != NULL; p = p->ai_next)
+ {
+ vlc_tls_t *tls = vlc_tls_SocketOpenAddrInfo(p, false);
+ if (tls == NULL)
+ {
+ msg_Err(obj, "connection error: %s", vlc_strerror_c(errno));
+ continue;
+ }
+
+ freeaddrinfo(res);
+ return tls;
+ }
+
+ freeaddrinfo(res);
+ return NULL;
+}
diff --git a/src/network/tls.c b/src/network/tls.c
index aec25bed6b..de1d7f64b2 100644
--- a/src/network/tls.c
+++ b/src/network/tls.c
@@ -20,10 +20,9 @@
*****************************************************************************/
/**
+ * @ingroup tls
* @file
- * Transport Layer Socket abstraction.
- *
- * This file implements the Transport Layer Socket (vlc_tls) abstraction.
+ * Transport Layer Session protocol API.
*/
#ifdef HAVE_CONFIG_H
@@ -35,15 +34,6 @@
#endif
#include <assert.h>
#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#ifdef HAVE_SYS_UIO_H
-# include <sys/uio.h>
-#endif
-#ifdef HAVE_NETINET_TCP_H
-# include <netinet/tcp.h>
-#endif
#ifndef SOL_TCP
# define SOL_TCP IPPROTO_TCP
#endif
@@ -225,403 +215,6 @@ vlc_tls_t *vlc_tls_ServerSessionCreate(vlc_tls_creds_t *crd,
return vlc_tls_SessionCreate(crd, sock, NULL, alpn);
}
-ssize_t vlc_tls_Read(vlc_tls_t *session, void *buf, size_t len, bool waitall)
-{
- struct pollfd ufd;
- struct iovec iov;
-
- ufd.fd = vlc_tls_GetFD(session);
- ufd.events = POLLIN;
- iov.iov_base = buf;
- iov.iov_len = len;
-
- for (size_t rcvd = 0;;)
- {
- if (vlc_killed())
- {
- errno = EINTR;
- return -1;
- }
-
- ssize_t val = session->readv(session, &iov, 1);
- if (val > 0)
- {
- if (!waitall)
- return val;
- iov.iov_base = (char *)iov.iov_base + val;
- iov.iov_len -= val;
- rcvd += val;
- }
- if (iov.iov_len == 0 || val == 0)
- return rcvd;
- if (val == -1)
- {
- if (vlc_killed())
- return -1;
- if (errno != EINTR && errno != EAGAIN)
- return rcvd ? (ssize_t)rcvd : -1;
- }
-
- vlc_poll_i11e(&ufd, 1, -1);
- }
-}
-
-ssize_t vlc_tls_Write(vlc_tls_t *session, const void *buf, size_t len)
-{
- struct pollfd ufd;
- struct iovec iov;
-
- ufd.fd = vlc_tls_GetFD(session);
- ufd.events = POLLOUT;
- iov.iov_base = (void *)buf;
- iov.iov_len = len;
-
- for (size_t sent = 0;;)
- {
- if (vlc_killed())
- {
- errno = EINTR;
- return -1;
- }
-
- ssize_t val = session->writev(session, &iov, 1);
- if (val > 0)
- {
- iov.iov_base = ((char *)iov.iov_base) + val;
- iov.iov_len -= val;
- sent += val;
- }
- if (iov.iov_len == 0 || val == 0)
- return sent;
- if (val == -1)
- {
- if (vlc_killed())
- return -1;
- if (errno != EINTR && errno != EAGAIN)
- return sent ? (ssize_t)sent : -1;
- }
-
- vlc_poll_i11e(&ufd, 1, -1);
- }
-}
-
-char *vlc_tls_GetLine(vlc_tls_t *session)
-{
- char *line = NULL;
- size_t linelen = 0, linesize = 0;
-
- do
- {
- if (linelen == linesize)
- {
- linesize += 1024;
-
- char *newline = realloc(line, linesize);
- if (unlikely(newline == NULL))
- goto error;
- line = newline;
- }
-
- if (vlc_tls_Read(session, line + linelen, 1, false) <= 0)
- goto error;
- }
- while (line[linelen++] != '\n');
-
- if (linelen >= 2 && line[linelen - 2] == '\r')
- line[linelen - 2] = '\0';
- return line;
-
-error:
- free(line);
- return NULL;
-}
-
-typedef struct vlc_tls_socket
-{
- struct vlc_tls tls;
- int fd;
- socklen_t peerlen;
- struct sockaddr peer[];
-} vlc_tls_socket_t;
-
-static int vlc_tls_SocketGetFD(vlc_tls_t *tls)
-{
- vlc_tls_socket_t *sock = (struct vlc_tls_socket *)tls;
-
- return sock->fd;
-}
-
-static ssize_t vlc_tls_SocketRead(vlc_tls_t *tls, struct iovec *iov,
- unsigned count)
-{
- struct msghdr msg =
- {
- .msg_iov = iov,
- .msg_iovlen = count,
- };
-
- return recvmsg(vlc_tls_SocketGetFD(tls), &msg, 0);
-}
-
-static ssize_t vlc_tls_SocketWrite(vlc_tls_t *tls, const struct iovec *iov,
- unsigned count)
-{
- const struct msghdr msg =
- {
- .msg_iov = (struct iovec *)iov,
- .msg_iovlen = count,
- };
-
- return sendmsg(vlc_tls_SocketGetFD(tls), &msg, MSG_NOSIGNAL);
-}
-
-static int vlc_tls_SocketShutdown(vlc_tls_t *tls, bool duplex)
-{
- return shutdown(vlc_tls_SocketGetFD(tls), duplex ? SHUT_RDWR : SHUT_WR);
-}
-
-static void vlc_tls_SocketClose(vlc_tls_t *tls)
-{
- net_Close(vlc_tls_SocketGetFD(tls));
- free(tls);
-}
-
-static vlc_tls_t *vlc_tls_SocketAlloc(int fd,
- const struct sockaddr *restrict peer,
- socklen_t peerlen)
-{
- vlc_tls_socket_t *sock = malloc(sizeof (*sock) + peerlen);
- if (unlikely(sock == NULL))
- return NULL;
-
- vlc_tls_t *tls = &sock->tls;
-
- tls->get_fd = vlc_tls_SocketGetFD;
- tls->readv = vlc_tls_SocketRead;
- tls->writev = vlc_tls_SocketWrite;
- tls->shutdown = vlc_tls_SocketShutdown;
- tls->close = vlc_tls_SocketClose;
- tls->p = NULL;
-
- sock->fd = fd;
- sock->peerlen = peerlen;
- if (peerlen > 0)
- memcpy(sock->peer, peer, peerlen);
- return tls;
-}
-
-vlc_tls_t *vlc_tls_SocketOpen(int fd)
-{
- return vlc_tls_SocketAlloc(fd, NULL, 0);
-}
-
-int vlc_tls_SocketPair(int family, int protocol, vlc_tls_t *pair[2])
-{
- int fds[2];
-
- if (vlc_socketpair(family, SOCK_STREAM, protocol, fds, true))
- return -1;
-
- for (size_t i = 0; i < 2; i++)
- {
- setsockopt(fds[i], SOL_SOCKET, SO_REUSEADDR,
- &(int){ 1 }, sizeof (int));
-
- pair[i] = vlc_tls_SocketAlloc(fds[i], NULL, 0);
- if (unlikely(pair[i] == NULL))
- {
- net_Close(fds[i]);
- if (i)
- vlc_tls_SessionDelete(pair[0]);
- else
- net_Close(fds[1]);
- return -1;
- }
- }
- return 0;
-}
-
-/**
- * Allocates an unconnected transport layer socket.
- */
-static vlc_tls_t *vlc_tls_SocketAddrInfo(const struct addrinfo *restrict info)
-{
- int fd = vlc_socket(info->ai_family, info->ai_socktype, info->ai_protocol,
- true /* nonblocking */);
- if (fd == -1)
- return NULL;
-
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
-
- if (info->ai_socktype == SOCK_STREAM && info->ai_protocol == IPPROTO_TCP)
- setsockopt(fd, SOL_TCP, TCP_NODELAY, &(int){ 1 }, sizeof (int));
-
- vlc_tls_t *sk = vlc_tls_SocketAlloc(fd, info->ai_addr, info->ai_addrlen);
- if (unlikely(sk == NULL))
- net_Close(fd);
- return sk;
-}
-
-/**
- * Waits for pending transport layer socket connection.
- */
-static int vlc_tls_WaitConnect(vlc_tls_t *tls)
-{
- const int fd = vlc_tls_GetFD(tls);
- struct pollfd ufd;
-
- ufd.fd = fd;
- ufd.events = POLLOUT;
-
- do
- {
- if (vlc_killed())
- {
- errno = EINTR;
- return -1;
- }
- }
- while (vlc_poll_i11e(&ufd, 1, -1) <= 0);
-
- int val;
- socklen_t len = sizeof (val);
-
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len))
- return -1;
-
- if (val != 0)
- {
- errno = val;
- return -1;
- }
- return 0;
-}
-
-/**
- * Connects a transport layer socket.
- */
-static ssize_t vlc_tls_Connect(vlc_tls_t *tls)
-{
- const vlc_tls_socket_t *sock = (vlc_tls_socket_t *)tls;
-
- if (connect(sock->fd, sock->peer, sock->peerlen) == 0)
- return 0;
-#ifndef _WIN32
- if (errno != EINPROGRESS)
- return -1;
-#else
- if (WSAGetLastError() != WSAEWOULDBLOCK)
- return -1;
-#endif
- return vlc_tls_WaitConnect(tls);
-}
-
-/* Callback for combined connection establishment and initial send */
-static ssize_t vlc_tls_ConnectWrite(vlc_tls_t *tls,
- const struct iovec *iov,unsigned count)
-{
-#ifdef MSG_FASTOPEN
- vlc_tls_socket_t *sock = (vlc_tls_socket_t *)tls;
- const struct msghdr msg =
- {
- .msg_name = sock->peer,
- .msg_namelen = sock->peerlen,
- .msg_iov = (struct iovec *)iov,
- .msg_iovlen = count,
- };
- ssize_t ret;
-
- /* Next time, write directly. Do not retry to connect. */
- tls->writev = vlc_tls_SocketWrite;
-
- ret = sendmsg(vlc_tls_SocketGetFD(tls), &msg, MSG_NOSIGNAL|MSG_FASTOPEN);
- if (ret >= 0)
- { /* Fast open in progress */
- return ret;
- }
-
- if (errno == EINPROGRESS)
- {
- if (vlc_tls_WaitConnect(tls))
- return -1;
- }
- else
- if (errno != EOPNOTSUPP)
- return -1;
- /* Fast open not supported or disabled... fallback to normal mode */
-#else
- tls->writev = vlc_tls_SocketWrite;
-#endif
-
- if (vlc_tls_Connect(tls))
- return -1;
-
- return vlc_tls_SocketWrite(tls, iov, count);
-}
-
-vlc_tls_t *vlc_tls_SocketOpenAddrInfo(const struct addrinfo *restrict info,
- bool defer_connect)
-{
- vlc_tls_t *sock = vlc_tls_SocketAddrInfo(info);
- if (sock == NULL)
- return NULL;
-
- if (defer_connect)
- { /* The socket is not connected yet.
- * The connection will be triggered on the first send. */
- sock->writev = vlc_tls_ConnectWrite;
- }
- else
- {
- if (vlc_tls_Connect(sock))
- {
- vlc_tls_SessionDelete(sock);
- sock = NULL;
- }
- }
- return sock;
-}
-
-vlc_tls_t *vlc_tls_SocketOpenTCP(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_i11e(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 NULL;
- }
-
- msg_Dbg(obj, "connecting to %s port %u ...", name, port);
-
- /* TODO: implement RFC8305 */
- for (const struct addrinfo *p = res; p != NULL; p = p->ai_next)
- {
- vlc_tls_t *tls = vlc_tls_SocketOpenAddrInfo(p, false);
- if (tls == NULL)
- {
- msg_Err(obj, "connection error: %s", vlc_strerror_c(errno));
- continue;
- }
-
- freeaddrinfo(res);
- return tls;
- }
-
- freeaddrinfo(res);
- return NULL;
-}
-
vlc_tls_t *vlc_tls_SocketOpenTLS(vlc_tls_creds_t *creds, const char *name,
unsigned port, const char *service,
const char *const *alpn, char **alp)
More information about the vlc-commits
mailing list