/** * Performs client side of TLS handshake through a connected socket, and * establishes a secure channel. This is a blocking network operation. * * @param fd socket through which to establish the secure channel * @param hostname expected server name, used both as Server Name Indication * and as expected Common Name of the peer certificate * * @return NULL on error. **/ vlc_tls_t *vlc_tls_ClientSessionCreate (vlc_tls_creds_t *crd, int fd, const char *host, const char *service) { vlc_tls_t *session = vlc_tls_SessionCreate (crd, fd, host); if (session == NULL) return NULL; mtime_t deadline = mdate (); deadline += var_InheritInteger (crd, "ipv4-timeout") * 1000; struct pollfd ufd[1]; ufd[0].fd = fd; int val; while ((val = vlc_tls_SessionHandshake (session, host, service)) > 0) { mtime_t now = mdate (); if (now > deadline) now = deadline; assert (val <= 2); ufd[0] .events = (val == 1) ? POLLIN : POLLOUT; if (poll (ufd, 1, (deadline - now) / 1000) == 0) { msg_Err (session, "TLS client session handshake timeout"); val = -1; break; } } while (val > 0); if (val != 0) { msg_Err (session, "TLS client session handshake error"); vlc_tls_SessionDelete (session); session = NULL; } return session; }
static void *tls_echo(void *data) { vlc_tls_t *tls = data; struct pollfd ufd; ssize_t val; char buf[256]; ufd.fd = vlc_tls_GetFD(tls); while ((val = vlc_tls_SessionHandshake(server_creds, tls)) > 0) { switch (val) { case 1: ufd.events = POLLIN; break; case 2: ufd.events = POLLOUT; break; default: vlc_assert_unreachable(); } poll(&ufd, 1, -1); } if (val < 0) goto error; while ((val = vlc_tls_Read(tls, buf, sizeof (buf), false)) > 0) if (vlc_tls_Write(tls, buf, val) < val) goto error; if (val < 0 || vlc_tls_Shutdown(tls, false)) goto error; vlc_tls_Close(tls); return tls; error: vlc_tls_Close(tls); return NULL; }