Import polipo--devel--0--base-0.
[polipo.git] / io.c
bloba9b6772dfe6e77d3e3b784af83209b6d2f616a3c
1 /*
2 Copyright (c) 2003 by Juliusz Chroboczek
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
23 #include "polipo.h"
25 void
26 preinitIo()
28 return;
31 void
32 initIo()
34 return;
37 FdEventHandlerPtr
38 do_stream(int operation, int fd, int offset, char *buf, int len,
39 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
40 void *data)
42 assert(len > offset || (operation & (IO_END | IO_IMMEDIATE)));
43 return schedule_stream(operation, fd, offset,
44 NULL, 0, buf, len, NULL, 0, NULL, 0, NULL,
45 handler, data);
48 FdEventHandlerPtr
49 do_stream_2(int operation, int fd, int offset,
50 char *buf, int len, char *buf2, int len2,
51 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
52 void *data)
54 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
55 return schedule_stream(operation, fd, offset,
56 NULL, 0, buf, len, buf2, len2, NULL, 0, NULL,
57 handler, data);
60 FdEventHandlerPtr
61 do_stream_3(int operation, int fd, int offset,
62 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
63 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
64 void *data)
66 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
67 return schedule_stream(operation, fd, offset,
68 NULL, 0, buf, len, buf2, len2, buf3, len3, NULL,
69 handler, data);
72 FdEventHandlerPtr
73 do_stream_h(int operation, int fd, int offset,
74 char *header, int hlen, char *buf, int len,
75 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
76 void *data)
78 assert(hlen + len > offset || (operation & (IO_END | IO_IMMEDIATE)));
79 return schedule_stream(operation, fd, offset,
80 header, hlen, buf, len, NULL, 0, NULL, 0, NULL,
81 handler, data);
84 FdEventHandlerPtr
85 do_stream_buf(int operation, int fd, int offset, char **buf_location, int len,
86 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
87 void *data)
89 assert((len > offset || (operation & (IO_END | IO_IMMEDIATE)))
90 && len <= CHUNK_SIZE);
91 return schedule_stream(operation, fd, offset,
92 NULL, 0, *buf_location, len,
93 NULL, 0, NULL, 0, buf_location,
94 handler, data);
97 static int
98 chunkHeaderLen(int i)
100 if(i <= 0)
101 return 0;
102 if(i < 0x10)
103 return 3;
104 else if(i < 0x100)
105 return 4;
106 else if(i < 0x1000)
107 return 5;
108 else if(i < 0x10000)
109 return 6;
110 else
111 abort();
114 static int
115 chunkHeader(char *buf, int buflen, int i)
117 int n;
118 if(i <= 0)
119 return 0;
120 n = snprintf(buf, buflen, "%x\r\n", i);
121 return n;
125 FdEventHandlerPtr
126 schedule_stream(int operation, int fd, int offset,
127 char *header, int hlen,
128 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
129 char **buf_location,
130 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
131 void *data)
133 StreamRequestRec request;
134 FdEventHandlerPtr event;
135 int done;
137 request.operation = operation;
138 request.fd = fd;
139 if(len3) {
140 assert(hlen == 0 && buf_location == NULL);
141 request.u.b.len3 = len3;
142 request.u.b.buf3 = buf3;
143 request.operation |= IO_BUF3;
144 } else if(buf_location) {
145 assert(hlen == 0);
146 request.u.l.buf_location = buf_location;
147 request.operation |= IO_BUF_LOCATION;
148 } else {
149 request.u.h.hlen = hlen;
150 request.u.h.header = header;
152 request.buf = buf;
153 request.len = len;
154 request.buf2 = buf2;
155 request.len2 = len2;
156 if((operation & IO_CHUNKED) ||
157 (!(request.operation & (IO_BUF3 | IO_BUF_LOCATION)) && hlen > 0)) {
158 assert(offset == 0);
159 request.offset = -hlen;
160 if(operation & IO_CHUNKED)
161 request.offset += -chunkHeaderLen(len + len2);
162 } else {
163 request.offset = offset;
165 request.handler = handler;
166 request.data = data;
167 event = makeFdEvent(fd,
168 (operation & IO_MASK) == IO_WRITE ?
169 POLLOUT : POLLIN,
170 do_scheduled_stream,
171 sizeof(StreamRequestRec), &request);
172 if(!event) {
173 done = (*handler)(-ENOMEM, NULL, &request);
174 assert(done);
175 return NULL;
178 if(!(operation & IO_NOTNOW)) {
179 done = event->handler(0, event);
180 if(done) {
181 free(event);
182 return NULL;
186 if(operation & IO_IMMEDIATE) {
187 assert(hlen == 0 && !(operation & IO_CHUNKED));
188 done = (*handler)(0, event, &request);
189 if(done) {
190 free(event);
191 return NULL;
194 event = registerFdEventHelper(event);
195 return event;
198 static const char *endChunkTrailer = "\r\n0\r\n\r\n";
201 do_scheduled_stream(int status, FdEventHandlerPtr event)
203 StreamRequestPtr request = (StreamRequestPtr)&event->data;
204 int rc, done, i;
205 struct iovec iov[6];
206 int chunk_header_len, chunk_trailer_len;
207 char chunk_header[10];
208 int len12 = request->len + request->len2;
209 int len123 =
210 request->len + request->len2 +
211 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
213 if(status) {
214 done = request->handler(status, event, request);
215 return done;
218 i = 0;
220 if(request->offset < 0) {
221 assert((request->operation & (IO_MASK | IO_BUF3 | IO_BUF_LOCATION)) ==
222 IO_WRITE);
223 if(request->operation & IO_CHUNKED) {
224 chunk_header_len = chunkHeaderLen(len123);
225 chunk_trailer_len = 2;
226 } else {
227 chunk_header_len = 0;
228 chunk_trailer_len = 0;
231 if(request->offset < -chunk_header_len) {
232 assert(request->offset >= -(request->u.h.hlen + chunk_header_len));
233 iov[i].iov_base = request->u.h.header;
234 iov[i].iov_len = -request->offset - chunk_header_len;
235 i++;
238 if(chunk_header_len > 0) {
239 chunkHeader(chunk_header, 10, len123);
240 if(request->offset < -chunk_header_len) {
241 iov[i].iov_base = chunk_header;
242 iov[i].iov_len = chunk_header_len;
243 } else {
244 iov[i].iov_base = chunk_header +
245 chunk_header_len + request->offset;
246 iov[i].iov_len = -request->offset;
248 i++;
252 if(request->len > 0) {
253 if(request->buf == NULL &&
254 (request->operation & IO_BUF_LOCATION)) {
255 assert(*request->u.l.buf_location == NULL);
256 request->buf = *request->u.l.buf_location = get_chunk();
257 if(request->buf == NULL) {
258 done = request->handler(-ENOMEM, event, request);
259 return done;
262 if(request->offset <= 0) {
263 iov[i].iov_base = request->buf;
264 iov[i].iov_len = request->len;
265 i++;
266 } else if(request->offset < request->len) {
267 iov[i].iov_base = request->buf + request->offset;
268 iov[i].iov_len = request->len - request->offset;
269 i++;
273 if(request->len2 > 0) {
274 if(request->offset <= request->len) {
275 iov[i].iov_base = request->buf2;
276 iov[i].iov_len = request->len2;
277 i++;
278 } else if(request->offset < request->len + request->len2) {
279 iov[i].iov_base = request->buf2 + request->offset - request->len;
280 iov[i].iov_len = request->len2 - request->offset + request->len;
281 i++;
285 if((request->operation & IO_BUF3) && request->u.b.len3 > 0) {
286 if(request->offset <= len12) {
287 iov[i].iov_base = request->u.b.buf3;
288 iov[i].iov_len = request->u.b.len3;
289 i++;
290 } else if(request->offset < len12 + request->u.b.len3) {
291 iov[i].iov_base = request->u.b.buf3 + request->offset - len12;
292 iov[i].iov_len = request->u.b.len3 - request->offset + len12;
293 i++;
297 if((request->operation & IO_CHUNKED)) {
298 int l;
299 const char *trailer;
300 if(request->operation & IO_END) {
301 if(len123 == 0) {
302 trailer = endChunkTrailer + 2;
303 l = 5;
304 } else {
305 trailer = endChunkTrailer;
306 l = 7;
308 } else {
309 trailer = endChunkTrailer;
310 l = 2;
313 if(request->offset <= len123) {
314 iov[i].iov_base = (char*)trailer;
315 iov[i].iov_len = l;
316 i++;
317 } else if(request->offset < len123 + l) {
318 iov[i].iov_base =
319 (char*)endChunkTrailer + request->offset - len123;
320 iov[i].iov_len = l - request->offset + len123;
321 i++;
325 assert(i > 0);
327 if((request->operation & IO_MASK) == IO_WRITE) {
328 if(i > 1)
329 rc = writev(request->fd, iov, i);
330 else
331 rc = write(request->fd, iov[0].iov_base, iov[0].iov_len);
332 } else {
333 if(i > 1)
334 rc = readv(request->fd, iov, i);
335 else
336 rc = read(request->fd, iov[0].iov_base, iov[0].iov_len);
339 if(rc > 0) {
340 request->offset += rc;
341 if(request->offset < 0) return 0;
342 done = request->handler(0, event, request);
343 return done;
344 } else if(rc == 0 || errno == EPIPE) {
345 done = request->handler(1, event, request);
346 } else if(errno == EAGAIN || errno == EINTR) {
347 return 0;
348 } else if(errno == EFAULT || errno == EBADF) {
349 abort();
350 } else {
351 done = request->handler(-errno, event, request);
353 assert(done);
354 return done;
358 streamRequestDone(StreamRequestPtr request)
360 int len123 =
361 request->len + request->len2 +
362 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
364 if(request->offset < 0)
365 return 0;
366 else if(request->offset < len123)
367 return 0;
368 else if(request->operation & IO_CHUNKED) {
369 if(request->operation & IO_END) {
370 if(request->offset < len123 + (len123 ? 7 : 5))
371 return 0;
372 } else {
373 if(request->offset < len123 + 2)
374 return 0;
378 return 1;
381 static int
382 serverSocket(int af)
384 int fd, rc;
385 if(af == 4) {
386 fd = socket(PF_INET, SOCK_STREAM, 0);
387 } else if(af == 6) {
388 #ifdef HAVE_IPv6
389 fd = socket(PF_INET6, SOCK_STREAM, 0);
390 #else
391 fd = -1;
392 errno = EAFNOSUPPORT;
393 #endif
394 } else {
395 abort();
398 if(fd >= 0) {
399 rc = setNonblocking(fd, 1);
400 if(rc < 0) {
401 int errno_save = errno;
402 close(fd);
403 errno = errno_save;
404 return -1;
407 return fd;
410 FdEventHandlerPtr
411 do_connect(AtomPtr addr, int index, int port,
412 int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr),
413 void *data)
415 ConnectRequestRec request;
416 FdEventHandlerPtr event;
417 int done, fd, af;
419 assert(addr->length > 0 && addr->string[0] == DNS_A);
420 assert(addr->length % sizeof(HostAddressRec) == 1);
422 if(index >= (addr->length - 1)/ sizeof(HostAddressRec))
423 index = 0;
425 request.firstindex = index;
426 request.port = port;
427 request.handler = handler;
428 request.data = data;
429 again:
430 af = addr->string[1 + index * sizeof(HostAddressRec)];
431 fd = serverSocket(af);
433 request.fd = fd;
434 request.af = af;
435 request.addr = addr;
436 request.index = index;
438 if(fd < 0) {
439 int n = (addr->length - 1) / sizeof(HostAddressRec);
440 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
441 if((index + 1) % n != request.firstindex) {
442 index = (index + 1) % n;
443 goto again;
446 do_log_error(L_ERROR, errno, "Couldn't create socket");
447 done = (*handler)(-errno, NULL, &request);
448 assert(done);
449 return NULL;
452 event = registerFdEvent(fd, POLLOUT,
453 do_scheduled_connect,
454 sizeof(ConnectRequestRec), &request);
455 if(event == NULL) {
456 done = (*handler)(-ENOMEM, NULL, &request);
457 assert(done);
458 return NULL;
461 done = event->handler(0, event);
462 if(done) {
463 unregisterFdEvent(event);
464 return NULL;
466 return event;
470 do_scheduled_connect(int status, FdEventHandlerPtr event)
472 ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
473 AtomPtr addr = request->addr;
474 int done;
475 int rc;
476 HostAddressPtr host;
477 struct sockaddr_in servaddr;
478 #ifdef HAVE_IPv6
479 struct sockaddr_in6 servaddr6;
480 #endif
482 assert(addr->length > 0 && addr->string[0] == DNS_A);
483 assert(addr->length % sizeof(HostAddressRec) == 1);
484 assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));
486 if(status) {
487 done = request->handler(status, event, request);
488 if(done) {
489 releaseAtom(addr);
490 request->addr = NULL;
491 return 1;
493 return 0;
496 again:
497 host = (HostAddressPtr)&addr->string[1 +
498 request->index *
499 sizeof(HostAddressRec)];
500 if(host->af != request->af) {
501 int newfd;
502 /* Ouch. Our socket has a different protocol than the host
503 address. */
504 close(request->fd);
505 newfd = serverSocket(host->af);
506 if(newfd < 0) {
507 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
508 int n = request->addr->length / sizeof(HostAddressRec);
509 if((request->index + 1) % n != request->firstindex) {
510 request->index = (request->index + 1) % n;
511 goto again;
514 request->fd = -1;
515 done = request->handler(-errno, event, request);
516 assert(done);
517 return 1;
519 if(newfd != request->fd) {
520 request->fd = dup2(newfd, request->fd);
521 close(newfd);
522 if(request->fd < 0) {
523 done = request->handler(-errno, event, request);
524 assert(done);
525 return 1;
528 request->af = host->af;
530 switch(host->af) {
531 case 4:
532 memset(&servaddr, 0, sizeof(servaddr));
533 servaddr.sin_family = AF_INET;
534 servaddr.sin_port = htons(request->port);
535 memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
536 rc = connect(request->fd,
537 (struct sockaddr*)&servaddr, sizeof(servaddr));
538 break;
539 case 6:
540 #ifdef HAVE_IPv6
541 memset(&servaddr6, 0, sizeof(servaddr6));
542 servaddr6.sin6_family = AF_INET6;
543 servaddr6.sin6_port = htons(request->port);
544 memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
545 rc = connect(request->fd,
546 (struct sockaddr*)&servaddr6, sizeof(servaddr6));
547 #else
548 rc = -1;
549 errno = EAFNOSUPPORT;
550 #endif
551 break;
552 default:
553 abort();
556 if(rc >= 0 || errno == EISCONN) {
557 done = request->handler(1, event, request);
558 assert(done);
559 releaseAtom(request->addr);
560 request->addr = NULL;
561 return 1;
564 if(errno == EINPROGRESS || errno == EINTR) {
565 return 0;
566 } else if(errno == EFAULT || errno == EBADF) {
567 abort();
568 } else {
569 int n = request->addr->length / sizeof(HostAddressRec);
570 if((request->index + 1) % n != request->firstindex) {
571 request->index = (request->index + 1) % n;
572 goto again;
574 done = request->handler(-errno, event, request);
575 assert(done);
576 releaseAtom(request->addr);
577 request->addr = NULL;
578 return 1;
582 FdEventHandlerPtr
583 do_accept(int fd,
584 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
585 void *data)
587 FdEventHandlerPtr event;
588 int done;
590 event = schedule_accept(fd, handler, data);
591 if(event == NULL) {
592 done = (*handler)(-ENOMEM, NULL, NULL);
593 assert(done);
596 /* But don't invoke it now - this will delay accept if under load. */
597 return event;
600 FdEventHandlerPtr
601 schedule_accept(int fd,
602 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
603 void *data)
605 FdEventHandlerPtr event;
606 AcceptRequestRec request;
607 int done;
609 request.fd = fd;
610 request.handler = handler;
611 request.data = data;
612 event = registerFdEvent(fd, POLLOUT|POLLIN,
613 do_scheduled_accept, sizeof(request), &request);
614 if(!event) {
615 done = (*handler)(-ENOMEM, NULL, NULL);
616 assert(done);
618 return event;
622 do_scheduled_accept(int status, FdEventHandlerPtr event)
624 AcceptRequestPtr request = (AcceptRequestPtr)&event->data;
625 int rc, done;
626 unsigned len;
627 struct sockaddr_in addr;
629 if(status) {
630 done = request->handler(status, event, request);
631 if(done) return done;
634 len = sizeof(struct sockaddr_in);
636 rc = accept(request->fd, (struct sockaddr*)&addr, &len);
638 if(rc >= 0)
639 done = request->handler(rc, event, request);
640 else
641 done = request->handler(-errno, event, request);
642 return done;
645 FdEventHandlerPtr
646 create_listener(char *address, int port,
647 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
648 void *data)
650 int fd, rc;
651 int one = 1;
652 int done;
653 struct sockaddr_in addr;
654 #ifdef HAVE_IPv6
655 int inet6 = 1;
656 struct sockaddr_in6 addr6;
657 #else
658 int inet6 = 0;
659 #endif
661 if(inet6 && address) {
662 struct in_addr buf;
663 rc = inet_aton(address, &buf);
664 if(rc == 1)
665 inet6 = 0;
667 fd = -1;
668 errno = EAFNOSUPPORT;
670 #ifdef HAVE_IPv6
671 if(inet6) {
672 fd = socket(PF_INET6, SOCK_STREAM, 0);
674 #endif
676 if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) {
677 inet6 = 0;
678 fd = socket(PF_INET, SOCK_STREAM, 0);
681 if(fd < 0) {
682 done = (*handler)(-errno, NULL, NULL);
683 assert(done);
684 return NULL;
687 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
688 if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR");
690 if(inet6) {
691 #ifdef HAVE_IPv6
692 memset(&addr6, 0, sizeof(addr6));
693 rc = inet_pton(AF_INET6, address, &addr6.sin6_addr);
694 if(rc != 1) {
695 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
696 assert(done);
697 return NULL;
699 addr6.sin6_family = AF_INET6;
700 addr6.sin6_port = htons(port);
701 rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
702 #else
703 rc = -1;
704 errno = EAFNOSUPPORT;
705 #endif
706 } else {
707 memset(&addr, 0, sizeof(addr));
708 rc = inet_aton(address, &addr.sin_addr);
709 if(rc != 1) {
710 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
711 assert(done);
712 return NULL;
714 addr.sin_family = AF_INET;
715 addr.sin_port = htons(port);
716 rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
719 if(rc < 0) {
720 do_log_error(L_ERROR, errno, "Couldn't bind");
721 close(fd);
722 done = (*handler)(-errno, NULL, NULL);
723 assert(done);
724 return NULL;
727 rc = setNonblocking(fd, 1);
728 if(rc < 0) {
729 do_log_error(L_ERROR, errno, "Couldn't set non blocking mode");
730 close(fd);
731 done = (*handler)(-errno, NULL, NULL);
732 assert(done);
733 return NULL;
736 rc = listen(fd, 32);
737 if(rc < 0) {
738 do_log_error(L_ERROR, errno, "Couldn't listen");
739 close(fd);
740 done = (*handler)(-errno, NULL, NULL);
741 assert(done);
742 return NULL;
745 return schedule_accept(fd, handler, data);
749 setNonblocking(int fd, int nonblocking)
751 int rc;
752 rc = fcntl(fd, F_GETFL, 0);
753 if(rc < 0)
754 return -1;
756 rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
757 if(rc < 0)
758 return -1;
760 return 0;
763 #ifndef SOL_TCP
764 /* BSD */
765 #define SOL_TCP IPPROTO_TCP
766 #endif
769 setNodelay(int fd, int nodelay)
771 int val = nodelay ? 1 : 0;
772 int rc;
773 rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
774 if(rc < 0)
775 return -1;
776 return 0;
779 typedef struct _LingeringClose {
780 int fd;
781 FdEventHandlerPtr handler;
782 TimeEventHandlerPtr timeout;
783 } LingeringCloseRec, *LingeringClosePtr;
785 static int
786 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
788 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
789 assert(l->timeout == event);
790 l->timeout = NULL;
791 if(l->handler)
792 pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
793 else {
794 close(l->fd);
795 free(l);
797 return 1;
800 static int
801 lingeringCloseHandler(int status, FdEventHandlerPtr event)
803 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
804 char buf[17];
805 int rc;
807 assert(l->handler == event);
809 l->handler = NULL;
810 if(status && status != -EDOGRACEFUL)
811 goto done;
813 rc = read(l->fd, &buf, 17);
814 if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
815 goto done;
817 /* The client is still sending data. Ignore it in order to let
818 TCP's flow control do its work. The timeout will close the
819 connection. */
820 return 1;
822 done:
823 if(l->timeout) {
824 cancelTimeEvent(l->timeout);
825 l->timeout = NULL;
827 close(l->fd);
828 free(l);
829 return 1;
833 lingeringClose(int fd)
835 int rc;
836 LingeringClosePtr l;
838 rc = shutdown(fd, 1);
839 if(rc < 0) {
840 if(errno != ENOTCONN) {
841 do_log_error(L_ERROR, errno, "Shutdown failed");
842 } else if(errno == EFAULT || errno == EBADF) {
843 abort();
845 close(fd);
846 return 1;
849 l = malloc(sizeof(LingeringCloseRec));
850 if(l == NULL)
851 goto fail;
852 l->fd = fd;
853 l->handler = NULL;
854 l->timeout = NULL;
856 l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
857 sizeof(LingeringClosePtr), &l);
858 if(l->timeout == NULL) {
859 free(l);
860 goto fail;
863 l->handler = registerFdEvent(fd, POLLIN,
864 lingeringCloseHandler,
865 sizeof(LingeringClosePtr), &l);
866 if(l->handler == NULL) {
867 do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
868 /* But don't close -- the timeout will do its work. */
870 return 1;
872 fail:
873 do_log(L_ERROR, "Couldn't schedule lingering close.\n");
874 close(fd);
875 return 1;
878 NetAddressPtr
879 parseNetAddress(AtomListPtr list)
881 NetAddressPtr nl;
882 int i, rc, rc6;
883 char buf[100];
884 struct in_addr ina;
885 #ifdef HAVE_IPv6
886 struct in6_addr ina6;
887 #endif
889 nl = malloc((list->length + 1) * sizeof(NetAddressRec));
890 if(nl == NULL) {
891 do_log(L_ERROR, "Couldn't allocate network list.\n");
892 return NULL;
895 for(i = 0; i < list->length; i++) {
896 int prefix;
897 char *s = list->list[i]->string, *p;
898 if(list->list[i]->length >= 100) {
899 do_log(L_ERROR, "Network name too long.\n");
900 goto fail;
902 p = memchr(s, '/', list->list[i]->length);
903 if(p) {
904 memcpy(buf, s, p - s);
905 buf[p - s] = '\0';
906 prefix = atol(p + 1);
907 } else {
908 prefix = -1;
909 strcpy(buf, list->list[i]->string);
912 rc = 0; rc6 = 0;
913 rc = inet_aton(buf, &ina);
914 #ifdef HAVE_IPv6
915 if(rc == 0) {
916 rc6 = inet_pton(AF_INET6, buf, &ina6);
918 #endif
919 if(rc == 0 && rc6 == 0) {
920 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
921 goto fail;
923 nl[i].prefix = prefix;
924 if(rc) {
925 nl[i].af = 4;
926 memcpy(nl[i].data, &ina, 4);
927 } else {
928 #ifdef HAVE_IPv6
929 nl[i].af = 6;
930 memcpy(nl[i].data, &ina6, 16);
931 #else
932 abort();
933 #endif
936 nl[i].af = 0;
937 return nl;
939 fail:
940 free(nl);
941 return NULL;
944 static int
945 bitmatch(const unsigned char *a, const unsigned char *b, int n)
947 if(n >= 8) {
948 if(memcmp(a, b, n / 8) != 0)
949 return 0;
952 if(n % 8 != 0) {
953 int mask = (~0) << (8 - n % 8);
954 if((a[n / 8] & mask) != (b[n / 8] & mask))
955 return 0;
958 return 1;
961 static int
962 match(int af, char *data, NetAddressPtr list)
964 int i;
965 #ifdef HAVE_IPv6
966 static const char v6mapped[] =
967 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
968 #endif
970 i = 0;
971 while(list[i].af != 0) {
972 if(af == 4 && list[i].af == 4) {
973 if(bitmatch(data, list[i].data,
974 list[i].prefix >= 0 ? list[i].prefix : 32))
975 return 1;
976 #ifdef HAVE_IPv6
977 } else if(af == 6 && list[i].af == 6) {
978 if(bitmatch(data, list[i].data,
979 list[i].prefix >= 0 ? list[i].prefix : 128))
980 return 1;
981 } else if(af == 6 && list[i].af == 4) {
982 if(bitmatch(data, v6mapped, 96)) {
983 if(bitmatch(data + 12, list[i].data,
984 list[i].prefix >= 0 ? list[i].prefix : 32))
985 return 1;
987 } else if(af == 4 && list[i].af == 6) {
988 if(bitmatch(list[i].data, v6mapped, 96)) {
989 if(bitmatch(data, list[i].data + 12,
990 list[i].prefix >= 96 ?
991 list[i].prefix - 96 : 32))
992 return 1;
994 #endif
995 } else {
996 abort();
998 i++;
1000 return 0;
1004 netAddressMatch(int fd, NetAddressPtr list)
1006 int rc;
1007 int len;
1008 struct sockaddr_in sain;
1009 #ifdef HAVE_IPv6
1010 struct sockaddr_in6 sain6;
1011 #endif
1013 len = sizeof(sain);
1014 rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1015 if(rc < 0) {
1016 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1017 return -1;
1020 if(sain.sin_family == AF_INET) {
1021 return match(4, (char*)&sain.sin_addr, list);
1022 #ifdef HAVE_IPv6
1023 } else if(sain.sin_family == AF_INET6) {
1024 len = sizeof(sain6);
1025 rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1026 if(rc < 0) {
1027 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1028 return -1;
1030 if(sain6.sin6_family != AF_INET6) {
1031 do_log(L_ERROR, "Inconsistent peer name");
1032 return -1;
1034 return match(6, (char*)&sain6.sin6_addr, list);
1035 #endif
1036 } else {
1037 do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1038 return -1;
1040 return 0;