/* 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 "@(#)getsockopt.c 1.9 93/09/30 SMI" /* SVr4.0 1.5 */ /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sock.h" #pragma weak getsockopt = _getsockopt int _getsockopt(s, level, optname, optval, optlen) register int s; register int level; register int optname; register char *optval; register int *optlen; { register struct T_optmgmt_req *opt_req; register struct T_optmgmt_ack *opt_ack; register struct _si_user *siptr; register int size; register struct opthdr *opt; char *cbuf; int retlen; int rval; sigset_t mask; int didalloc = 0; if ((siptr = _s_checkfd(s)) == NULL) return (-1); MUTEX_LOCK_SIGMASK(&siptr->lock, mask); if (level == SOL_SOCKET && optname == SO_TYPE) { if (*optlen < sizeof (int)) { MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask); errno = EINVAL; return (-1); } if (siptr->udata.servtype == T_CLTS) *(int *)optval = SOCK_DGRAM; else *(int *)optval = SOCK_STREAM; *optlen = sizeof (int); MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask); return (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; } opt_req = (struct T_optmgmt_req *)cbuf; opt_req->PRIM_type = T_OPTMGMT_REQ; opt_req->OPT_length = sizeof (*opt) + *optlen; opt_req->OPT_offset = sizeof (*opt_req); opt_req->MGMT_flags = T_CHECK; size = sizeof (*opt_req) + opt_req->OPT_length; opt = (struct opthdr *)(cbuf + opt_req->OPT_offset); opt->level = level; opt->name = optname; opt->len = *optlen; do { rval = _s_do_ioctl(s, cbuf, size, TI_OPTMGMT, &retlen); } while (! rval && errno == EINTR); if (! rval) { goto err_out; } if (retlen < (sizeof (*opt_ack) + sizeof (*opt))) { errno = EPROTO; goto err_out; } opt_ack = (struct T_optmgmt_ack *)cbuf; opt = (struct opthdr *)(cbuf + opt_ack->OPT_offset); (void) memcpy(optval, (caddr_t)opt + sizeof (*opt), opt->len); *optlen = opt->len; if (didalloc) free(cbuf); else siptr->ctlbuf = cbuf; MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask); return (0); err_out: if (didalloc) free(cbuf); else siptr->ctlbuf = cbuf; MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask); return (-1); }