From: Mark Wooding Date: Wed, 6 Jun 2018 19:04:16 +0000 (+0100) Subject: noip.c: Add commentary to some hairier functions. X-Git-Tag: 1.2.0~23 X-Git-Url: https://git.distorted.org.uk/~mdw/preload-hacks/commitdiff_plain/4b1a617448e8ce7b0169f45523fcee8d861cd573 noip.c: Add commentary to some hairier functions. No code change. --- diff --git a/noip.c b/noip.c index e3da246..8806d02 100644 --- a/noip.c +++ b/noip.c @@ -641,10 +641,23 @@ static int unix_socket_status(struct sockaddr_un *sun, int quickp) int rc; char buf[256]; + /* If we can't find the socket node, then it's definitely not in use. If + * we get some other error, then this socket is weird. + */ if (stat(sun->sun_path, &st)) return (errno == ENOENT ? UNUSED : USED); + + /* If it's not a socket, then something weird is going on. If we're just + * probing quickly to find a spare port, then existence is sufficient to + * discourage us now. + */ if (!S_ISSOCK(st.st_mode) || quickp) return (USED); + + /* The socket's definitely there, but is anyone actually still holding it + * open? The only way I know to discover this is to trundle through + * `/proc/net/unix'. If there's no entry, then the socket must be stale. + */ rc = USED; if ((fp = fopen("/proc/net/unix", "r")) == 0) goto done; @@ -661,6 +674,8 @@ static int unix_socket_status(struct sockaddr_un *sun, int quickp) rc = STALE; done: if (fp) fclose(fp); + + /* All done. */ return (rc); } @@ -678,11 +693,18 @@ static int encode_unused_inet_addr(struct sockaddr *sa, char buf[ADDRBUFSZ]; int port = port_from_sockaddr(sa); + /* First, look for an exact match. Only look quickly unless we're + * desperate. If the socket is in use, we fail here. (This could get + * racy. Let's not worry about that for now.) + */ snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, present_sockaddr(sa, 0, buf, sizeof(buf))); if ((rc = unix_socket_status(sun, !desperatep)) == USED) return (-1); else if (rc == STALE) unlink(sun->sun_path); + /* Next, check the corresponding wildcard address, so as to avoid + * inadvertant collisions with listeners. Do this in the same way. + */ wildcard_address(sa->sa_family, &waddr.sa); port_to_sockaddr(&waddr.sa, port); snprintf(wsun.sun_path, sizeof(wsun.sun_path), "%s/%s", sockdir, @@ -690,6 +712,7 @@ static int encode_unused_inet_addr(struct sockaddr *sa, if ((rc = unix_socket_status(&wsun, !desperatep)) == USED) return (-1); else if (rc == STALE) unlink(wsun.sun_path); + /* All is well. */ return (0); } @@ -714,34 +737,60 @@ static int encode_inet_addr(struct sockaddr_un *sun, D( fprintf(stderr, "noip(%d): encode %s (%s)", getpid(), present_sockaddr(sa, 0, buf, sizeof(buf)), (f&ENCF_FRESH) ? "FRESH" : "EXISTING"); ) + + /* Start making the Unix-domain address. */ sun->sun_family = AF_UNIX; + if (port || !(f&ENCF_FRESH)) { + + /* Try the address as given. If it's in use, or we don't necessarily + * want an existing socket, then we're done. + */ snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, present_sockaddr(sa, 0, buf, sizeof(buf))); rc = unix_socket_status(sun, 0); if (rc == STALE) unlink(sun->sun_path); if (rc == USED || (f&ENCF_FRESH)) goto found; + + /* We're looking for a socket which already exists. Try the + * corresponding wildcard address. + */ wildcard_address(sa->sa_family, &addr.sa); port_to_sockaddr(&addr.sa, port); snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s", sockdir, present_sockaddr(&addr.sa, 0, buf, sizeof(buf))); if (unix_socket_status(sun, 0) == STALE) unlink(sun->sun_path); + } else { + /* We want a fresh new socket. */ + + /* Make a copy of the given address, because we're going to mangle it. */ copy_sockaddr(&addr.sa, sa); + + /* Try a few random-ish port numbers to see if any of them is spare. */ for (i = 0; i < 10; i++) { port_to_sockaddr(&addr.sa, randrange(minautoport, maxautoport)); if (!encode_unused_inet_addr(&addr.sa, sun, 0)) goto found; } + + /* Things must be getting tight. Work through all of the autoport range + * to see if we can find a spare one. The first time, just do it the + * quick way; if that doesn't work, then check harder for stale sockets. + */ for (desperatep = 0; desperatep < 2; desperatep++) { for (i = minautoport; i <= maxautoport; i++) { port_to_sockaddr(&addr.sa, i); if (!encode_unused_inet_addr(&addr.sa, sun, 0)) goto found; } } + + /* We failed to find any free ports. */ errno = EADDRINUSE; D( fprintf(stderr, " -- can't resolve\n"); ) return (-1); } + + /* Success. */ found: D( fprintf(stderr, " -> `%s'\n", sun->sun_path); ) return (0);