1*e6e30c83Schristos /*	$NetBSD: ev_connects.c,v 1.1.1.2 2012/09/09 16:08:00 christos Exp $	*/
2b5677b36Schristos 
3b5677b36Schristos /*
4b5677b36Schristos  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5b5677b36Schristos  * Copyright (c) 1995-1999 by Internet Software Consortium
6b5677b36Schristos  *
7b5677b36Schristos  * Permission to use, copy, modify, and distribute this software for any
8b5677b36Schristos  * purpose with or without fee is hereby granted, provided that the above
9b5677b36Schristos  * copyright notice and this permission notice appear in all copies.
10b5677b36Schristos  *
11b5677b36Schristos  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12b5677b36Schristos  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13b5677b36Schristos  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14b5677b36Schristos  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15b5677b36Schristos  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16b5677b36Schristos  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17b5677b36Schristos  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18b5677b36Schristos  */
19b5677b36Schristos 
20b5677b36Schristos /* ev_connects.c - implement asynch connect/accept for the eventlib
21b5677b36Schristos  * vix 16sep96 [initial]
22b5677b36Schristos  */
23b5677b36Schristos 
24b5677b36Schristos #if !defined(LINT) && !defined(CODECENTER)
25b5677b36Schristos static const char rcsid[] = "Id: ev_connects.c,v 1.8 2006/03/09 23:57:56 marka Exp ";
26b5677b36Schristos #endif
27b5677b36Schristos 
28b5677b36Schristos /* Import. */
29b5677b36Schristos 
30b5677b36Schristos #include "port_before.h"
31b5677b36Schristos #include "fd_setsize.h"
32b5677b36Schristos 
33b5677b36Schristos #include <sys/types.h>
34b5677b36Schristos #include <sys/socket.h>
35b5677b36Schristos #include <sys/ioctl.h>
36b5677b36Schristos 
37b5677b36Schristos #include <unistd.h>
38b5677b36Schristos 
39b5677b36Schristos #include <isc/eventlib.h>
40b5677b36Schristos #include <isc/assertions.h>
41b5677b36Schristos #include "eventlib_p.h"
42b5677b36Schristos 
43b5677b36Schristos #include "port_after.h"
44b5677b36Schristos 
45b5677b36Schristos /* Macros. */
46b5677b36Schristos 
47b5677b36Schristos #define GETXXXNAME(f, s, sa, len) ( \
48b5677b36Schristos 	(f((s), (&sa), (&len)) >= 0) ? 0 : \
49b5677b36Schristos 		(errno != EAFNOSUPPORT && errno != EOPNOTSUPP) ? -1 : ( \
50b5677b36Schristos 			memset(&(sa), 0, sizeof (sa)), \
51b5677b36Schristos 			(len) = sizeof (sa), \
52b5677b36Schristos 			(sa).sa_family = AF_UNIX, \
53b5677b36Schristos 			0 \
54b5677b36Schristos 		) \
55b5677b36Schristos 	)
56b5677b36Schristos 
57b5677b36Schristos /* Forward. */
58b5677b36Schristos 
59b5677b36Schristos static void	listener(evContext ctx, void *uap, int fd, int evmask);
60b5677b36Schristos static void	connector(evContext ctx, void *uap, int fd, int evmask);
61b5677b36Schristos 
62b5677b36Schristos /* Public. */
63b5677b36Schristos 
64b5677b36Schristos int
evListen(evContext opaqueCtx,int fd,int maxconn,evConnFunc func,void * uap,evConnID * id)65b5677b36Schristos evListen(evContext opaqueCtx, int fd, int maxconn,
66b5677b36Schristos 	 evConnFunc func, void *uap, evConnID *id)
67b5677b36Schristos {
68b5677b36Schristos 	evContext_p *ctx = opaqueCtx.opaque;
69b5677b36Schristos 	evConn *new;
70b5677b36Schristos 	int mode;
71b5677b36Schristos 
72b5677b36Schristos 	OKNEW(new);
73b5677b36Schristos 	new->flags = EV_CONN_LISTEN;
74b5677b36Schristos 	OKFREE(mode = fcntl(fd, F_GETFL, NULL), new);	/*%< side effect: validate fd. */
75b5677b36Schristos 	/*
76b5677b36Schristos 	 * Remember the nonblocking status.  We assume that either evSelectFD
77b5677b36Schristos 	 * has not been done to this fd, or that if it has then the caller
78b5677b36Schristos 	 * will evCancelConn before they evDeselectFD.  If our assumptions
79b5677b36Schristos 	 * are not met, then we might restore the old nonblocking status
80b5677b36Schristos 	 * incorrectly.
81b5677b36Schristos 	 */
82b5677b36Schristos 	if ((mode & PORT_NONBLOCK) == 0) {
83b5677b36Schristos #ifdef USE_FIONBIO_IOCTL
84b5677b36Schristos 		int on = 1;
85b5677b36Schristos 		OKFREE(ioctl(fd, FIONBIO, (char *)&on), new);
86b5677b36Schristos #else
87b5677b36Schristos 		OKFREE(fcntl(fd, F_SETFL, mode | PORT_NONBLOCK), new);
88b5677b36Schristos #endif
89b5677b36Schristos 		new->flags |= EV_CONN_BLOCK;
90b5677b36Schristos 	}
91b5677b36Schristos 	OKFREE(listen(fd, maxconn), new);
92b5677b36Schristos 	if (evSelectFD(opaqueCtx, fd, EV_READ, listener, new, &new->file) < 0){
93b5677b36Schristos 		int save = errno;
94b5677b36Schristos 
95b5677b36Schristos 		FREE(new);
96b5677b36Schristos 		errno = save;
97b5677b36Schristos 		return (-1);
98b5677b36Schristos 	}
99b5677b36Schristos 	new->flags |= EV_CONN_SELECTED;
100b5677b36Schristos 	new->func = func;
101b5677b36Schristos 	new->uap = uap;
102b5677b36Schristos 	new->fd = fd;
103b5677b36Schristos 	if (ctx->conns != NULL)
104b5677b36Schristos 		ctx->conns->prev = new;
105b5677b36Schristos 	new->prev = NULL;
106b5677b36Schristos 	new->next = ctx->conns;
107b5677b36Schristos 	ctx->conns = new;
108b5677b36Schristos 	if (id)
109b5677b36Schristos 		id->opaque = new;
110b5677b36Schristos 	return (0);
111b5677b36Schristos }
112b5677b36Schristos 
113b5677b36Schristos int
evConnect(evContext opaqueCtx,int fd,const void * ra,int ralen,evConnFunc func,void * uap,evConnID * id)114b5677b36Schristos evConnect(evContext opaqueCtx, int fd, const void *ra, int ralen,
115b5677b36Schristos 	  evConnFunc func, void *uap, evConnID *id)
116b5677b36Schristos {
117b5677b36Schristos 	evContext_p *ctx = opaqueCtx.opaque;
118b5677b36Schristos 	evConn *new;
119b5677b36Schristos 
120b5677b36Schristos 	OKNEW(new);
121b5677b36Schristos 	new->flags = 0;
122b5677b36Schristos 	/* Do the select() first to get the socket into nonblocking mode. */
123b5677b36Schristos 	if (evSelectFD(opaqueCtx, fd, EV_MASK_ALL,
124b5677b36Schristos 		       connector, new, &new->file) < 0) {
125b5677b36Schristos 		int save = errno;
126b5677b36Schristos 
127b5677b36Schristos 		FREE(new);
128b5677b36Schristos 		errno = save;
129b5677b36Schristos 		return (-1);
130b5677b36Schristos 	}
131b5677b36Schristos 	new->flags |= EV_CONN_SELECTED;
132b5677b36Schristos 	if (connect(fd, ra, ralen) < 0 &&
133b5677b36Schristos 	    errno != EWOULDBLOCK &&
134b5677b36Schristos 	    errno != EAGAIN &&
135b5677b36Schristos 	    errno != EINPROGRESS) {
136b5677b36Schristos 		int save = errno;
137b5677b36Schristos 
138b5677b36Schristos 		(void) evDeselectFD(opaqueCtx, new->file);
139b5677b36Schristos 		FREE(new);
140b5677b36Schristos 		errno = save;
141b5677b36Schristos 		return (-1);
142b5677b36Schristos 	}
143b5677b36Schristos 	/* No error, or EWOULDBLOCK.  select() tells when it's ready. */
144b5677b36Schristos 	new->func = func;
145b5677b36Schristos 	new->uap = uap;
146b5677b36Schristos 	new->fd = fd;
147b5677b36Schristos 	if (ctx->conns != NULL)
148b5677b36Schristos 		ctx->conns->prev = new;
149b5677b36Schristos 	new->prev = NULL;
150b5677b36Schristos 	new->next = ctx->conns;
151b5677b36Schristos 	ctx->conns = new;
152b5677b36Schristos 	if (id)
153b5677b36Schristos 		id->opaque = new;
154b5677b36Schristos 	return (0);
155b5677b36Schristos }
156b5677b36Schristos 
157b5677b36Schristos int
evCancelConn(evContext opaqueCtx,evConnID id)158b5677b36Schristos evCancelConn(evContext opaqueCtx, evConnID id) {
159b5677b36Schristos 	evContext_p *ctx = opaqueCtx.opaque;
160b5677b36Schristos 	evConn *this = id.opaque;
161b5677b36Schristos 	evAccept *acc, *nxtacc;
162b5677b36Schristos 	int mode;
163b5677b36Schristos 
164b5677b36Schristos 	if ((this->flags & EV_CONN_SELECTED) != 0)
165b5677b36Schristos 		(void) evDeselectFD(opaqueCtx, this->file);
166b5677b36Schristos 	if ((this->flags & EV_CONN_BLOCK) != 0) {
167b5677b36Schristos 		mode = fcntl(this->fd, F_GETFL, NULL);
168b5677b36Schristos 		if (mode == -1) {
169b5677b36Schristos 			if (errno != EBADF)
170b5677b36Schristos 				return (-1);
171b5677b36Schristos 		} else {
172b5677b36Schristos #ifdef USE_FIONBIO_IOCTL
173b5677b36Schristos 			int off = 0;
174b5677b36Schristos 			OK(ioctl(this->fd, FIONBIO, (char *)&off));
175b5677b36Schristos #else
176b5677b36Schristos 			OK(fcntl(this->fd, F_SETFL, mode & ~PORT_NONBLOCK));
177b5677b36Schristos #endif
178b5677b36Schristos 		}
179b5677b36Schristos 	}
180b5677b36Schristos 
181b5677b36Schristos 	/* Unlink from ctx->conns. */
182b5677b36Schristos 	if (this->prev != NULL)
183b5677b36Schristos 		this->prev->next = this->next;
184b5677b36Schristos 	else
185b5677b36Schristos 		ctx->conns = this->next;
186b5677b36Schristos 	if (this->next != NULL)
187b5677b36Schristos 		this->next->prev = this->prev;
188b5677b36Schristos 
189b5677b36Schristos 	/*
190b5677b36Schristos 	 * Remove `this' from the ctx->accepts list (zero or more times).
191b5677b36Schristos 	 */
192b5677b36Schristos 	for (acc = HEAD(ctx->accepts), nxtacc = NULL;
193b5677b36Schristos 	     acc != NULL;
194b5677b36Schristos 	     acc = nxtacc)
195b5677b36Schristos 	{
196b5677b36Schristos 		nxtacc = NEXT(acc, link);
197b5677b36Schristos 		if (acc->conn == this) {
198b5677b36Schristos 			UNLINK(ctx->accepts, acc, link);
199b5677b36Schristos 			close(acc->fd);
200b5677b36Schristos 			FREE(acc);
201b5677b36Schristos 		}
202b5677b36Schristos 	}
203b5677b36Schristos 
204b5677b36Schristos 	/* Wrap up and get out. */
205b5677b36Schristos 	FREE(this);
206b5677b36Schristos 	return (0);
207b5677b36Schristos }
208b5677b36Schristos 
evHold(evContext opaqueCtx,evConnID id)209b5677b36Schristos int evHold(evContext opaqueCtx, evConnID id) {
210b5677b36Schristos 	evConn *this = id.opaque;
211b5677b36Schristos 
212b5677b36Schristos 	if ((this->flags & EV_CONN_LISTEN) == 0) {
213b5677b36Schristos 		errno = EINVAL;
214b5677b36Schristos 		return (-1);
215b5677b36Schristos 	}
216b5677b36Schristos 	if ((this->flags & EV_CONN_SELECTED) == 0)
217b5677b36Schristos 		return (0);
218b5677b36Schristos 	this->flags &= ~EV_CONN_SELECTED;
219b5677b36Schristos 	return (evDeselectFD(opaqueCtx, this->file));
220b5677b36Schristos }
221b5677b36Schristos 
evUnhold(evContext opaqueCtx,evConnID id)222b5677b36Schristos int evUnhold(evContext opaqueCtx, evConnID id) {
223b5677b36Schristos 	evConn *this = id.opaque;
224b5677b36Schristos 	int ret;
225b5677b36Schristos 
226b5677b36Schristos 	if ((this->flags & EV_CONN_LISTEN) == 0) {
227b5677b36Schristos 		errno = EINVAL;
228b5677b36Schristos 		return (-1);
229b5677b36Schristos 	}
230b5677b36Schristos 	if ((this->flags & EV_CONN_SELECTED) != 0)
231b5677b36Schristos 		return (0);
232b5677b36Schristos 	ret = evSelectFD(opaqueCtx, this->fd, EV_READ, listener, this,
233b5677b36Schristos 			 &this->file);
234b5677b36Schristos 	if (ret == 0)
235b5677b36Schristos 		this->flags |= EV_CONN_SELECTED;
236b5677b36Schristos 	return (ret);
237b5677b36Schristos }
238b5677b36Schristos 
239b5677b36Schristos int
evTryAccept(evContext opaqueCtx,evConnID id,int * sys_errno)240b5677b36Schristos evTryAccept(evContext opaqueCtx, evConnID id, int *sys_errno) {
241b5677b36Schristos 	evContext_p *ctx = opaqueCtx.opaque;
242b5677b36Schristos 	evConn *conn = id.opaque;
243b5677b36Schristos 	evAccept *new;
244b5677b36Schristos 
245b5677b36Schristos 	if ((conn->flags & EV_CONN_LISTEN) == 0) {
246b5677b36Schristos 		errno = EINVAL;
247b5677b36Schristos 		return (-1);
248b5677b36Schristos 	}
249b5677b36Schristos 	OKNEW(new);
250b5677b36Schristos 	new->conn = conn;
251b5677b36Schristos 	new->ralen = sizeof new->ra;
252b5677b36Schristos 	new->fd = accept(conn->fd, &new->ra.sa, &new->ralen);
253b5677b36Schristos 	if (new->fd > ctx->highestFD) {
254b5677b36Schristos 		close(new->fd);
255b5677b36Schristos 		new->fd = -1;
256b5677b36Schristos 		new->ioErrno = ENOTSOCK;
257b5677b36Schristos 	}
258b5677b36Schristos 	if (new->fd >= 0) {
259b5677b36Schristos 		new->lalen = sizeof new->la;
260b5677b36Schristos 		if (GETXXXNAME(getsockname, new->fd, new->la.sa, new->lalen) < 0) {
261b5677b36Schristos 			new->ioErrno = errno;
262b5677b36Schristos 			(void) close(new->fd);
263b5677b36Schristos 			new->fd = -1;
264b5677b36Schristos 		} else
265b5677b36Schristos 			new->ioErrno = 0;
266b5677b36Schristos 	} else {
267b5677b36Schristos 		new->ioErrno = errno;
268b5677b36Schristos 		if (errno == EAGAIN || errno == EWOULDBLOCK) {
269b5677b36Schristos 			FREE(new);
270b5677b36Schristos 			return (-1);
271b5677b36Schristos 		}
272b5677b36Schristos 	}
273b5677b36Schristos 	INIT_LINK(new, link);
274b5677b36Schristos 	APPEND(ctx->accepts, new, link);
275b5677b36Schristos 	*sys_errno = new->ioErrno;
276b5677b36Schristos 	return (0);
277b5677b36Schristos }
278b5677b36Schristos 
279b5677b36Schristos /* Private. */
280b5677b36Schristos 
281b5677b36Schristos static void
listener(evContext opaqueCtx,void * uap,int fd,int evmask)282b5677b36Schristos listener(evContext opaqueCtx, void *uap, int fd, int evmask) {
283b5677b36Schristos 	evContext_p *ctx = opaqueCtx.opaque;
284b5677b36Schristos 	evConn *conn = uap;
285b5677b36Schristos 	union {
286b5677b36Schristos 		struct sockaddr    sa;
287b5677b36Schristos 		struct sockaddr_in in;
288b5677b36Schristos #ifndef NO_SOCKADDR_UN
289b5677b36Schristos 		struct sockaddr_un un;
290b5677b36Schristos #endif
291b5677b36Schristos 	} la, ra;
292b5677b36Schristos 	int new;
293b5677b36Schristos 	ISC_SOCKLEN_T lalen = 0, ralen;
294b5677b36Schristos 
295b5677b36Schristos 	REQUIRE((evmask & EV_READ) != 0);
296b5677b36Schristos 	ralen = sizeof ra;
297b5677b36Schristos 	new = accept(fd, &ra.sa, &ralen);
298b5677b36Schristos 	if (new > ctx->highestFD) {
299b5677b36Schristos 		close(new);
300b5677b36Schristos 		new = -1;
301b5677b36Schristos 		errno = ENOTSOCK;
302b5677b36Schristos 	}
303b5677b36Schristos 	if (new >= 0) {
304b5677b36Schristos 		lalen = sizeof la;
305b5677b36Schristos 		if (GETXXXNAME(getsockname, new, la.sa, lalen) < 0) {
306b5677b36Schristos 			int save = errno;
307b5677b36Schristos 
308b5677b36Schristos 			(void) close(new);
309b5677b36Schristos 			errno = save;
310b5677b36Schristos 			new = -1;
311b5677b36Schristos 		}
312b5677b36Schristos 	} else if (errno == EAGAIN || errno == EWOULDBLOCK)
313b5677b36Schristos 		return;
314b5677b36Schristos 	(*conn->func)(opaqueCtx, conn->uap, new, &la.sa, lalen, &ra.sa, ralen);
315b5677b36Schristos }
316b5677b36Schristos 
317b5677b36Schristos static void
connector(evContext opaqueCtx,void * uap,int fd,int evmask)318b5677b36Schristos connector(evContext opaqueCtx, void *uap, int fd, int evmask) {
319b5677b36Schristos 	evConn *conn = uap;
320b5677b36Schristos 	union {
321b5677b36Schristos 		struct sockaddr    sa;
322b5677b36Schristos 		struct sockaddr_in in;
323b5677b36Schristos #ifndef NO_SOCKADDR_UN
324b5677b36Schristos 		struct sockaddr_un un;
325b5677b36Schristos #endif
326b5677b36Schristos 	} la, ra;
327b5677b36Schristos 	ISC_SOCKLEN_T lalen, ralen;
328b5677b36Schristos #ifndef NETREAD_BROKEN
329b5677b36Schristos 	char buf[1];
330b5677b36Schristos #endif
331b5677b36Schristos 	void *conn_uap;
332b5677b36Schristos 	evConnFunc conn_func;
333b5677b36Schristos 	evConnID id;
334b5677b36Schristos 	int socket_errno = 0;
335b5677b36Schristos 	ISC_SOCKLEN_T optlen;
336b5677b36Schristos 
337b5677b36Schristos 	UNUSED(evmask);
338b5677b36Schristos 
339b5677b36Schristos 	lalen = sizeof la;
340b5677b36Schristos 	ralen = sizeof ra;
341b5677b36Schristos 	conn_uap = conn->uap;
342b5677b36Schristos 	conn_func = conn->func;
343b5677b36Schristos 	id.opaque = conn;
344b5677b36Schristos #ifdef SO_ERROR
345b5677b36Schristos 	optlen = sizeof socket_errno;
346b5677b36Schristos 	if (fd < 0 &&
347b5677b36Schristos 	    getsockopt(conn->fd, SOL_SOCKET, SO_ERROR, (char *)&socket_errno,
348b5677b36Schristos 		       &optlen) < 0)
349b5677b36Schristos 		socket_errno = errno;
350b5677b36Schristos 	else
351b5677b36Schristos 		errno = socket_errno;
352b5677b36Schristos #endif
353b5677b36Schristos 	if (evCancelConn(opaqueCtx, id) < 0 ||
354b5677b36Schristos 	    socket_errno ||
355b5677b36Schristos #ifdef NETREAD_BROKEN
356b5677b36Schristos 	    0 ||
357b5677b36Schristos #else
358b5677b36Schristos 	    read(fd, buf, 0) < 0 ||
359b5677b36Schristos #endif
360b5677b36Schristos 	    GETXXXNAME(getsockname, fd, la.sa, lalen) < 0 ||
361b5677b36Schristos 	    GETXXXNAME(getpeername, fd, ra.sa, ralen) < 0) {
362b5677b36Schristos 		int save = errno;
363b5677b36Schristos 
364b5677b36Schristos 		(void) close(fd);	/*%< XXX closing caller's fd */
365b5677b36Schristos 		errno = save;
366b5677b36Schristos 		fd = -1;
367b5677b36Schristos 	}
368b5677b36Schristos 	(*conn_func)(opaqueCtx, conn_uap, fd, &la.sa, lalen, &ra.sa, ralen);
369b5677b36Schristos }
370b5677b36Schristos 
371b5677b36Schristos /*! \file */
372