]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Fix epoll support for connection pause/restart
authorDavid Woodhouse <dwmw2@infradead.org>
Thu, 1 Jul 2021 15:30:27 +0000 (16:30 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Thu, 1 Jul 2021 15:40:25 +0000 (16:40 +0100)
We need to actually remove the file descriptors from the epoll set.
Otherwise we get -EEXIST when adding them again (in the case of the
cmd_fd as we re-enter the main loop).

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
dtls.c
esp.c
gnutls.c
mainloop.c
openconnect-internal.h
openssl.c
tun.c

diff --git a/dtls.c b/dtls.c
index 894a9687a92fa233a717d826a134c05c3a70b1b3..ca8ad551090855f227ff14168920e888e883b5b4 100644 (file)
--- a/dtls.c
+++ b/dtls.c
@@ -154,9 +154,7 @@ void dtls_close(struct openconnect_info *vpninfo)
 {
        if (vpninfo->dtls_ssl) {
                dtls_ssl_free(vpninfo);
-               unmonitor_read_fd(vpninfo, dtls);
-               unmonitor_write_fd(vpninfo, dtls);
-               unmonitor_except_fd(vpninfo, dtls);
+               unmonitor_fd(vpninfo, dtls);
                closesocket(vpninfo->dtls_fd);
                vpninfo->dtls_ssl = NULL;
                vpninfo->dtls_fd = -1;
diff --git a/esp.c b/esp.c
index 56190b17d999e8fae121f9d4b92b6acefdf8d51a..cc423a580e5d0b96e7c9cd3b5573a36167e1cc41 100644 (file)
--- a/esp.c
+++ b/esp.c
@@ -392,9 +392,7 @@ void esp_close(struct openconnect_info *vpninfo)
        /* We close and reopen the socket in case we roamed and our
           local IP address has changed. */
        if (vpninfo->dtls_fd != -1) {
-               unmonitor_read_fd(vpninfo, dtls);
-               unmonitor_write_fd(vpninfo, dtls);
-               unmonitor_except_fd(vpninfo, dtls);
+               unmonitor_fd(vpninfo, dtls);
                closesocket(vpninfo->dtls_fd);
                vpninfo->dtls_fd = -1;
        }
index afa5d91794cd8b8f188a06cd54965dd68f4c9487..12147ab5a745ed6959b98ec87414b44e6aefc6e2 100644 (file)
--- a/gnutls.c
+++ b/gnutls.c
@@ -2473,9 +2473,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
                vpninfo->https_sess = NULL;
        }
        if (vpninfo->ssl_fd != -1) {
-               unmonitor_read_fd(vpninfo, ssl);
-               unmonitor_write_fd(vpninfo, ssl);
-               unmonitor_except_fd(vpninfo, ssl);
+               unmonitor_fd(vpninfo, ssl);
                closesocket(vpninfo->ssl_fd);
                vpninfo->ssl_fd = -1;
        }
index 0d57db261697a63ffa8b284876dffb24efdf3d9a..848049faddf9f716b9f91eeae77fd6deed926472 100644 (file)
@@ -285,6 +285,10 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,
 
                                vpninfo->got_pause_cmd = 0;
                                vpn_progress(vpninfo, PRG_INFO, _("Caller paused the connection\n"));
+
+                               if (vpninfo->cmd_fd >= 0)
+                                       unmonitor_fd(vpninfo, cmd);
+
                                return 0;
                        }
                }
@@ -390,6 +394,10 @@ int openconnect_mainloop(struct openconnect_info *vpninfo,
 
        if (tun_is_up(vpninfo))
                os_shutdown_tun(vpninfo);
+
+       if (vpninfo->cmd_fd >= 0)
+               unmonitor_fd(vpninfo, cmd);
+
        return ret < 0 ? ret : -EIO;
 }
 
index e4ac54193c9b3c6496bf27aaf4f25dea9a91d29a..023b14be67e50568c67600998b068cbc6ebc61f8 100644 (file)
@@ -856,8 +856,11 @@ static inline void free_pkt(struct openconnect_info *vpninfo, struct pkt *pkt)
 #define monitor_fd_new(_v, _n) do { if (!_v->_n##_event) _v->_n##_event = CreateEvent(NULL, FALSE, FALSE, NULL); } while (0)
 #define read_fd_monitored(_v, _n) (_v->_n##_monitored & FD_READ)
 
-#else
+#define __unmonitor_fd(_v, _n) do { CloseHandle(_v->_n##_event); \
+               _v->_n##_event = (HANDLE)0;                      \
+       } while(0)
 
+#else
 
 #ifdef HAVE_EPOLL
 static inline void __sync_epoll_fd(struct openconnect_info *vpninfo, int fd, uint32_t *fd_evts)
@@ -880,10 +883,27 @@ static inline void __sync_epoll_fd(struct openconnect_info *vpninfo, int fd, uin
        }
 }
 #define update_epoll_fd(_v, _n) __sync_epoll_fd(_v, _v->_n##_fd, &_v->_n##_epoll)
+
+static inline void __remove_epoll_fd(struct openconnect_info *vpninfo, int fd)
+{
+       struct epoll_event ev = { 0 };
+       if (vpninfo->epoll_fd >= 0 &&
+           epoll_ctl(vpninfo->epoll_fd, EPOLL_CTL_DEL, fd, &ev) < 0)
+               vpn_perror(vpninfo, "EPOLL_CTL_DEL");
+       /* No other action on error; if it truly matters we'll bail
+        * later and fall back to select() */
+}
+
+#define __unmonitor_fd(_v, _n) do {                \
+               __remove_epoll_fd(_v, _v->_n##_fd); \
+               _v->_n##_epoll = 0; } while(0)
+
+#else /* !HAVE_POLL */
+#define __unmonitor_fd(_v, _n) do { } while(0)
 #endif
 
-static inline void __monitor_fd(struct openconnect_info *vpninfo,
-                               int fd, fd_set *set)
+static inline void __monitor_fd_event(struct openconnect_info *vpninfo,
+                                     int fd, fd_set *set)
 {
        if (fd < 0 || FD_ISSET(fd, set))
                return;
@@ -894,8 +914,8 @@ static inline void __monitor_fd(struct openconnect_info *vpninfo,
 #endif
 }
 
-static inline void __unmonitor_fd(struct openconnect_info *vpninfo,
-                                 int fd, fd_set *set)
+static inline void __unmonitor_fd_event(struct openconnect_info *vpninfo,
+                                       int fd, fd_set *set)
 {
        if (fd < 0 || !FD_ISSET(fd, set))
                return;
@@ -906,12 +926,12 @@ static inline void __unmonitor_fd(struct openconnect_info *vpninfo,
 #endif
 }
 
-#define monitor_read_fd(_v, _n) __monitor_fd(_v, _v->_n##_fd, &_v->_select_rfds)
-#define unmonitor_read_fd(_v, _n) __unmonitor_fd(_v, _v->_n##_fd, &_v->_select_rfds)
-#define monitor_write_fd(_v, _n) __monitor_fd(_v, _v->_n##_fd, &_v->_select_wfds)
-#define unmonitor_write_fd(_v, _n) __unmonitor_fd(_v, _v->_n##_fd, &_v->_select_wfds)
-#define monitor_except_fd(_v, _n) __monitor_fd(_v, _v->_n##_fd, &_v->_select_efds)
-#define unmonitor_except_fd(_v, _n) __unmonitor_fd(_v, _v->_n##_fd, &_v->_select_efds)
+#define monitor_read_fd(_v, _n) __monitor_fd_event(_v, _v->_n##_fd, &_v->_select_rfds)
+#define unmonitor_read_fd(_v, _n) __unmonitor_fd_event(_v, _v->_n##_fd, &_v->_select_rfds)
+#define monitor_write_fd(_v, _n) __monitor_fd_event(_v, _v->_n##_fd, &_v->_select_wfds)
+#define unmonitor_write_fd(_v, _n) __unmonitor_fd_event(_v, _v->_n##_fd, &_v->_select_wfds)
+#define monitor_except_fd(_v, _n) __monitor_fd_event(_v, _v->_n##_fd, &_v->_select_efds)
+#define unmonitor_except_fd(_v, _n) __unmonitor_fd_event(_v, _v->_n##_fd, &_v->_select_efds)
 
 static inline void __monitor_fd_new(struct openconnect_info *vpninfo,
                                    int fd)
@@ -931,11 +951,17 @@ static inline void __monitor_fd_new(struct openconnect_info *vpninfo,
 #endif
 }
 
-
 #define monitor_fd_new(_v, _n) __monitor_fd_new(_v, _v->_n##_fd)
-
 #define read_fd_monitored(_v, _n) FD_ISSET(_v->_n##_fd, &_v->_select_rfds)
-#endif
+#endif /* !WIN32 */
+
+/* This is for all platforms */
+#define unmonitor_fd(_v, _n) do {              \
+               unmonitor_read_fd(_v, _n);      \
+               unmonitor_write_fd(_v, _n);     \
+               unmonitor_except_fd(_v, _n);    \
+               __unmonitor_fd(_v, _n);         \
+       } while(0)
 
 /* Key material for DTLS-PSK */
 #define PSK_LABEL "EXPORTER-openconnect-psk"
index 095e29f3bf6d9f8baee48487d6875649e311ac1f..8d8e81f5cf3c840ff6a33ed04956dfb6ae5320c0 100644 (file)
--- a/openssl.c
+++ b/openssl.c
@@ -1999,9 +1999,7 @@ void openconnect_close_https(struct openconnect_info *vpninfo, int final)
                vpninfo->https_ssl = NULL;
        }
        if (vpninfo->ssl_fd != -1) {
-               unmonitor_read_fd(vpninfo, ssl);
-               unmonitor_write_fd(vpninfo, ssl);
-               unmonitor_except_fd(vpninfo, ssl);
+               unmonitor_fd(vpninfo, ssl);
                closesocket(vpninfo->ssl_fd);
                vpninfo->ssl_fd = -1;
        }
diff --git a/tun.c b/tun.c
index e5b8a49df183011ff53213ab78fb4ea8a807d075..eba766d8859f5fecff18b868b5971cd9456788f4 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -453,7 +453,7 @@ int openconnect_setup_tun_fd(struct openconnect_info *vpninfo, int tun_fd)
        set_fd_cloexec(tun_fd);
 
        if (vpninfo->tun_fd != -1)
-               unmonitor_read_fd(vpninfo, tun);
+               unmonitor_fd(vpninfo, tun);
 
        vpninfo->tun_fd = tun_fd;