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
ssize_t (*writev)(struct vlc_tls *, const struct iovec *, unsigned);
int (*shutdown)(struct vlc_tls *, bool duplex);
void (*close)(struct vlc_tls *);
void *p;
};
/**
......@@ -149,9 +151,9 @@ struct vlc_tls_creds
module_t *module;
void *sys;
int (*open) (vlc_tls_creds_t *, vlc_tls_t *, int fd, const char *host,
const char *const *alpn);
int (*handshake)(vlc_tls_creds_t *, vlc_tls_t *, const char *host,
int (*open)(vlc_tls_creds_t *, vlc_tls_t *session, vlc_tls_t *sock,
const char *host, const char *const *alpn);
int (*handshake)(vlc_tls_creds_t *, vlc_tls_t *session, const char *host,
const char *service, char ** /*restrict*/ alp);
};
......
......@@ -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,
size_t length)
{
int fd = (intptr_t)ptr;
vlc_tls_t *sock = ptr;
struct iovec iov = {
.iov_base = buf,
.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,
......@@ -157,12 +153,8 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
if (unlikely(iovcnt == 0))
return 0;
vlc_tls_t *sock = ptr;
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++)
{
......@@ -170,14 +162,15 @@ static ssize_t vlc_gnutls_writev(gnutls_transport_ptr_t ptr,
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)
{
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)
......@@ -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,
gnutls_certificate_credentials_t x509, int fd,
const char *const *alpn)
gnutls_certificate_credentials_t x509,
vlc_tls_t *sock, const char *const *alpn)
{
gnutls_session_t session;
const char *errp;
......@@ -313,7 +306,7 @@ static int gnutls_SessionOpen(vlc_tls_creds_t *creds, vlc_tls_t *tls, int type,
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_pull_function(session, vlc_gnutls_read);
tls->sys = session;
......@@ -389,11 +382,11 @@ done:
return 0;
}
static int gnutls_ClientSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
int fd, const char *hostname,
static int gnutls_ClientSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *tls,
vlc_tls_t *sk, const char *hostname,
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)
return val;
......@@ -595,14 +588,14 @@ typedef struct vlc_tls_creds_sys
/**
* Initializes a server-side TLS session.
*/
static int gnutls_ServerSessionOpen (vlc_tls_creds_t *crd, vlc_tls_t *tls,
int fd, const char *hostname,
static int gnutls_ServerSessionOpen(vlc_tls_creds_t *crd, vlc_tls_t *tls,
vlc_tls_t *sock, const char *hostname,
const char *const *alpn)
{
vlc_tls_creds_sys_t *sys = crd->sys;
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);
}
......
......@@ -89,7 +89,7 @@ typedef struct {
SSLContextRef p_context;
vlc_tls_creds_sys_t *p_cred;
size_t i_send_buffered_bytes;
int i_fd;
vlc_tls_t *sock;
bool b_blocking_send;
bool b_handshaked;
......@@ -127,15 +127,14 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection,
vlc_tls_t *session = (vlc_tls_t *)connection;
vlc_tls_sys_t *sys = session->sys;
size_t bytesToGo = *dataLength;
size_t initLen = bytesToGo;
UInt8 *currData = (UInt8 *)data;
struct iovec iov = {
.iov_base = data,
.iov_len = *dataLength,
};
OSStatus retValue = noErr;
ssize_t val;
for (;;) {
val = read(sys->i_fd, currData, bytesToGo);
while (iov.iov_len > 0) {
ssize_t val = sys->sock->readv(sys->sock, &iov, 1);
if (val <= 0) {
if (val == 0) {
msg_Dbg(session->obj, "found eof");
......@@ -154,25 +153,20 @@ static OSStatus st_SocketReadFunc (SSLConnectionRef connection,
sys->b_blocking_send = false;
break;
default:
msg_Err(session->obj, "try to read %d bytes, got error %d",
(int)bytesToGo, errno);
msg_Err(session->obj, "try to read %zu bytes, "
"got error %d", iov.iov_len, errno);
retValue = ioErr;
break;
}
}
break;
} else {
bytesToGo -= val;
currData += val;
}
if (bytesToGo == 0) {
/* filled buffer with incoming data, done */
break;
iov.iov_base = (char *)iov.iov_base + val;
iov.iov_len -= val;
}
}
*dataLength = initLen - bytesToGo;
*dataLength -= iov.iov_len;
return retValue;
}
......@@ -187,18 +181,16 @@ static OSStatus st_SocketWriteFunc (SSLConnectionRef connection,
vlc_tls_t *session = (vlc_tls_t *)connection;
vlc_tls_sys_t *sys = session->sys;
size_t bytesSent = 0;
size_t dataLen = *dataLength;
struct iovec iov = {
.iov_base = (void *)data,
.iov_len = *dataLength,
};
OSStatus retValue = noErr;
ssize_t val;
do {
val = write(sys->i_fd, (char *)data + bytesSent, dataLen - bytesSent);
} while (val >= 0 && (bytesSent += val) < dataLen);
while (iov.iov_len > 0) {
ssize_t val = sys->sock->writev(sys->sock, &iov, 1);
if (val < 0) {
switch(errno) {
switch (errno) {
case EAGAIN:
retValue = errSSLWouldBlock;
sys->b_blocking_send = true;
......@@ -212,10 +204,16 @@ static OSStatus st_SocketWriteFunc (SSLConnectionRef connection,
default:
msg_Err(session->obj, "error while writing: %d", errno);
retValue = ioErr;
break;
}
break;
}
iov.iov_base = (char *)iov.iov_base + val;
iov.iov_len -= val;
}
*dataLength = bytesSent;
*dataLength -= iov.iov_len;
return retValue;
}
......
......@@ -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,
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));
if (unlikely(session == NULL))
{
vlc_tls_SessionDelete(sock);
return NULL;
}
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)
{
free(session);
......@@ -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)
{
do
{
int canc = vlc_savecancel();
session->close(session);
vlc_restorecancel(canc);
vlc_tls_t *sock = session->p;
free(session);
session = sock;
}
while (session != NULL);
}
static void cleanup_tls(void *data)
......@@ -376,5 +390,6 @@ vlc_tls_t *vlc_tls_SocketOpen(vlc_object_t *obj, int fd)
session->writev = vlc_tls_SocketWrite;
session->shutdown = vlc_tls_SocketShutdown;
session->close = vlc_tls_SocketClose;
session->p = NULL;
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