diff --git a/lib/libc/rpc/bindresvport.3 b/lib/libc/rpc/bindresvport.3 index dc94dec06413..d83761324a2e 100644 --- a/lib/libc/rpc/bindresvport.3 +++ b/lib/libc/rpc/bindresvport.3 @@ -1,5 +1,5 @@ .\" @(#)bindresvport.3n 2.2 88/08/02 4.0 RPCSRC; from 1.7 88/03/14 SMI -.\" $NetBSD: bindresvport.3,v 1.3 1997/07/01 06:28:22 mikel Exp $ +.\" $NetBSD: bindresvport.3,v 1.4 1998/01/14 11:04:17 lukem Exp $ .\" .Dd November 22, 1987 .Dt BINDRESVPORT 3 @@ -11,7 +11,7 @@ .Fd #include .Fd #include .Ft int -.Fn bindresvport "int sd" "struct sockaddr_in **sin" +.Fn bindresvport "int sd" "struct sockaddr_in *sin" .Sh DESCRIPTION .Fn bindresvport is used to bind a socket descriptor to a privileged @@ -23,5 +23,60 @@ otherwise -1 is returned and .Va errno set to reflect the cause of the error. .Pp +If +.Fa sin +is a pointer to a +.Ft "struct sockaddr_in" +then the appropriate fields in the structure should be defined. +If +.Fa sin.sin_port +is +.Sq 0 +then an anonymous port (in the range 600-1023) will be +chosen, and if +.Xr bind 2 +is successful, the +.Fa sin.sin_port +will be updated to contain the allocated port. +.Pp +If +.Fa sin +is the +.Dv NULL +pointer, +an anonymous port will be allocated (as above). +However, there is no way for +.Fn bindresvport +to return the allocated port in this case. +.Pp Only root can bind to a privileged port; this call will fail for any other users. +.Sh RETURN VALUES +If the bind is successful, a 0 value is returned. +A return value of -1 indicates an error, which is +further specified in the global +.Va errno . +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EPFNOSUPPORT +If +.Fa sin +was supplied, and +.Fa sin.sin_family +isn't +.Dv AF_INET . +.El +.Pp +.Fn bindresvport +may also fail and set +.Va errno +for any of the errors specified for the calls +.Xr bind 2 , +.Xr getsockopt 2 , +or +.Xr setsockopt 2 . +.Sh SEE ALSO +.Xr bind 2 , +.Xr getsockopt 2 , +.Xr setsockopt 2 , +.Xr ip 4 . diff --git a/lib/libc/rpc/bindresvport.c b/lib/libc/rpc/bindresvport.c index b3ad2cec3362..85a6ac6d5877 100644 --- a/lib/libc/rpc/bindresvport.c +++ b/lib/libc/rpc/bindresvport.c @@ -1,4 +1,4 @@ -/* $NetBSD: bindresvport.c,v 1.8 1997/07/21 14:08:21 jtc Exp $ */ +/* $NetBSD: bindresvport.c,v 1.9 1998/01/14 11:04:18 lukem Exp $ */ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for @@ -35,7 +35,7 @@ static char *sccsid = "@(#)bindresvport.c 1.8 88/02/08 SMI"; static char *sccsid = "@(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC"; #else -__RCSID("$NetBSD: bindresvport.c,v 1.8 1997/07/21 14:08:21 jtc Exp $"); +__RCSID("$NetBSD: bindresvport.c,v 1.9 1998/01/14 11:04:18 lukem Exp $"); #endif #endif @@ -64,36 +64,50 @@ bindresvport(sd, sin) int sd; struct sockaddr_in *sin; { - int res; - static short port; + int res, old; struct sockaddr_in myaddr; - int i; + int sinlen = sizeof(struct sockaddr_in); -#define STARTPORT 600 -#define ENDPORT (IPPORT_RESERVED - 1) -#define NPORTS (ENDPORT - STARTPORT + 1) - - if (sin == (struct sockaddr_in *)0) { + if (sin == NULL) { sin = &myaddr; - memset(sin, 0, sizeof (*sin)); - sin->sin_len = sizeof(struct sockaddr_in); + memset(sin, 0, sinlen); + sin->sin_len = sinlen; sin->sin_family = AF_INET; } else if (sin->sin_family != AF_INET) { errno = EPFNOSUPPORT; return (-1); } - if (port == 0) { - port = (getpid() % NPORTS) + STARTPORT; + + if (sin->sin_port == 0) { + int on, oldlen = sizeof(old); + + res = getsockopt(sd, IPPROTO_IP, IP_PORTRANGE, &old, &oldlen); + if (res < 0) + return(res); + on = IP_PORTRANGE_LOW; + res = setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, &on, sizeof(on)); + if (res < 0) + return(res); } - res = -1; - errno = EADDRINUSE; - for (i = 0; i < NPORTS && res < 0 && errno == EADDRINUSE; i++) { - sin->sin_port = htons(port++); - if (port > ENDPORT) { - port = STARTPORT; + + res = bind(sd, (struct sockaddr *)sin, sinlen); + + if (sin->sin_port == 0) { + int saved_errno = errno; + + if (res < 0) { + if (setsockopt(sd, IPPROTO_IP, IP_PORTRANGE, + &old, sizeof(old)) < 0) + errno = saved_errno; + return (res); + } + + if (sin != &myaddr) { /* What did the kernel assign? */ + if (getsockname(sd, (struct sockaddr *)sin, &sinlen) + < 0) + errno = saved_errno; + return (res); } - res = bind(sd, - (struct sockaddr *)sin, sizeof(struct sockaddr_in)); } return (res); }