Files
Arquivotheca.Solaris-2.5/lib/libsocket/socket/bind.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

362 lines
7.9 KiB
C
Executable File

/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
/* The copyright notice above does not evidence any */
/* actual or intended publication of such source code. */
#ident "@(#)bind.c 1.20 95/07/12 SMI" /* SVr4.0 1.9 */
/*
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
* PROPRIETARY NOTICE (Combined)
*
* This source code is unpublished proprietary information
* constituting, or derived under license from AT&T's UNIX(r) System V.
* In addition, portions of such source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*
*
*
* Copyright Notice
*
* Notice of copyright on this source code product does not indicate
* publication.
*
* (c) 1986,1987,1988.1989 Sun Microsystems, Inc
* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
* All rights reserved.
*
*/
#include "sockmt.h"
#include <sys/param.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stream.h>
#include <sys/ioctl.h>
#include <stropts.h>
#include <sys/tihdr.h>
#include <sys/timod.h>
#include <sys/socketvar.h>
#include <sys/socket.h>
#include <tiuser.h>
#include <sys/sockmod.h>
#include <signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <syslog.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "sock.h"
static int _unbind(struct _si_user *siptr);
#pragma weak bind = _bind
int
_bind(s, name, namelen)
register int s;
register struct sockaddr *name;
register int namelen;
{
register struct _si_user *siptr;
sigset_t mask;
int retval;
u_int family;
if ((siptr = _s_checkfd(s)) == NULL)
return (-1);
MUTEX_LOCK_SIGMASK(&siptr->lock, mask);
if (name == NULL || namelen == 0) {
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
errno = EINVAL;
return (-1);
}
if (siptr->udata.so_state & SS_ISBOUND) {
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
errno = EINVAL;
return (-1);
}
family = name->sa_family;
if (family == 0) {
/*
* Handle old applications that do not set the family
* in the bind call.
*/
family = siptr->udata.sockparams.sp_family;
name->sa_family = family;
}
/*
* In UNIX domain a bind address must be given.
*/
if (family == AF_UNIX) {
if (namelen <= sizeof (name->sa_family)) {
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
errno = EISDIR;
return (-1);
}
if (namelen > sizeof (struct sockaddr_un)) {
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
errno = EINVAL;
return (-1);
}
if (name->sa_data[0] == 0) {
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
errno = EINVAL;
return (-1);
}
}
retval = __bind(siptr, name, namelen, NULL, NULL);
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
return (retval);
}
int
__bind(siptr, name, namelen, raddr, raddrlen)
register struct _si_user *siptr;
register struct sockaddr *name;
register int namelen;
register char *raddr;
register int *raddrlen;
{
register char *buf;
register struct T_bind_req *bind_req;
register struct T_bind_ack *bind_ack;
register int size;
char *cbuf;
sigset_t procmask;
struct stat rstat;
struct bind_ux bind_ux;
int fflag;
int didalloc = 0;
if (siptr->udata.sockparams.sp_family == AF_UNIX) {
(void) memset((caddr_t)&bind_ux, 0, sizeof (bind_ux));
if (name == NULL) {
bind_ux.name.sun_family = AF_UNIX;
fflag = 0;
} else {
struct sockaddr_un *un;
int len;
un = (struct sockaddr_un *)name;
if (un->sun_family != AF_UNIX) {
errno = EINVAL;
return (-1);
}
if (namelen > sizeof (*un) ||
(len = _s_uxpathlen(un)) ==
sizeof (un->sun_path)) {
errno = EMSGSIZE;
return (-1);
}
un->sun_path[len] = 0; /* Null terminate */
/*
* We really have to bind to the actual vnode, so
* that renames will not cause a problem. First
* create the file and then get the dev/ino to
* bind to.
*/
if ((_ioctl(siptr->fd, _I_BIND_RSVD, un->sun_path) < 0) ||
#if defined(i386)
(_xstat(_STAT_VER, (caddr_t) un->sun_path,
&rstat) < 0)) {
#elif defined(sparc)
_stat((caddr_t)un->sun_path, &rstat) < 0) {
#else
#error Unknown architecture!
#endif
if (errno == EEXIST)
errno = EADDRINUSE;
return (-1);
}
bind_ux.extdev = rstat.st_dev;
bind_ux.extino = rstat.st_ino;
bind_ux.extsize = sizeof (struct ux_dev);
(void) memcpy((caddr_t)&bind_ux.name, (caddr_t)name,
namelen);
fflag = 1;
}
name = (struct sockaddr *)&bind_ux;
namelen = sizeof (bind_ux);
} else namelen = _s_min(namelen, siptr->udata.addrsize);
if (siptr->ctlbuf) {
cbuf = siptr->ctlbuf;
siptr->ctlbuf = NULL;
} else {
/*
* siptr->ctlbuf is in use
* allocate and free after use.
*/
if (_s_cbuf_alloc(siptr, &cbuf) < 0)
return (-1);
didalloc = 1;
}
buf = cbuf;
bind_req = (struct T_bind_req *)buf;
size = sizeof (*bind_req);
bind_req->PRIM_type = T_BIND_REQ;
bind_req->ADDR_length = name == NULL ? 0 : namelen;
bind_req->ADDR_offset = 0;
bind_req->CONIND_number = 0;
if (bind_req->ADDR_length) {
_s_aligned_copy(buf, bind_req->ADDR_length, size,
(caddr_t)name,
(int *)&bind_req->ADDR_offset);
size = bind_req->ADDR_offset + bind_req->ADDR_length;
}
_s_blockallsignals(&procmask);
if (!_s_do_ioctl(siptr->fd, buf, size, TI_BIND, NULL)) {
_s_restoresigmask(&procmask);
goto err_out;
}
_s_restoresigmask(&procmask);
bind_ack = (struct T_bind_ack *)buf;
buf += bind_ack->ADDR_offset;
/*
* Check that the address returned by the
* transport provider meets the criteria.
*/
errno = 0;
if (name != (struct sockaddr *)NULL) {
/*
* Some programs like inetd(1M) don't set the
* family field. So we use the family field that
* was passed in to the socket() call.
*/
switch (siptr->udata.sockparams.sp_family) {
case AF_INET: {
struct sockaddr_in *rname;
struct sockaddr_in *aname;
rname = (struct sockaddr_in *)buf;
aname = (struct sockaddr_in *)name;
if (aname->sin_port != 0 &&
aname->sin_port != rname->sin_port)
errno = EADDRINUSE;
if (aname->sin_addr.s_addr != INADDR_ANY &&
aname->sin_addr.s_addr != rname->sin_addr.s_addr)
errno = EADDRNOTAVAIL;
break;
}
case AF_UNIX:
if (fflag) {
register struct bind_ux *rbind_ux;
rbind_ux = (struct bind_ux *)buf;
if (rbind_ux->extdev != bind_ux.extdev ||
rbind_ux->extino != bind_ux.extino)
errno = EADDRINUSE;
}
break;
default:
if (bind_ack->ADDR_length != namelen)
errno = EADDRNOTAVAIL;
else if (memcmp((caddr_t)name, buf, namelen) != 0)
errno = EADDRNOTAVAIL;
}
}
if (errno) {
register int error;
error = errno; /* Save it */
(void) _unbind(siptr);
if (name && name->sa_family == AF_UNIX && fflag) {
(void) _ioctl(siptr->fd, _I_RELE_RSVD);
(void) unlink(name->sa_data);
}
errno = error;
goto err_out;
}
/*
* Copy back the bound address if requested.
*/
if (raddr != NULL)
*raddrlen = _s_cpaddr(siptr, raddr, *raddrlen,
buf, bind_ack->ADDR_length);
siptr->udata.so_state |= SS_ISBOUND;
if (didalloc)
free(cbuf);
else
siptr->ctlbuf = cbuf;
return (0);
err_out:
if (didalloc)
free(cbuf);
else
siptr->ctlbuf = cbuf;
return (-1);
}
static int
_unbind(siptr)
register struct _si_user *siptr;
{
sigset_t procmask;
char *cbuf;
int didalloc = 0;
if (siptr->ctlbuf) {
cbuf = siptr->ctlbuf;
siptr->ctlbuf = NULL;
} else {
/*
* siptr->ctlbuf is in use
* allocate and free after use.
*/
if (_s_cbuf_alloc(siptr, &cbuf) < 0)
return (-1);
didalloc = 1;
}
((struct T_unbind_req *)cbuf)->PRIM_type = T_UNBIND_REQ;
_s_blockallsignals(&procmask);
if (!_s_do_ioctl(siptr->fd, cbuf,
sizeof (struct T_unbind_req),
TI_UNBIND, NULL)) {
_s_restoresigmask(&procmask);
if (didalloc)
free(cbuf);
else
siptr->ctlbuf = cbuf;
return (-1);
}
_s_restoresigmask(&procmask);
siptr->udata.so_state &= ~SS_ISBOUND;
if (didalloc)
free(cbuf);
else
siptr->ctlbuf = cbuf;
return (0);
}