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