Most callers will use a simple nonblocking UNIX pipe as their cancel_fd, so provide a convenience function for creating it. Also, libopenconnect will take care of cleaning up pipes created in this manner when the library instance is freed. Signed-off-by: Kevin Cernekee <cernekee at gmail.com> --- libopenconnect.map.in | 5 +++++ library.c | 24 ++++++++++++++++++++++++ openconnect-internal.h | 1 + openconnect.h | 5 +++++ 4 files changed, 35 insertions(+) diff --git a/libopenconnect.map.in b/libopenconnect.map.in index 16d3380..2845754 100644 --- a/libopenconnect.map.in +++ b/libopenconnect.map.in @@ -43,6 +43,11 @@ OPENCONNECT_2.2 { openconnect_set_token_mode; } OPENCONNECT_2.1; +OPENCONNECT_2.3 { + global: + openconnect_setup_cancel_pipe; +} OPENCONNECT_2.2; + OPENCONNECT_PRIVATE { global: @SYMVER_TIME@ @SYMVER_ASPRINTF@ @SYMVER_GETLINE@ @SYMVER_PRINT_ERR@ openconnect_SSL_gets; diff --git a/library.c b/library.c index 66bf89b..86c3df8 100644 --- a/library.c +++ b/library.c @@ -26,6 +26,8 @@ #include <string.h> #include <errno.h> #include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> #ifdef HAVE_LIBSTOKEN #include <stoken.h> @@ -57,6 +59,7 @@ struct openconnect_info *openconnect_vpninfo_new(char *useragent, vpninfo->progress = progress; vpninfo->cbdata = privdata ? : vpninfo; vpninfo->cancel_fd = -1; + vpninfo->cancel_fd_write = -1; vpninfo->xmlpost = 1; openconnect_set_reported_os(vpninfo, NULL); @@ -106,6 +109,10 @@ static void free_optlist(struct vpn_option *opt) void openconnect_vpninfo_free(struct openconnect_info *vpninfo) { openconnect_close_https(vpninfo, 1); + if (vpninfo->cancel_fd_write != -1) { + close(vpninfo->cancel_fd); + close(vpninfo->cancel_fd_write); + } free(vpninfo->peer_addr); free_optlist(vpninfo->cookies); free_optlist(vpninfo->cstp_options); @@ -287,6 +294,23 @@ void openconnect_set_cancel_fd(struct openconnect_info *vpninfo, int fd) vpninfo->cancel_fd = fd; } +int openconnect_setup_cancel_pipe(struct openconnect_info *vpninfo) +{ + int pipefd[2]; + + if (pipe(pipefd) < 0) + return -EIO; + if (fcntl(pipefd[0], F_SETFL, O_NONBLOCK) || + fcntl(pipefd[1], F_SETFL, O_NONBLOCK)) { + close(pipefd[0]); + close(pipefd[1]); + return -EIO; + } + vpninfo->cancel_fd = pipefd[0]; + vpninfo->cancel_fd_write = pipefd[1]; + return vpninfo->cancel_fd_write; +} + const char *openconnect_get_version(void) { return openconnect_version_str; diff --git a/openconnect-internal.h b/openconnect-internal.h index ea59d23..549448c 100644 --- a/openconnect-internal.h +++ b/openconnect-internal.h @@ -295,6 +295,7 @@ struct openconnect_info { int dtls_fd; int new_dtls_fd; int cancel_fd; + int cancel_fd_write; struct pkt *incoming_queue; struct pkt *outgoing_queue; diff --git a/openconnect.h b/openconnect.h index d48bc25..47ac8b5 100644 --- a/openconnect.h +++ b/openconnect.h @@ -217,6 +217,11 @@ void openconnect_set_cert_expiry_warning(struct openconnect_info *vpninfo, cancellation mechanism inactive. */ void openconnect_set_cancel_fd(struct openconnect_info *vpninfo, int fd); +/* Create a nonblocking pipe, set the read end as the cancel_fd, and return a + file descriptor for the write end. Both sides will be closed by + openconnect_vpninfo_free(). */ +int openconnect_setup_cancel_pipe(struct openconnect_info *vpninfo); + const char *openconnect_get_version(void); /* The first (privdata) argument to each of these functions is either -- 1.7.9.5