From 8388bc3705b60491cf1ae06aed7e78fa34ea2978 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Sat, 9 Apr 2022 22:45:49 +0100 Subject: [PATCH] Add cancellable_accept(), make cancellable_send() take a const buffer These will be needed for AnyConnect 'external browser' SAML mode. Signed-off-by: David Woodhouse --- openconnect-internal.h | 3 ++- ssl.c | 58 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/openconnect-internal.h b/openconnect-internal.h index f066246a..a14a8252 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -1372,9 +1372,10 @@ int cancellable_gets(struct openconnect_info *vpninfo, int fd, char *buf, size_t len); int cancellable_send(struct openconnect_info *vpninfo, int fd, - char *buf, size_t len); + const char *buf, size_t len); int cancellable_recv(struct openconnect_info *vpninfo, int fd, char *buf, size_t len); +int cancellable_accept(struct openconnect_info *vpninfo, int fd); #if defined(OPENCONNECT_OPENSSL) /* openssl-pkcs11.c */ diff --git a/ssl.c b/ssl.c index e77abba2..aa706f79 100644 --- a/ssl.c +++ b/ssl.c @@ -156,6 +156,62 @@ static int cancellable_connect(struct openconnect_info *vpninfo, int sockfd, return err; } + +static inline int accept_pending(void) +{ +#ifdef _WIN32 + return WSAGetLastError() == WSAEWOULDBLOCK; +#else + return errno == EAGAIN || errno == EWOULDBLOCK; +#endif +} + +int cancellable_accept(struct openconnect_info *vpninfo, int sockfd) +{ + fd_set wr_set, rd_set, ex_set; + int accept_fd, maxfd = sockfd; + char *errstr; + + do { + accept_fd = accept(sockfd, NULL, NULL); + if (accept_fd >= 0) + return accept_fd; + + if (!accept_pending()) + break; + + FD_ZERO(&wr_set); + FD_ZERO(&rd_set); + FD_ZERO(&ex_set); + FD_SET(sockfd, &rd_set); + + cmd_fd_set(vpninfo, &rd_set, &maxfd); + if (select(maxfd + 1, &rd_set, &wr_set, &ex_set, NULL) < 0 && + errno != EINTR) { + vpn_perror(vpninfo, _("Failed select() for socket accept")); + return -EIO; + } + + if (is_cancel_pending(vpninfo, &rd_set)) { + vpn_progress(vpninfo, PRG_ERR, _("Socket accept cancelled\n")); + return -EINTR; + } + } while (!FD_ISSET(sockfd, &ex_set) && !vpninfo->got_pause_cmd); + +#ifdef _WIN32 + errstr = openconnect__win32_strerror(WSAGetLastError()); +#else + errstr = strerror(errno); +#endif + vpn_progress(vpninfo, PRG_ERR, + _("Failed to accept local connection: %s\n"), + errstr); +#ifdef _WIN32 + free(errstr); +#endif + return -1; +} + /* checks whether the provided string is an IP or a hostname. */ unsigned string_is_hostname(const char *str) @@ -1212,7 +1268,7 @@ int cancellable_gets(struct openconnect_info *vpninfo, int fd, } int cancellable_send(struct openconnect_info *vpninfo, int fd, - char *buf, size_t len) + const char *buf, size_t len) { size_t count; -- 2.49.0