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 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 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 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 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 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 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 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 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