#include <isc/region.h>
#include <isc/result.h>
#include <isc/sockaddr.h>
+#include <isc/stdtime.h>
#include <isc/thread.h>
#include <isc/util.h>
#include <isc/uv.h>
isc__nm_sendcb(sock, uvreq, result, false);
}
+static _Atomic(isc_stdtime_t) last_udpsends_log = 0;
+
+static bool
+can_log_udp_sends(void) {
+ isc_stdtime_t now = isc_stdtime_now();
+ isc_stdtime_t last = atomic_exchange_relaxed(&last_udpsends_log, now);
+ if (now != last) {
+ return (true);
+ }
+
+ return (false);
+}
+
/*
* Send the data in 'region' to a peer via a UDP socket. We try to find
* a proper sibling/child socket so that we won't have to jump to
goto fail;
}
- r = uv_udp_send(&uvreq->uv_req.udp_send, &sock->uv_handle.udp,
- &uvreq->uvbuf, 1, sa, udp_send_cb);
- if (r < 0) {
- isc__nm_incstats(sock, STATID_SENDFAIL);
- result = isc_uverr2result(r);
- goto fail;
+ if (uv_udp_get_send_queue_size(&sock->uv_handle.udp) >
+ ISC_NETMGR_UDP_SENDBUF_SIZE)
+ {
+ /*
+ * The kernel UDP send queue is full, try sending the UDP
+ * response synchronously instead of just failing.
+ */
+ r = uv_udp_try_send(&sock->uv_handle.udp, &uvreq->uvbuf, 1, sa);
+ if (r < 0) {
+ if (can_log_udp_sends()) {
+ isc__netmgr_log(
+ worker->netmgr, ISC_LOG_ERROR,
+ "Sending UDP messages failed: %s",
+ isc_result_totext(isc_uverr2result(r)));
+ }
+
+ isc__nm_incstats(sock, STATID_SENDFAIL);
+ result = isc_uverr2result(r);
+ goto fail;
+ }
+
+ RUNTIME_CHECK(r == (int)region->length);
+ isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, true);
+
+ } else {
+ /* Send the message asynchronously */
+ r = uv_udp_send(&uvreq->uv_req.udp_send, &sock->uv_handle.udp,
+ &uvreq->uvbuf, 1, sa, udp_send_cb);
+ if (r < 0) {
+ isc__nm_incstats(sock, STATID_SENDFAIL);
+ result = isc_uverr2result(r);
+ goto fail;
+ }
}
return;
fail: