[vlc-commits] tls: revector
Rémi Denis-Courmont
git at videolan.org
Sat Feb 25 22:41:58 CET 2017
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sat Feb 25 22:09:05 2017 +0200| [e2583c430e391b9397f89f35765ea3f4c6e402f8] | committer: Rémi Denis-Courmont
tls: revector
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=e2583c430e391b9397f89f35765ea3f4c6e402f8
---
src/network/tls.c | 189 +++++++++++++++++++++++++++++++++++++++---------------
1 file changed, 137 insertions(+), 52 deletions(-)
diff --git a/src/network/tls.c b/src/network/tls.c
index a4f35c9..2d04eb4 100644
--- a/src/network/tls.c
+++ b/src/network/tls.c
@@ -35,6 +35,7 @@
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#ifdef HAVE_SYS_UIO_H
# include <sys/uio.h>
#endif
@@ -328,6 +329,8 @@ 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)
@@ -372,9 +375,11 @@ static void vlc_tls_SocketClose(vlc_tls_t *tls)
free(tls);
}
-vlc_tls_t *vlc_tls_SocketOpen(int fd)
+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));
+ vlc_tls_socket_t *sock = malloc(sizeof (*sock) + peerlen);
if (unlikely(sock == NULL))
return NULL;
@@ -386,72 +391,115 @@ vlc_tls_t *vlc_tls_SocketOpen(int fd)
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;
}
-static vlc_tls_t *vlc_tls_SocketOpenAddrInfoSingle(vlc_object_t *obj,
- const struct addrinfo *restrict info)
+vlc_tls_t *vlc_tls_SocketOpen(int fd)
+{
+ return vlc_tls_SocketAlloc(fd, NULL, 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)
- {
- msg_Warn(obj, "socket error: %s", vlc_strerror_c(errno));
return NULL;
- }
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, sizeof (int));
- int val = connect(fd, info->ai_addr, info->ai_addrlen);
- if (val != 0)
- {
- if (errno != EINPROGRESS)
- {
- msg_Err(obj, "connection error: %s", vlc_strerror_c(errno));
- goto giveup;
- }
+ vlc_tls_t *sk = vlc_tls_SocketAlloc(fd, info->ai_addr, info->ai_addrlen);
+ if (unlikely(sk == NULL))
+ net_Close(fd);
+ return sk;
+}
- struct pollfd ufd;
+/**
+ * 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;
+ ufd.fd = fd;
+ ufd.events = POLLOUT;
- do
+ do
+ {
+ if (vlc_killed())
{
- if (vlc_killed())
- {
- errno = EINTR;
- goto giveup;
- }
+ errno = EINTR;
+ return -1;
}
- while (vlc_poll_i11e(&ufd, 1, -1) <= 0);
+ }
+ while (vlc_poll_i11e(&ufd, 1, -1) <= 0);
- socklen_t len = sizeof (val);
- if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len))
- {
- msg_Err(obj, "socket option error: %s",
- vlc_strerror_c(errno));
- goto giveup;
- }
+ int val;
+ socklen_t len = sizeof (val);
- if (val != 0)
- {
- msg_Err(obj, "connection error: %s", vlc_strerror_c(val));
- errno = val;
- goto giveup;
- }
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &val, &len))
+ return -1;
+
+ if (val != 0)
+ {
+ errno = val;
+ return -1;
}
+ return 0;
+}
- vlc_tls_t *tls = vlc_tls_SocketOpen(fd);
- if (unlikely(tls == NULL))
- goto giveup;
+/**
+ * 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);
+}
- return 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)
+{
+ if (vlc_tls_Connect(tls))
+ return -1;
-giveup:
- net_Close(fd);
- return NULL;
+ /* Next time, write directly. Do not retry to connect. */
+ tls->writev = vlc_tls_SocketWrite;
+ return vlc_tls_SocketWrite(tls, iov, count);
+}
+
+static vlc_tls_t *vlc_tls_ConnectAddrInfo(const struct addrinfo *info)
+{
+ vlc_tls_t *tls = vlc_tls_SocketAddrInfo(info);
+ if (tls == NULL)
+ return NULL;
+
+ if (vlc_tls_Connect(tls))
+ {
+ vlc_tls_SessionDelete(tls);
+ tls = NULL;
+ }
+ return tls;
}
vlc_tls_t *vlc_tls_SocketOpenAddrInfo(vlc_object_t *obj,
@@ -460,9 +508,11 @@ vlc_tls_t *vlc_tls_SocketOpenAddrInfo(vlc_object_t *obj,
/* TODO: implement RFC6555 */
for (const struct addrinfo *p = info; p != NULL; p = p->ai_next)
{
- vlc_tls_t *tls = vlc_tls_SocketOpenAddrInfoSingle(obj, p);
+ vlc_tls_t *tls = vlc_tls_ConnectAddrInfo(p);
if (tls != NULL)
return tls;
+
+ msg_Err(obj, "connection error: %s", vlc_strerror_c(errno));
}
return NULL;
}
@@ -498,13 +548,48 @@ 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)
{
- vlc_tls_t *tcp = vlc_tls_SocketOpenTCP(VLC_OBJECT(creds), name, port);
- if (tcp == NULL)
+ struct addrinfo hints =
+ {
+ .ai_socktype = SOCK_STREAM,
+ .ai_protocol = IPPROTO_TCP,
+ }, *res;
+
+ msg_Dbg(creds, "resolving %s ...", name);
+
+ int val = vlc_getaddrinfo_i11e(name, port, &hints, &res);
+ if (val != 0)
+ { /* TODO: C locale for gai_strerror() */
+ msg_Err(creds, "cannot resolve %s port %u: %s", name, port,
+ gai_strerror(val));
return NULL;
+ }
- vlc_tls_t *tls = vlc_tls_ClientSessionCreate(creds, tcp, name, service,
- alpn, alp);
- if (tls == NULL)
+ for (const struct addrinfo *p = res; p != NULL; p = p->ai_next)
+ {
+ vlc_tls_t *tcp = vlc_tls_SocketAddrInfo(p);
+ if (tcp == NULL)
+ {
+ msg_Err(creds, "socket error: %s", vlc_strerror_c(errno));
+ continue;
+ }
+
+ /* The socket is not connected yet.
+ * The connection will be triggered on the first send. */
+ tcp->writev = vlc_tls_ConnectWrite;
+
+ vlc_tls_t *tls = vlc_tls_ClientSessionCreate(creds, tcp, name, service,
+ alpn, alp);
+ if (tls != NULL)
+ { /* Success! */
+ freeaddrinfo(res);
+ return tls;
+ }
+
+ msg_Err(creds, "connection error: %s", vlc_strerror_c(errno));
vlc_tls_SessionDelete(tcp);
- return tls;
+ }
+
+ /* Failure! */
+ freeaddrinfo(res);
+ return NULL;
}
More information about the vlc-commits
mailing list