* use setsockopt(IP_PORTRANGE_LOW) instead of looping through the

address range (from freebsd).
* enhance the man page to be a bit more useful.
This commit is contained in:
lukem 1998-01-14 11:04:17 +00:00
parent 910a3d4cc4
commit bba0660678
2 changed files with 93 additions and 24 deletions

View File

@ -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 <sys/types.h>
.Fd #include <netinet/in.h>
.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 .

View File

@ -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);
}