From 3014e3059d5732ca5b0954406a0e6fa74ec23148 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Tue, 26 Mar 2019 10:31:00 +0000 Subject: [PATCH] Fix retry when ESP socket send() fails EAGAIN Don't drop packets; requeue them until the socket becomes writeable again. Signed-off-by: David Woodhouse --- esp.c | 69 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/esp.c b/esp.c index 9b79c03a..289c6ebe 100644 --- a/esp.c +++ b/esp.c @@ -261,34 +261,55 @@ int esp_mainloop(struct openconnect_info *vpninfo, int *timeout) case KA_NONE: break; } - unmonitor_write_fd(vpninfo, dtls); - while ((this = dequeue_packet(&vpninfo->outgoing_queue))) { + while (1) { int len; - len = encrypt_esp_packet(vpninfo, this); - if (len > 0) { - ret = send(vpninfo->dtls_fd, (void *)&this->esp, len, 0); - if (ret < 0) { - /* Not that this is likely to happen with UDP, but... */ - if (errno == ENOBUFS || errno == EAGAIN || errno == EWOULDBLOCK) { - monitor_write_fd(vpninfo, dtls); - /* XXX: Keep the packet somewhere? */ - free(this); - return work_done; - } else { - /* A real error in sending. Fall back to TCP? */ - vpn_progress(vpninfo, PRG_ERR, - _("Failed to send ESP packet: %s\n"), - strerror(errno)); - } - } else { - vpninfo->dtls_times.last_tx = time(NULL); + if (vpninfo->deflate_pkt) { + this = vpninfo->deflate_pkt; + len = this->len; + } else { + this = dequeue_packet(&vpninfo->outgoing_queue); + if (!this) + break; - vpn_progress(vpninfo, PRG_TRACE, _("Sent ESP packet of %d bytes\n"), + len = encrypt_esp_packet(vpninfo, this); + if (len < 0) { + vpn_progress(vpninfo, PRG_ERR, + _("Failed to encrypt ESP packet: %d\n"), len); + free(this); + work_done = 1; + continue; + } + } + + ret = send(vpninfo->dtls_fd, (void *)&this->esp, len, 0); + if (ret < 0) { + /* Not that this is likely to happen with UDP, but... */ + if (errno == ENOBUFS || errno == EAGAIN || errno == EWOULDBLOCK) { + int err = errno; + vpninfo->deflate_pkt = this; + this->len = len; + vpn_progress(vpninfo, PRG_DEBUG, + _("Requeueing failed ESP send: %s\n"), + strerror(err)); + monitor_write_fd(vpninfo, dtls); + return work_done; + } else { + /* A real error in sending. Fall back to TCP? */ + vpn_progress(vpninfo, PRG_ERR, + _("Failed to send ESP packet: %s\n"), + strerror(errno)); } } else { - /* XXX: Fall back to TCP transport? */ + vpninfo->dtls_times.last_tx = time(NULL); + + vpn_progress(vpninfo, PRG_TRACE, _("Sent ESP packet of %d bytes\n"), + len); + } + if (this == vpninfo->deflate_pkt) { + unmonitor_write_fd(vpninfo, dtls); + vpninfo->deflate_pkt = NULL; } free(this); work_done = 1; @@ -310,6 +331,10 @@ void esp_close(struct openconnect_info *vpninfo) } if (vpninfo->dtls_state > DTLS_DISABLED) vpninfo->dtls_state = DTLS_SLEEPING; + if (vpninfo->deflate_pkt) { + free(vpninfo->deflate_pkt); + vpninfo->deflate_pkt = NULL; + } } void esp_shutdown(struct openconnect_info *vpninfo) -- 2.50.1