10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
30Sstevel@tonic-gate * Copyright (c) 1995-1999 by Internet Software Consortium
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate *
9*11038SRao.Shoaib@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate */
170Sstevel@tonic-gate
180Sstevel@tonic-gate /* ev_connects.c - implement asynch connect/accept for the eventlib
190Sstevel@tonic-gate * vix 16sep96 [initial]
200Sstevel@tonic-gate */
210Sstevel@tonic-gate
220Sstevel@tonic-gate #if !defined(LINT) && !defined(CODECENTER)
23*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: ev_connects.c,v 1.8 2006/03/09 23:57:56 marka Exp $";
240Sstevel@tonic-gate #endif
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Import. */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include "port_before.h"
290Sstevel@tonic-gate #include "fd_setsize.h"
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <sys/types.h>
320Sstevel@tonic-gate #include <sys/socket.h>
330Sstevel@tonic-gate #include <sys/ioctl.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include <unistd.h>
360Sstevel@tonic-gate
370Sstevel@tonic-gate #include <isc/eventlib.h>
380Sstevel@tonic-gate #include <isc/assertions.h>
390Sstevel@tonic-gate #include "eventlib_p.h"
400Sstevel@tonic-gate
410Sstevel@tonic-gate #include "port_after.h"
420Sstevel@tonic-gate
430Sstevel@tonic-gate /* Macros. */
440Sstevel@tonic-gate
450Sstevel@tonic-gate #define GETXXXNAME(f, s, sa, len) ( \
460Sstevel@tonic-gate (f((s), (&sa), (&len)) >= 0) ? 0 : \
470Sstevel@tonic-gate (errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
480Sstevel@tonic-gate memset(&(sa), 0, sizeof (sa)), \
490Sstevel@tonic-gate (len) = sizeof (sa), \
500Sstevel@tonic-gate (sa).sa_family = AF_UNIX, \
510Sstevel@tonic-gate 0 \
520Sstevel@tonic-gate ) \
530Sstevel@tonic-gate )
540Sstevel@tonic-gate
550Sstevel@tonic-gate /* Forward. */
560Sstevel@tonic-gate
570Sstevel@tonic-gate static void listener(evContext ctx, void *uap, int fd, int evmask);
580Sstevel@tonic-gate static void connector(evContext ctx, void *uap, int fd, int evmask);
590Sstevel@tonic-gate
600Sstevel@tonic-gate /* Public. */
610Sstevel@tonic-gate
620Sstevel@tonic-gate int
evListen(evContext opaqueCtx,int fd,int maxconn,evConnFunc func,void * uap,evConnID * id)630Sstevel@tonic-gate evListen(evContext opaqueCtx, int fd, int maxconn,
640Sstevel@tonic-gate evConnFunc func, void *uap, evConnID *id)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque;
670Sstevel@tonic-gate evConn *new;
680Sstevel@tonic-gate int mode;
690Sstevel@tonic-gate
700Sstevel@tonic-gate OKNEW(new);
710Sstevel@tonic-gate new->flags = EV_CONN_LISTEN;
72*11038SRao.Shoaib@Sun.COM OKFREE(mode = fcntl(fd, F_GETFL, NULL), new); /*%< side effect: validate fd. */
730Sstevel@tonic-gate /*
740Sstevel@tonic-gate * Remember the nonblocking status. We assume that either evSelectFD
750Sstevel@tonic-gate * has not been done to this fd, or that if it has then the caller
760Sstevel@tonic-gate * will evCancelConn before they evDeselectFD. If our assumptions
770Sstevel@tonic-gate * are not met, then we might restore the old nonblocking status
780Sstevel@tonic-gate * incorrectly.
790Sstevel@tonic-gate */
800Sstevel@tonic-gate if ((mode & PORT_NONBLOCK) == 0) {
810Sstevel@tonic-gate #ifdef USE_FIONBIO_IOCTL
820Sstevel@tonic-gate int on = 1;
83*11038SRao.Shoaib@Sun.COM OKFREE(ioctl(fd, FIONBIO, (char *)&on), new);
840Sstevel@tonic-gate #else
85*11038SRao.Shoaib@Sun.COM OKFREE(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK), new);
860Sstevel@tonic-gate #endif
870Sstevel@tonic-gate new->flags |= EV_CONN_BLOCK;
880Sstevel@tonic-gate }
89*11038SRao.Shoaib@Sun.COM OKFREE(listen(fd, maxconn), new);
900Sstevel@tonic-gate if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){
910Sstevel@tonic-gate int save = errno;
920Sstevel@tonic-gate
930Sstevel@tonic-gate FREE(new);
940Sstevel@tonic-gate errno = save;
950Sstevel@tonic-gate return (-1);
960Sstevel@tonic-gate }
970Sstevel@tonic-gate new->flags |= EV_CONN_SELECTED;
980Sstevel@tonic-gate new->func = func;
990Sstevel@tonic-gate new->uap = uap;
1000Sstevel@tonic-gate new->fd = fd;
1010Sstevel@tonic-gate if (ctx->conns != NULL)
1020Sstevel@tonic-gate ctx->conns->prev = new;
1030Sstevel@tonic-gate new->prev = NULL;
1040Sstevel@tonic-gate new->next = ctx->conns;
1050Sstevel@tonic-gate ctx->conns = new;
1060Sstevel@tonic-gate if (id)
1070Sstevel@tonic-gate id->opaque = new;
1080Sstevel@tonic-gate return (0);
1090Sstevel@tonic-gate }
1100Sstevel@tonic-gate
1110Sstevel@tonic-gate int
evConnect(evContext opaqueCtx,int fd,const void * ra,int ralen,evConnFunc func,void * uap,evConnID * id)1120Sstevel@tonic-gate evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen,
1130Sstevel@tonic-gate evConnFunc func, void *uap, evConnID *id)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque;
1160Sstevel@tonic-gate evConn *new;
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate OKNEW(new);
1190Sstevel@tonic-gate new->flags = 0;
1200Sstevel@tonic-gate /* Do the select() first to get the socket into nonblocking mode. */
1210Sstevel@tonic-gate if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL,
1220Sstevel@tonic-gate connector, new, &new->file) < 0) {
1230Sstevel@tonic-gate int save = errno;
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate FREE(new);
1260Sstevel@tonic-gate errno = save;
1270Sstevel@tonic-gate return (-1);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate new->flags |= EV_CONN_SELECTED;
1300Sstevel@tonic-gate if (connect(fd, ra, ralen) < 0 &&
1310Sstevel@tonic-gate errno != EWOULDBLOCK &&
1320Sstevel@tonic-gate errno != EAGAIN &&
1330Sstevel@tonic-gate errno != EINPROGRESS) {
1340Sstevel@tonic-gate int save = errno;
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate (void) evDeselectFD(opaqueCtx, new->file);
1370Sstevel@tonic-gate FREE(new);
1380Sstevel@tonic-gate errno = save;
1390Sstevel@tonic-gate return (-1);
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate /* No error, or EWOULDBLOCK. select() tells when it's ready. */
1420Sstevel@tonic-gate new->func = func;
1430Sstevel@tonic-gate new->uap = uap;
1440Sstevel@tonic-gate new->fd = fd;
1450Sstevel@tonic-gate if (ctx->conns != NULL)
1460Sstevel@tonic-gate ctx->conns->prev = new;
1470Sstevel@tonic-gate new->prev = NULL;
1480Sstevel@tonic-gate new->next = ctx->conns;
1490Sstevel@tonic-gate ctx->conns = new;
1500Sstevel@tonic-gate if (id)
1510Sstevel@tonic-gate id->opaque = new;
1520Sstevel@tonic-gate return (0);
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate int
evCancelConn(evContext opaqueCtx,evConnID id)1560Sstevel@tonic-gate evCancelConn(evContext opaqueCtx, evConnID id) {
1570Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque;
1580Sstevel@tonic-gate evConn *this = id.opaque;
1590Sstevel@tonic-gate evAccept *acc, *nxtacc;
1600Sstevel@tonic-gate int mode;
1610Sstevel@tonic-gate
1620Sstevel@tonic-gate if ((this->flags & EV_CONN_SELECTED) != 0)
1630Sstevel@tonic-gate (void) evDeselectFD(opaqueCtx, this->file);
1640Sstevel@tonic-gate if ((this->flags & EV_CONN_BLOCK) != 0) {
1650Sstevel@tonic-gate mode = fcntl(this->fd, F_GETFL, NULL);
1660Sstevel@tonic-gate if (mode == -1) {
1670Sstevel@tonic-gate if (errno != EBADF)
1680Sstevel@tonic-gate return (-1);
1690Sstevel@tonic-gate } else {
1700Sstevel@tonic-gate #ifdef USE_FIONBIO_IOCTL
171*11038SRao.Shoaib@Sun.COM int off = 0;
172*11038SRao.Shoaib@Sun.COM OK(ioctl(this->fd, FIONBIO, (char *)&off));
1730Sstevel@tonic-gate #else
174*11038SRao.Shoaib@Sun.COM OK(fcntl(this->fd, F_SETFL, mode & ~PORT_NONBLOCK));
1750Sstevel@tonic-gate #endif
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate }
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* Unlink from ctx->conns. */
1800Sstevel@tonic-gate if (this->prev != NULL)
1810Sstevel@tonic-gate this->prev->next = this->next;
1820Sstevel@tonic-gate else
1830Sstevel@tonic-gate ctx->conns = this->next;
1840Sstevel@tonic-gate if (this->next != NULL)
1850Sstevel@tonic-gate this->next->prev = this->prev;
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate /*
1880Sstevel@tonic-gate * Remove `this' from the ctx->accepts list (zero or more times).
1890Sstevel@tonic-gate */
1900Sstevel@tonic-gate for (acc = HEAD(ctx->accepts), nxtacc = NULL;
1910Sstevel@tonic-gate acc != NULL;
1920Sstevel@tonic-gate acc = nxtacc)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate nxtacc = NEXT(acc, link);
1950Sstevel@tonic-gate if (acc->conn == this) {
1960Sstevel@tonic-gate UNLINK(ctx->accepts, acc, link);
1970Sstevel@tonic-gate close(acc->fd);
1980Sstevel@tonic-gate FREE(acc);
1990Sstevel@tonic-gate }
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate /* Wrap up and get out. */
2030Sstevel@tonic-gate FREE(this);
2040Sstevel@tonic-gate return (0);
2050Sstevel@tonic-gate }
2060Sstevel@tonic-gate
evHold(evContext opaqueCtx,evConnID id)2070Sstevel@tonic-gate int evHold(evContext opaqueCtx, evConnID id) {
2080Sstevel@tonic-gate evConn *this = id.opaque;
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate if ((this->flags & EV_CONN_LISTEN) == 0) {
2110Sstevel@tonic-gate errno = EINVAL;
2120Sstevel@tonic-gate return (-1);
2130Sstevel@tonic-gate }
2140Sstevel@tonic-gate if ((this->flags & EV_CONN_SELECTED) == 0)
2150Sstevel@tonic-gate return (0);
2160Sstevel@tonic-gate this->flags &= ~EV_CONN_SELECTED;
2170Sstevel@tonic-gate return (evDeselectFD(opaqueCtx, this->file));
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate
evUnhold(evContext opaqueCtx,evConnID id)2200Sstevel@tonic-gate int evUnhold(evContext opaqueCtx, evConnID id) {
2210Sstevel@tonic-gate evConn *this = id.opaque;
2220Sstevel@tonic-gate int ret;
2230Sstevel@tonic-gate
2240Sstevel@tonic-gate if ((this->flags & EV_CONN_LISTEN) == 0) {
2250Sstevel@tonic-gate errno = EINVAL;
2260Sstevel@tonic-gate return (-1);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate if ((this->flags & EV_CONN_SELECTED) != 0)
2290Sstevel@tonic-gate return (0);
2300Sstevel@tonic-gate ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this,
2310Sstevel@tonic-gate &this->file);
2320Sstevel@tonic-gate if (ret == 0)
2330Sstevel@tonic-gate this->flags |= EV_CONN_SELECTED;
2340Sstevel@tonic-gate return (ret);
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate
2370Sstevel@tonic-gate int
evTryAccept(evContext opaqueCtx,evConnID id,int * sys_errno)2380Sstevel@tonic-gate evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
2390Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque;
2400Sstevel@tonic-gate evConn *conn = id.opaque;
2410Sstevel@tonic-gate evAccept *new;
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate if ((conn->flags & EV_CONN_LISTEN) == 0) {
2440Sstevel@tonic-gate errno = EINVAL;
2450Sstevel@tonic-gate return (-1);
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate OKNEW(new);
2480Sstevel@tonic-gate new->conn = conn;
2490Sstevel@tonic-gate new->ralen = sizeof new->ra;
2500Sstevel@tonic-gate new->fd = accept(conn->fd, &new->ra.sa, &new->ralen);
2510Sstevel@tonic-gate if (new->fd > ctx->highestFD) {
2520Sstevel@tonic-gate close(new->fd);
2530Sstevel@tonic-gate new->fd = -1;
2540Sstevel@tonic-gate new->ioErrno = ENOTSOCK;
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate if (new->fd >= 0) {
2570Sstevel@tonic-gate new->lalen = sizeof new->la;
2580Sstevel@tonic-gate if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) {
2590Sstevel@tonic-gate new->ioErrno = errno;
2600Sstevel@tonic-gate (void) close(new->fd);
2610Sstevel@tonic-gate new->fd = -1;
2620Sstevel@tonic-gate } else
2630Sstevel@tonic-gate new->ioErrno = 0;
2640Sstevel@tonic-gate } else {
2650Sstevel@tonic-gate new->ioErrno = errno;
2660Sstevel@tonic-gate if (errno == EAGAIN || errno == EWOULDBLOCK) {
2670Sstevel@tonic-gate FREE(new);
2680Sstevel@tonic-gate return (-1);
2690Sstevel@tonic-gate }
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate INIT_LINK(new, link);
2720Sstevel@tonic-gate APPEND(ctx->accepts, new, link);
2730Sstevel@tonic-gate *sys_errno = new->ioErrno;
2740Sstevel@tonic-gate return (0);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate /* Private. */
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate static void
listener(evContext opaqueCtx,void * uap,int fd,int evmask)2800Sstevel@tonic-gate listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
2810Sstevel@tonic-gate evContext_p *ctx = opaqueCtx.opaque;
2820Sstevel@tonic-gate evConn *conn = uap;
2830Sstevel@tonic-gate union {
2840Sstevel@tonic-gate struct sockaddr sa;
2850Sstevel@tonic-gate struct sockaddr_in in;
2860Sstevel@tonic-gate #ifndef NO_SOCKADDR_UN
2870Sstevel@tonic-gate struct sockaddr_un un;
2880Sstevel@tonic-gate #endif
2890Sstevel@tonic-gate } la, ra;
2900Sstevel@tonic-gate int new;
2910Sstevel@tonic-gate ISC_SOCKLEN_T lalen = 0, ralen;
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate REQUIRE((evmask & EV_READ) != 0);
2940Sstevel@tonic-gate ralen = sizeof ra;
2950Sstevel@tonic-gate new = accept(fd, &ra.sa, &ralen);
2960Sstevel@tonic-gate if (new > ctx->highestFD) {
2970Sstevel@tonic-gate close(new);
2980Sstevel@tonic-gate new = -1;
2990Sstevel@tonic-gate errno = ENOTSOCK;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate if (new >= 0) {
3020Sstevel@tonic-gate lalen = sizeof la;
3030Sstevel@tonic-gate if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) {
3040Sstevel@tonic-gate int save = errno;
3050Sstevel@tonic-gate
3060Sstevel@tonic-gate (void) close(new);
3070Sstevel@tonic-gate errno = save;
3080Sstevel@tonic-gate new = -1;
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate } else if (errno == EAGAIN || errno == EWOULDBLOCK)
3110Sstevel@tonic-gate return;
3120Sstevel@tonic-gate (*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen);
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate
3150Sstevel@tonic-gate static void
connector(evContext opaqueCtx,void * uap,int fd,int evmask)3160Sstevel@tonic-gate connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
3170Sstevel@tonic-gate evConn *conn = uap;
3180Sstevel@tonic-gate union {
3190Sstevel@tonic-gate struct sockaddr sa;
3200Sstevel@tonic-gate struct sockaddr_in in;
3210Sstevel@tonic-gate #ifndef NO_SOCKADDR_UN
3220Sstevel@tonic-gate struct sockaddr_un un;
3230Sstevel@tonic-gate #endif
3240Sstevel@tonic-gate } la, ra;
3250Sstevel@tonic-gate ISC_SOCKLEN_T lalen, ralen;
326*11038SRao.Shoaib@Sun.COM #ifndef NETREAD_BROKEN
3270Sstevel@tonic-gate char buf[1];
328*11038SRao.Shoaib@Sun.COM #endif
3290Sstevel@tonic-gate void *conn_uap;
3300Sstevel@tonic-gate evConnFunc conn_func;
3310Sstevel@tonic-gate evConnID id;
3320Sstevel@tonic-gate int socket_errno = 0;
3330Sstevel@tonic-gate ISC_SOCKLEN_T optlen;
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate UNUSED(evmask);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate lalen = sizeof la;
3380Sstevel@tonic-gate ralen = sizeof ra;
3390Sstevel@tonic-gate conn_uap = conn->uap;
3400Sstevel@tonic-gate conn_func = conn->func;
3410Sstevel@tonic-gate id.opaque = conn;
3420Sstevel@tonic-gate #ifdef SO_ERROR
3430Sstevel@tonic-gate optlen = sizeof socket_errno;
3440Sstevel@tonic-gate if (fd < 0 &&
3450Sstevel@tonic-gate getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno,
3460Sstevel@tonic-gate &optlen) < 0)
3470Sstevel@tonic-gate socket_errno = errno;
3480Sstevel@tonic-gate else
3490Sstevel@tonic-gate errno = socket_errno;
3500Sstevel@tonic-gate #endif
3510Sstevel@tonic-gate if (evCancelConn(opaqueCtx, id) < 0 ||
3520Sstevel@tonic-gate socket_errno ||
3530Sstevel@tonic-gate #ifdef NETREAD_BROKEN
3540Sstevel@tonic-gate 0 ||
3550Sstevel@tonic-gate #else
3560Sstevel@tonic-gate read(fd, buf, 0) < 0 ||
3570Sstevel@tonic-gate #endif
3580Sstevel@tonic-gate GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 ||
3590Sstevel@tonic-gate GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) {
3600Sstevel@tonic-gate int save = errno;
3610Sstevel@tonic-gate
362*11038SRao.Shoaib@Sun.COM (void) close(fd); /*%< XXX closing caller's fd */
3630Sstevel@tonic-gate errno = save;
3640Sstevel@tonic-gate fd = -1;
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate (*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen);
3670Sstevel@tonic-gate }
368*11038SRao.Shoaib@Sun.COM
369*11038SRao.Shoaib@Sun.COM /*! \file */
370