[patch] rresvport_af(3) uses setsockopt(SO_REUSEADDR)
Andrey Zonov
andrey.zonov at gmail.com
Wed Nov 24 18:38:25 UTC 2010
Hi,
I've made the patch for rresvport_af(3) and rcmd_af(3) which makes
possible to use more connections for rsh/rshd.
I've also reviewed freebsd src tree and I think these changes in libc do
not break any existing applications.
Can anybody look at the patch?
--
Andrey Zonov
-------------- next part --------------
Index: libexec/rshd/rshd.c
===================================================================
--- libexec/rshd/rshd.c (revision 215508)
+++ libexec/rshd/rshd.c (working copy)
@@ -278,11 +278,6 @@
(void) alarm(0);
if (port != 0) {
int lport = IPPORT_RESERVED - 1;
- s = rresvport_af(&lport, af);
- if (s < 0) {
- syslog(LOG_ERR, "can't get stderr port: %m");
- exit(1);
- }
if (port >= IPPORT_RESERVED ||
port < IPPORT_RESERVED/2) {
syslog(LOG_NOTICE|LOG_AUTH,
@@ -291,10 +286,31 @@
port);
exit(1);
}
- *((in_port_t *)&fromp->sa_data) = htons(port);
- if (connect(s, fromp, fromp->sa_len) < 0) {
- syslog(LOG_INFO, "connect second port %d: %m", port);
- exit(1);
+ for ( ;; ) {
+ s = rresvport_af(&lport, af);
+ if (s < 0) {
+ if (errno == EADDRINUSE ||
+ errno == EADDRNOTAVAIL) {
+ lport--;
+ continue;
+ }
+ if (errno == EAGAIN)
+ syslog(LOG_ERR, "socket: all ports in use");
+ else
+ syslog(LOG_ERR, "can't get stderr port: %m");
+ exit(1);
+ }
+ *((in_port_t *)&fromp->sa_data) = htons(port);
+ if (connect(s, fromp, fromp->sa_len) < 0) {
+ if (errno == EADDRINUSE) {
+ lport--;
+ close(s);
+ continue;
+ }
+ syslog(LOG_INFO, "connect second port %d: %m", port);
+ exit(1);
+ }
+ break;
}
}
@@ -535,11 +551,11 @@
char c;
do {
+ if (cnt-- == 0)
+ rshd_errx(1, "%s too long", error);
if (read(STDIN_FILENO, &c, 1) != 1)
exit(1);
*buf++ = c;
- if (--cnt == 0)
- rshd_errx(1, "%s too long", error);
} while (c != 0);
}
Index: lib/libc/net/rcmd.c
===================================================================
--- lib/libc/net/rcmd.c (revision 215508)
+++ lib/libc/net/rcmd.c (working copy)
@@ -152,6 +152,11 @@
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
s = rresvport_af(&lport, ai->ai_family);
if (s < 0) {
+ if (errno == EADDRINUSE ||
+ errno == EADDRNOTAVAIL) {
+ lport--;
+ continue;
+ }
if (errno != EAGAIN && ai->ai_next) {
ai = ai->ai_next;
continue;
@@ -212,17 +217,34 @@
fprintf(stderr, "Trying %s...\n", paddr);
}
}
- lport--;
+ lport = IPPORT_RESERVED - 1;
if (fd2p == 0) {
_write(s, "", 1);
lport = 0;
} else {
- int s2 = rresvport_af(&lport, ai->ai_family), s3;
+ int s2, s3;
socklen_t len = ai->ai_addrlen;
int nfds;
- if (s2 < 0)
- goto bad;
+ for ( ;; ) {
+ s2 = rresvport_af(&lport, ai->ai_family);
+ if (s2 < 0) {
+ if (errno == EADDRINUSE ||
+ errno == EADDRNOTAVAIL) {
+ lport--;
+ continue;
+ }
+ if (errno == EAGAIN)
+ (void)fprintf(stderr,
+ "rcmd: socket2: All ports in use\n");
+ else
+ (void)fprintf(stderr, "rcmd: socket2: %s\n",
+ strerror(errno));
+ goto bad;
+ }
+ break;
+ }
+
_listen(s2, 1);
(void)snprintf(num, sizeof(num), "%d", lport);
if (_write(s, num, strlen(num)+1) != strlen(num)+1) {
@@ -366,6 +388,27 @@
return (-1);
}
#endif
+ if (*alport && *alport < IPPORT_RESERVED - 1) {
+ if (*alport < IPPORT_RESERVED / 2) {
+ (void)_close(s);
+ errno = EAGAIN;
+ return (-1);
+ }
+ int reuse = 1;
+ if (_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
+ (void)_close(s);
+ return (-1);
+ }
+
+ *sport = htons((u_short)*alport);
+ if (_bind(s, (struct sockaddr *)&ss, ((struct sockaddr *)&ss)->sa_len) < 0) {
+ (void)_close(s);
+ return (-1);
+ }
+ *alport = (int)ntohs(*sport);
+ return (s);
+ }
+
*sport = 0;
if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
(void)_close(s);
More information about the freebsd-hackers
mailing list