--- gvpe/src/vpn.C 2015/07/15 23:04:06 1.68 +++ gvpe/src/vpn.C 2015/09/05 17:40:22 1.69 @@ -61,6 +61,32 @@ ///////////////////////////////////////////////////////////////////////////// +// hopefully temporary workaround for rare buffer full conditions +// if it happens, usually instantly retrying or retrying ~5ms later +// is good enough with current network technologies/kernels + +static ssize_t +xsendto (int fd, const void *buf, size_t len, int flags, + const struct sockaddr *sa, socklen_t salen) +{ + ssize_t res; + + for (int retry = 0; retry <= 13; ++retry) // ~100ms + { + res = sendto (fd, buf, len, flags, sa, salen); + + if (res >= 0 || errno != ENOBUFS) + break; + + struct timespec ts = { 0, 1000 * retry }; + nanosleep (&ts, 0); + } + + return res; +} + +///////////////////////////////////////////////////////////////////////////// + static void inline set_tos (int fd, int &tos_prev, int tos) { @@ -462,7 +488,7 @@ vpn::send_ipv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { set_tos (ipv4_fd, ipv4_tos, tos); - sendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (ipv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; } @@ -503,7 +529,7 @@ hdr->checksum = ipv4_checksum ((u16 *)hdr, pkt->len); set_tos (icmpv4_fd, icmpv4_tos, tos); - sendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (icmpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; } @@ -513,7 +539,7 @@ vpn::send_udpv4_packet (vpn_packet *pkt, const sockinfo &si, int tos) { set_tos (udpv4_fd, udpv4_tos, tos); - sendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); + xsendto (udpv4_fd, &((*pkt)[0]), pkt->len, 0, si.sav4 (), si.salenv4 ()); return true; }