Set O_NONBLOCK for UDP sockets not to block on recv(). Actually
authoryasuoka <yasuoka@openbsd.org>
Tue, 27 Oct 2015 04:27:01 +0000 (04:27 +0000)
committeryasuoka <yasuoka@openbsd.org>
Tue, 27 Oct 2015 04:27:01 +0000 (04:27 +0000)
block had happened if an error of the socket is handled by send().

diff from Yuuichi Someya.

usr.sbin/radiusd/radiusd.c
usr.sbin/radiusd/radiusd_radius.c

index 0c1a2ff..6a85c0b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: radiusd.c,v 1.10 2015/10/27 04:18:36 yasuoka Exp $    */
+/*     $OpenBSD: radiusd.c,v 1.11 2015/10/27 04:27:01 yasuoka Exp $    */
 
 /*
  * Copyright (c) 2013 Internet Initiative Japan Inc.
@@ -197,7 +197,7 @@ radiusd_start(struct radiusd *radiusd)
 {
        struct radiusd_listen   *l;
        struct radiusd_module   *module;
-       int                      s;
+       int                      s, ival;
        char                     hbuf[NI_MAXHOST];
 
        TAILQ_FOREACH(l, &radiusd->listen, next) {
@@ -220,6 +220,16 @@ radiusd_start(struct radiusd *radiusd)
                        close(s);
                        goto on_error;
                }
+               if ((ival = fcntl(s, F_GETFL, 0)) < 0) {
+                       log_warn("fcntl(F_GETFL) failed at %s()", __func__);
+                       close(s);
+                       goto on_error;
+               }
+               if (fcntl(s, F_SETFL, ival | O_NONBLOCK) < 0) {
+                       log_warn("fcntl(F_SETFL,O_NONBLOCK) failed at %s()", __func__);
+                       close(s);
+                       goto on_error;
+               }
                if (l->addr.ipv4.sin_family == AF_INET)
                        log_info("Start listening on %s:%d/udp", hbuf,
                            (int)ntohs(l->addr.ipv4.sin_port));
@@ -368,6 +378,8 @@ radiusd_listen_on_event(int fd, short evmask, void *ctx)
                peersz = sizeof(peer);
                if ((sz = recvfrom(listn->sock, buf, sizeof(buf), 0,
                    (struct sockaddr *)&peer, &peersz)) < 0) {
+                       if (errno == EAGAIN)
+                               return;
                        log_warn("%s: recvfrom() failed", __func__);
                        goto on_error;
                }
index 88590ff..8015384 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: radiusd_radius.c,v 1.8 2015/10/19 22:07:37 yasuoka Exp $      */
+/*     $OpenBSD: radiusd_radius.c,v 1.9 2015/10/27 04:27:01 yasuoka Exp $      */
 
 /*
  * Copyright (c) 2013 Internet Initiative Japan Inc.
@@ -22,7 +22,9 @@
 #include <netinet/in.h>
 
 #include <err.h>
+#include <errno.h>
 #include <event.h>
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -326,6 +328,7 @@ on_fail:
 static int
 radius_server_start(struct radius_server *server)
 {
+       int              ival;
        socklen_t        locallen;
        char             buf0[NI_MAXHOST + NI_MAXSERV + 32];
        char             buf1[NI_MAXHOST + NI_MAXSERV + 32];
@@ -343,6 +346,16 @@ radius_server_start(struct radius_server *server)
                        server->addr.sin4.sin_len, buf1, sizeof(buf1)));
                goto on_error;
        }
+       if ((ival = fcntl(server->sock, F_GETFL, 0)) < 0) {
+               module_radius_log(server->module, LOG_WARNING,
+                   "%s: fcntl(F_GETFL) failed", __func__);
+               goto on_error;
+       }
+       if (fcntl(server->sock, F_SETFL, ival | O_NONBLOCK) < 0) {
+               module_radius_log(server->module, LOG_WARNING,
+                   "%s: fcntl(F_SETFL) failed", __func__);
+               goto on_error;
+       }
        locallen = sizeof(server->local);
        if (getsockname(server->sock, (struct sockaddr *)&server->local,
            &locallen) != 0) {
@@ -394,7 +407,9 @@ radius_server_on_event(int fd, short evmask, void *ctx)
        struct sockaddr                 *peer;
 
        peer = (struct sockaddr *)&server->addr;
-       if ((sz = recv(server->sock, pkt, sizeof(pkt), 0)) <= 0) {
+       if ((sz = recv(server->sock, pkt, sizeof(pkt), 0)) == -1) {
+               if (errno == EAGAIN)
+                       return;
                module_radius_log(server->module, LOG_WARNING,
                    "server=%s recv() failed: %m",
                    addrport_tostring(peer, peer->sa_len, buf, sizeof(buf)));