Commit cff5a808 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

tls: provide an abstract transport layer to TLS plug-ins

This (partially) enables running TLS over something else than a plain
TCP socket file descriptor.
parent 48f2d395
...@@ -46,6 +46,8 @@ struct vlc_tls ...@@ -46,6 +46,8 @@ struct vlc_tls
ssize_t (*writev)(struct vlc_tls *, const struct iovec *, unsigned); ssize_t (*writev)(struct vlc_tls *, const struct iovec *, unsigned);
int (*shutdown)(struct vlc_tls *, bool duplex); int (*shutdown)(struct vlc_tls *, bool duplex);
void (*close)(struct vlc_tls *); void (*close)(struct vlc_tls *);
void *p;
}; };
/** /**
...@@ -149,9 +151,9 @@ struct vlc_tls_creds ...@@ -149,9 +151,9 @@ struct vlc_tls_creds
module_t *module; module_t *module;
void *sys; void *sys;
int (*open) (vlc_tls_creds_t *, vlc_tls_t *, int fd, const char *host, int (*open)(vlc_tls_creds_t *, vlc_tls_t *session, vlc_tls_t *sock,
const char *const *alpn); const char *host, const char *const *alpn);
int (*handshake)(vlc_tls_creds_t *, vlc_tls_t *, const char *host, int (*handshake)(vlc_tls_creds_t *, vlc_tls_t *session, const char *host,
const char *service, char ** /*restrict*/ alp); const char *service, char ** /*restrict*/ alp);
}; };
......
...@@ -133,17 +133,13 @@ static int gnutls_Error(vlc_tls_t *tls, int val) ...@@ -133,17 +133,13 @@ static int gnutls_Error(vlc_tls_t *tls, int val)
static ssize_t vlc_gnutls_read(gnutls_transport_ptr_t ptr, void *buf, static ssize_t vlc_gnutls_read(gnutls_transport_ptr_t ptr, void *buf,
size_t length) size_t length)
{ {
int fd = (intptr_t)ptr; vlc_tls_t *sock = ptr;
struct iovec iov = { struct iovec iov = {
.iov_base = buf, .iov_base = buf,
.iov_len = length, .iov_len = length,
}; };
struct msghdr msg = {
.msg_iov = &iov,
.msg_iovlen = 1,
};
return recvmsg(fd, &msg, 0); return sock->readv(sock, &iov, 1);
} }
static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr, static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
...@@ -157,12 +153,8 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr, ...@@ -157,12 +153,8 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
if (unlikely(iovcnt == 0)) if (unlikely(iovcnt == 0))
return 0; return 0;
vlc_tls_t *sock = ptr;
struct iovec iov[iovcnt]; struct iovec iov[iovcnt];
struct msghdr msg = {
.msg_iov = iov,
.msg_iovlen = iovcnt,
};
int fd = (intptr_t)ptr;
for (int i = 0; i < iovcnt; i++) for (int i = 0; i < iovcnt; i++)
{ {
...@@ -170,14 +162,15 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr, ...@@ -170,14 +162,15 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
iov[i].iov_len = giov[i].iov_len; iov[i].iov_len = giov[i].iov_len;
} }
return sendmsg (fd, &msg, MSG_NOSIGNAL); return sock->writev(sock, iov, iovcnt);
} }
static int gnutls_GetFD(vlc_tls_t *tls) static int gnutls_GetFD(vlc_tls_t *tls)
{ {
gnutls_session_t session = tls->sys; gnutls_session_t session = tls->sys;
vlc_tls_t *sock = gnutls_transport_get_ptr(session);
return gnutls_transport_get_int(session); return vlc_tls_GetFD(sock);
} }
static ssize_t gnutls_Recv(vlc_tls_t *tls, struct iovec *iov, unsigned count) static ssize_t gnutls_Recv(vlc_tls_t *tls, struct iovec *iov, unsigned count)
...@@ -253,8 +246,8 @@ static void gnutls_Close (vlc_tls_t *tls) ...@@ -253,8 +246,8 @@ static void gnutls_Close (vlc_tls_t *tls)
} }
static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type, static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type,
gnutls_certificate_credentials_t x509, int fd, gnutls_certificate_credentials_t x509,
const char *const *alpn) vlc_tls_t *sock, const char *const *alpn)
{ {
gnutls_session_t session; gnutls_session_t session;
const char *errp; const char *errp;
...@@ -313,7 +306,7 @@ static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type, ...@@ -313,7 +306,7 @@ static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type,
free (protv); free (protv);
} }
gnutls_transport_set_ptr(session, (void *)(intptr_t)fd); gnutls_transport_set_ptr(session, sock);
gnutls_transport_set_vec_push_function(session, vlc_gnutls_writev); gnutls_transport_set_vec_push_function(session, vlc_gnutls_writev);
gnutls_transport_set_pull_function(session, vlc_gnutls_read); gnutls_transport_set_pull_function(session, vlc_gnutls_read);
tls->sys = session; tls->sys = session;
...@@ -389,11 +382,11 @@ done: ...@@ -389,11 +382,11 @@ done:
return 0; return 0;
} }
static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls, static int gnutls_ClientSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *tls,
int fd, const char *hostname, vlc_tls_t *sk, const char *hostname,
const char *const *alpn) const char *const *alpn)
{ {
int val = gnutls_SessionOpen(crd, tls, GNUTLS_CLIENT, crd->sys, fd, alpn); int val = gnutls_SessionOpen(crd, tls, GNUTLS_CLIENT, crd->sys, sk, alpn);
if (val != VLC_SUCCESS) if (val != VLC_SUCCESS)
return val; return val;
...@@ -595,14 +588,14 @@ typedef struct vlc_tls_creds_sys ...@@ -595,14 +588,14 @@ typedef struct vlc_tls_creds_sys
/** /**
* Initializes a server-side TLS session. * Initializes a server-side TLS session.
*/ */
static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls, static int gnutls_ServerSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *tls,
int fd, const char *hostname, vlc_tls_t *sock, const char *hostname,
const char *const *alpn) const char *const *alpn)
{ {
vlc_tls_creds_sys_t *sys = crd->sys; vlc_tls_creds_sys_t *sys = crd->sys;
assert (hostname == NULL); assert (hostname == NULL);
return gnutls_SessionOpen(crd, tls, GNUTLS_SERVER, sys->x509_cred, fd, return gnutls_SessionOpen(crd, tls, GNUTLS_SERVER, sys->x509_cred, sock,
alpn); alpn);
} }
......
...@@ -89,7 +89,7 @@ typedef struct { ...@@ -89,7 +89,7 @@ typedef struct {
SSLContextRef p_context; SSLContextRef p_context;
vlc_tls_creds_sys_t *p_cred; vlc_tls_creds_sys_t *p_cred;
size_t i_send_buffered_bytes; size_t i_send_buffered_bytes;
int i_fd; vlc_tls_t *sock;
bool b_blocking_send; bool b_blocking_send;
bool b_handshaked; bool b_handshaked;
...@@ -127,15 +127,14 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection, ...@@ -127,15 +127,14 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection,
vlc_tls_t *session = (vlc_tls_t *)connection; vlc_tls_t *session = (vlc_tls_t *)connection;
vlc_tls_sys_t *sys = session->sys; vlc_tls_sys_t *sys = session->sys;
struct iovec iov = {
size_t bytesToGo = *dataLength; .iov_base = data,
size_t initLen = bytesToGo; .iov_len = *dataLength,
UInt8 *currData = (UInt8 *)data; };
OSStatus retValue = noErr; OSStatus retValue = noErr;
ssize_t val;
for (;;) { while (iov.iov_len > 0) {
val = read(sys->i_fd, currData, bytesToGo); ssize_t val = sys->sock->readv(sys->sock, &iov, 1);
if (val <= 0) { if (val <= 0) {
if (val == 0) { if (val == 0) {
msg_Dbg(session->obj, "found eof"); msg_Dbg(session->obj, "found eof");
...@@ -154,25 +153,20 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection, ...@@ -154,25 +153,20 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection,
sys->b_blocking_send = false; sys->b_blocking_send = false;
break; break;
default: default:
msg_Err(session->obj, "try to read %d bytes, got error %d", msg_Err(session->obj, "try to read %zu bytes, "
(int)bytesToGo, errno); "got error %d", iov.iov_len, errno);
retValue = ioErr; retValue = ioErr;
break; break;
} }
} }
break; break;
} else {
bytesToGo -= val;
currData += val;
} }
if (bytesToGo == 0) { iov.iov_base = (char *)iov.iov_base + val;
/* filled buffer with incoming data, done */ iov.iov_len -= val;
break;
}
} }
*dataLength = initLen - bytesToGo;
*dataLength -= iov.iov_len;
return retValue; return retValue;
} }
...@@ -187,35 +181,39 @@ static OSStatus st_SocketWriteFunc (SSLConnectionRef connection, ...@@ -187,35 +181,39 @@ static OSStatus st_SocketWriteFunc (SSLConnectionRef connection,
vlc_tls_t *session = (vlc_tls_t *)connection; vlc_tls_t *session = (vlc_tls_t *)connection;
vlc_tls_sys_t *sys = session->sys; vlc_tls_sys_t *sys = session->sys;
struct iovec iov = {
size_t bytesSent = 0; .iov_base = (void *)data,
size_t dataLen = *dataLength; .iov_len = *dataLength,
};
OSStatus retValue = noErr; OSStatus retValue = noErr;
ssize_t val;
while (iov.iov_len > 0) {
do { ssize_t val = sys->sock->writev(sys->sock, &iov, 1);
val = write(sys->i_fd, (char *)data + bytesSent, dataLen - bytesSent); if (val < 0) {
} while (val >= 0 && (bytesSent += val) < dataLen); switch (errno) {
case EAGAIN:
if (val < 0) { retValue = errSSLWouldBlock;
switch(errno) { sys->b_blocking_send = true;
case EAGAIN: break;
retValue = errSSLWouldBlock;
sys->b_blocking_send = true; case EPIPE:
break; case ECONNRESET:
retValue = errSSLClosedAbort;
case EPIPE: break;
case ECONNRESET:
retValue = errSSLClosedAbort; default:
break; msg_Err(session->obj, "error while writing: %d", errno);
retValue = ioErr;
default: break;
msg_Err(session->obj, "error while writing: %d", errno); }
retValue = ioErr; break;
} }
iov.iov_base = (char *)iov.iov_base + val;
iov.iov_len -= val;
} }
*dataLength = bytesSent; *dataLength -= iov.iov_len;
return retValue; return retValue;
} }
......
...@@ -131,13 +131,21 @@ void vlc_tls_Delete (vlc_tls_creds_t *crd) ...@@ -131,13 +131,21 @@ void vlc_tls_Delete (vlc_tls_creds_t *crd)
vlc_tls_t *vlc_tls_SessionCreate (vlc_tls_creds_t *crd, int fd, vlc_tls_t *vlc_tls_SessionCreate (vlc_tls_creds_t *crd, int fd,
const char *host, const char *const *alpn) const char *host, const char *const *alpn)
{ {
vlc_tls_t *sock = vlc_tls_SocketOpen(VLC_OBJECT(crd), fd);
if (unlikely(sock == NULL))
return NULL;
vlc_tls_t *session = malloc(sizeof (*session)); vlc_tls_t *session = malloc(sizeof (*session));
if (unlikely(session == NULL)) if (unlikely(session == NULL))
{
vlc_tls_SessionDelete(sock);
return NULL; return NULL;
}
session->obj = crd->p_parent; session->obj = crd->p_parent;
session->p = sock;
int val = crd->open (crd, session, fd, host, alpn); int val = crd->open(crd, session, sock, host, alpn);
if (val != VLC_SUCCESS) if (val != VLC_SUCCESS)
{ {
free(session); free(session);
...@@ -148,11 +156,17 @@ vlc_tls_t *vlc_tls_SessionCreate (vlc_tls_creds_t *crd, int fd, ...@@ -148,11 +156,17 @@ vlc_tls_t *vlc_tls_SessionCreate (vlc_tls_creds_t *crd, int fd,
void vlc_tls_SessionDelete (vlc_tls_t *session) void vlc_tls_SessionDelete (vlc_tls_t *session)
{ {
int canc = vlc_savecancel(); do
session->close(session); {
vlc_restorecancel(canc); int canc = vlc_savecancel();
session->close(session);
vlc_restorecancel(canc);
free(session); vlc_tls_t *sock = session->p;
free(session);
session = sock;
}
while (session != NULL);
} }
static void cleanup_tls(void *data) static void cleanup_tls(void *data)
...@@ -376,5 +390,6 @@ vlc_tls_t *vlc_tls_SocketOpen(vlc_object_t *obj, int fd) ...@@ -376,5 +390,6 @@ vlc_tls_t *vlc_tls_SocketOpen(vlc_object_t *obj, int fd)
session->writev = vlc_tls_SocketWrite; session->writev = vlc_tls_SocketWrite;
session->shutdown = vlc_tls_SocketShutdown; session->shutdown = vlc_tls_SocketShutdown;
session->close = vlc_tls_SocketClose; session->close = vlc_tls_SocketClose;
session->p = NULL;
return session; return session;
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment