Use chunks throughout the disk cache code.
[polipo.git] / io.c
blob5de636cca1d732de2a75844ccd5a7e8877f2d290
1 /*
2 Copyright (c) 2003-2006 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 #ifdef HAVE_WINSOCK
29 /* Load the winsock dll */
30 WSADATA wsaData;
31 WORD wVersionRequested = MAKEWORD(2, 2);
32 int err = WSAStartup( wVersionRequested, &wsaData );
33 if (err != 0) {
34 do_log_error(L_ERROR, err, "Couldn't load winsock dll");
35 exit(-1);
37 #endif
38 return;
41 void
42 initIo()
44 return;
47 FdEventHandlerPtr
48 do_stream(int operation, int fd, int offset, char *buf, int len,
49 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
50 void *data)
52 assert(len > offset || (operation & (IO_END | IO_IMMEDIATE)));
53 return schedule_stream(operation, fd, offset,
54 NULL, 0, buf, len, NULL, 0, NULL, 0, NULL,
55 handler, data);
58 FdEventHandlerPtr
59 do_stream_2(int operation, int fd, int offset,
60 char *buf, int len, char *buf2, int len2,
61 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
62 void *data)
64 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
65 return schedule_stream(operation, fd, offset,
66 NULL, 0, buf, len, buf2, len2, NULL, 0, NULL,
67 handler, data);
70 FdEventHandlerPtr
71 do_stream_3(int operation, int fd, int offset,
72 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
73 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
74 void *data)
76 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
77 return schedule_stream(operation, fd, offset,
78 NULL, 0, buf, len, buf2, len2, buf3, len3, NULL,
79 handler, data);
82 FdEventHandlerPtr
83 do_stream_h(int operation, int fd, int offset,
84 char *header, int hlen, char *buf, int len,
85 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
86 void *data)
88 assert(hlen + len > offset || (operation & (IO_END | IO_IMMEDIATE)));
89 return schedule_stream(operation, fd, offset,
90 header, hlen, buf, len, NULL, 0, NULL, 0, NULL,
91 handler, data);
94 FdEventHandlerPtr
95 do_stream_buf(int operation, int fd, int offset, char **buf_location, int len,
96 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
97 void *data)
99 assert((len > offset || (operation & (IO_END | IO_IMMEDIATE)))
100 && len <= CHUNK_SIZE);
101 return schedule_stream(operation, fd, offset,
102 NULL, 0, *buf_location, len,
103 NULL, 0, NULL, 0, buf_location,
104 handler, data);
107 static int
108 chunkHeaderLen(int i)
110 if(i <= 0)
111 return 0;
112 if(i < 0x10)
113 return 3;
114 else if(i < 0x100)
115 return 4;
116 else if(i < 0x1000)
117 return 5;
118 else if(i < 0x10000)
119 return 6;
120 else
121 abort();
124 static int
125 chunkHeader(char *buf, int buflen, int i)
127 int n;
128 if(i <= 0)
129 return 0;
130 n = snprintf(buf, buflen, "%x\r\n", i);
131 return n;
135 FdEventHandlerPtr
136 schedule_stream(int operation, int fd, int offset,
137 char *header, int hlen,
138 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
139 char **buf_location,
140 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
141 void *data)
143 StreamRequestRec request;
144 FdEventHandlerPtr event;
145 int done;
147 request.operation = operation;
148 request.fd = fd;
149 if(len3) {
150 assert(hlen == 0 && buf_location == NULL);
151 request.u.b.len3 = len3;
152 request.u.b.buf3 = buf3;
153 request.operation |= IO_BUF3;
154 } else if(buf_location) {
155 assert(hlen == 0);
156 request.u.l.buf_location = buf_location;
157 request.operation |= IO_BUF_LOCATION;
158 } else {
159 request.u.h.hlen = hlen;
160 request.u.h.header = header;
162 request.buf = buf;
163 request.len = len;
164 request.buf2 = buf2;
165 request.len2 = len2;
166 if((operation & IO_CHUNKED) ||
167 (!(request.operation & (IO_BUF3 | IO_BUF_LOCATION)) && hlen > 0)) {
168 assert(offset == 0);
169 request.offset = -hlen;
170 if(operation & IO_CHUNKED)
171 request.offset += -chunkHeaderLen(len + len2);
172 } else {
173 request.offset = offset;
175 request.handler = handler;
176 request.data = data;
177 event = makeFdEvent(fd,
178 (operation & IO_MASK) == IO_WRITE ?
179 POLLOUT : POLLIN,
180 do_scheduled_stream,
181 sizeof(StreamRequestRec), &request);
182 if(!event) {
183 done = (*handler)(-ENOMEM, NULL, &request);
184 assert(done);
185 return NULL;
188 if(!(operation & IO_NOTNOW)) {
189 done = event->handler(0, event);
190 if(done) {
191 free(event);
192 return NULL;
196 if(operation & IO_IMMEDIATE) {
197 assert(hlen == 0 && !(operation & IO_CHUNKED));
198 done = (*handler)(0, event, &request);
199 if(done) {
200 free(event);
201 return NULL;
204 event = registerFdEventHelper(event);
205 return event;
208 static const char *endChunkTrailer = "\r\n0\r\n\r\n";
211 do_scheduled_stream(int status, FdEventHandlerPtr event)
213 StreamRequestPtr request = (StreamRequestPtr)&event->data;
214 int rc, done, i;
215 struct iovec iov[6];
216 int chunk_header_len, chunk_trailer_len;
217 char chunk_header[10];
218 int len12 = request->len + request->len2;
219 int len123 =
220 request->len + request->len2 +
221 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
223 if(status) {
224 done = request->handler(status, event, request);
225 return done;
228 i = 0;
230 if(request->offset < 0) {
231 assert((request->operation & (IO_MASK | IO_BUF3 | IO_BUF_LOCATION)) ==
232 IO_WRITE);
233 if(request->operation & IO_CHUNKED) {
234 chunk_header_len = chunkHeaderLen(len123);
235 chunk_trailer_len = 2;
236 } else {
237 chunk_header_len = 0;
238 chunk_trailer_len = 0;
241 if(request->offset < -chunk_header_len) {
242 assert(request->offset >= -(request->u.h.hlen + chunk_header_len));
243 iov[i].iov_base = request->u.h.header;
244 iov[i].iov_len = -request->offset - chunk_header_len;
245 i++;
248 if(chunk_header_len > 0) {
249 chunkHeader(chunk_header, 10, len123);
250 if(request->offset < -chunk_header_len) {
251 iov[i].iov_base = chunk_header;
252 iov[i].iov_len = chunk_header_len;
253 } else {
254 iov[i].iov_base = chunk_header +
255 chunk_header_len + request->offset;
256 iov[i].iov_len = -request->offset;
258 i++;
262 if(request->len > 0) {
263 if(request->buf == NULL &&
264 (request->operation & IO_BUF_LOCATION)) {
265 assert(*request->u.l.buf_location == NULL);
266 request->buf = *request->u.l.buf_location = get_chunk();
267 if(request->buf == NULL) {
268 done = request->handler(-ENOMEM, event, request);
269 return done;
272 if(request->offset <= 0) {
273 iov[i].iov_base = request->buf;
274 iov[i].iov_len = request->len;
275 i++;
276 } else if(request->offset < request->len) {
277 iov[i].iov_base = request->buf + request->offset;
278 iov[i].iov_len = request->len - request->offset;
279 i++;
283 if(request->len2 > 0) {
284 if(request->offset <= request->len) {
285 iov[i].iov_base = request->buf2;
286 iov[i].iov_len = request->len2;
287 i++;
288 } else if(request->offset < request->len + request->len2) {
289 iov[i].iov_base = request->buf2 + request->offset - request->len;
290 iov[i].iov_len = request->len2 - request->offset + request->len;
291 i++;
295 if((request->operation & IO_BUF3) && request->u.b.len3 > 0) {
296 if(request->offset <= len12) {
297 iov[i].iov_base = request->u.b.buf3;
298 iov[i].iov_len = request->u.b.len3;
299 i++;
300 } else if(request->offset < len12 + request->u.b.len3) {
301 iov[i].iov_base = request->u.b.buf3 + request->offset - len12;
302 iov[i].iov_len = request->u.b.len3 - request->offset + len12;
303 i++;
307 if((request->operation & IO_CHUNKED)) {
308 int l;
309 const char *trailer;
310 if(request->operation & IO_END) {
311 if(len123 == 0) {
312 trailer = endChunkTrailer + 2;
313 l = 5;
314 } else {
315 trailer = endChunkTrailer;
316 l = 7;
318 } else {
319 trailer = endChunkTrailer;
320 l = 2;
323 if(request->offset <= len123) {
324 iov[i].iov_base = (char*)trailer;
325 iov[i].iov_len = l;
326 i++;
327 } else if(request->offset < len123 + l) {
328 iov[i].iov_base =
329 (char*)endChunkTrailer + request->offset - len123;
330 iov[i].iov_len = l - request->offset + len123;
331 i++;
335 assert(i > 0);
337 if((request->operation & IO_MASK) == IO_WRITE) {
338 if(i > 1)
339 rc = WRITEV(request->fd, iov, i);
340 else
341 rc = WRITE(request->fd, iov[0].iov_base, iov[0].iov_len);
342 } else {
343 if(i > 1)
344 rc = READV(request->fd, iov, i);
345 else
346 rc = READ(request->fd, iov[0].iov_base, iov[0].iov_len);
349 if(rc > 0) {
350 request->offset += rc;
351 if(request->offset < 0) return 0;
352 done = request->handler(0, event, request);
353 return done;
354 } else if(rc == 0 || errno == EPIPE) {
355 done = request->handler(1, event, request);
356 } else if(errno == EAGAIN || errno == EINTR) {
357 return 0;
358 } else if(errno == EFAULT || errno == EBADF) {
359 abort();
360 } else {
361 done = request->handler(-errno, event, request);
363 assert(done);
364 return done;
368 streamRequestDone(StreamRequestPtr request)
370 int len123 =
371 request->len + request->len2 +
372 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
374 if(request->offset < 0)
375 return 0;
376 else if(request->offset < len123)
377 return 0;
378 else if(request->operation & IO_CHUNKED) {
379 if(request->operation & IO_END) {
380 if(request->offset < len123 + (len123 ? 7 : 5))
381 return 0;
382 } else {
383 if(request->offset < len123 + 2)
384 return 0;
388 return 1;
391 static int
392 serverSocket(int af)
394 int fd, rc;
395 if(af == 4) {
396 fd = socket(PF_INET, SOCK_STREAM, 0);
397 } else if(af == 6) {
398 #ifdef HAVE_IPv6
399 fd = socket(PF_INET6, SOCK_STREAM, 0);
400 #else
401 fd = -1;
402 errno = EAFNOSUPPORT;
403 #endif
404 } else {
405 abort();
408 if(fd >= 0) {
409 rc = setNonblocking(fd, 1);
410 if(rc < 0) {
411 int errno_save = errno;
412 CLOSE(fd);
413 errno = errno_save;
414 return -1;
417 return fd;
420 FdEventHandlerPtr
421 do_connect(AtomPtr addr, int index, int port,
422 int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr),
423 void *data)
425 ConnectRequestRec request;
426 FdEventHandlerPtr event;
427 int done, fd, af;
429 assert(addr->length > 0 && addr->string[0] == DNS_A);
430 assert(addr->length % sizeof(HostAddressRec) == 1);
432 if(index >= (addr->length - 1)/ sizeof(HostAddressRec))
433 index = 0;
435 request.firstindex = index;
436 request.port = port;
437 request.handler = handler;
438 request.data = data;
439 again:
440 af = addr->string[1 + index * sizeof(HostAddressRec)];
441 fd = serverSocket(af);
443 request.fd = fd;
444 request.af = af;
445 request.addr = addr;
446 request.index = index;
448 if(fd < 0) {
449 int n = (addr->length - 1) / sizeof(HostAddressRec);
450 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
451 if((index + 1) % n != request.firstindex) {
452 index = (index + 1) % n;
453 goto again;
456 do_log_error(L_ERROR, errno, "Couldn't create socket");
457 done = (*handler)(-errno, NULL, &request);
458 assert(done);
459 return NULL;
462 /* POLLIN is apparently needed on Windows */
463 event = registerFdEvent(fd, POLLIN | POLLOUT,
464 do_scheduled_connect,
465 sizeof(ConnectRequestRec), &request);
466 if(event == NULL) {
467 done = (*handler)(-ENOMEM, NULL, &request);
468 assert(done);
469 return NULL;
472 done = event->handler(0, event);
473 if(done) {
474 unregisterFdEvent(event);
475 return NULL;
477 return event;
481 do_scheduled_connect(int status, FdEventHandlerPtr event)
483 ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
484 AtomPtr addr = request->addr;
485 int done;
486 int rc;
487 HostAddressPtr host;
488 struct sockaddr_in servaddr;
489 #ifdef HAVE_IPv6
490 struct sockaddr_in6 servaddr6;
491 #endif
493 assert(addr->length > 0 && addr->string[0] == DNS_A);
494 assert(addr->length % sizeof(HostAddressRec) == 1);
495 assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));
497 if(status) {
498 done = request->handler(status, event, request);
499 if(done) {
500 releaseAtom(addr);
501 request->addr = NULL;
502 return 1;
504 return 0;
507 again:
508 host = (HostAddressPtr)&addr->string[1 +
509 request->index *
510 sizeof(HostAddressRec)];
511 if(host->af != request->af) {
512 int newfd;
513 /* Ouch. Our socket has a different protocol than the host
514 address. */
515 CLOSE(request->fd);
516 newfd = serverSocket(host->af);
517 if(newfd < 0) {
518 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
519 int n = request->addr->length / sizeof(HostAddressRec);
520 if((request->index + 1) % n != request->firstindex) {
521 request->index = (request->index + 1) % n;
522 goto again;
525 request->fd = -1;
526 done = request->handler(-errno, event, request);
527 assert(done);
528 return 1;
530 if(newfd != request->fd) {
531 request->fd = dup2(newfd, request->fd);
532 CLOSE(newfd);
533 if(request->fd < 0) {
534 done = request->handler(-errno, event, request);
535 assert(done);
536 return 1;
539 request->af = host->af;
541 switch(host->af) {
542 case 4:
543 memset(&servaddr, 0, sizeof(servaddr));
544 servaddr.sin_family = AF_INET;
545 servaddr.sin_port = htons(request->port);
546 memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
547 rc = connect(request->fd,
548 (struct sockaddr*)&servaddr, sizeof(servaddr));
549 break;
550 case 6:
551 #ifdef HAVE_IPv6
552 memset(&servaddr6, 0, sizeof(servaddr6));
553 servaddr6.sin6_family = AF_INET6;
554 servaddr6.sin6_port = htons(request->port);
555 memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
556 rc = connect(request->fd,
557 (struct sockaddr*)&servaddr6, sizeof(servaddr6));
558 #else
559 rc = -1;
560 errno = EAFNOSUPPORT;
561 #endif
562 break;
563 default:
564 abort();
567 if(rc >= 0 || errno == EISCONN) {
568 done = request->handler(1, event, request);
569 assert(done);
570 releaseAtom(request->addr);
571 request->addr = NULL;
572 return 1;
575 if(errno == EINPROGRESS || errno == EINTR) {
576 return 0;
577 } else if(errno == EFAULT || errno == EBADF) {
578 abort();
579 } else {
580 int n = request->addr->length / sizeof(HostAddressRec);
581 if((request->index + 1) % n != request->firstindex) {
582 request->index = (request->index + 1) % n;
583 goto again;
585 done = request->handler(-errno, event, request);
586 assert(done);
587 releaseAtom(request->addr);
588 request->addr = NULL;
589 return 1;
593 FdEventHandlerPtr
594 do_accept(int fd,
595 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
596 void *data)
598 FdEventHandlerPtr event;
599 int done;
601 event = schedule_accept(fd, handler, data);
602 if(event == NULL) {
603 done = (*handler)(-ENOMEM, NULL, NULL);
604 assert(done);
607 /* But don't invoke it now - this will delay accept if under load. */
608 return event;
611 FdEventHandlerPtr
612 schedule_accept(int fd,
613 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
614 void *data)
616 FdEventHandlerPtr event;
617 AcceptRequestRec request;
618 int done;
620 request.fd = fd;
621 request.handler = handler;
622 request.data = data;
623 event = registerFdEvent(fd, POLLOUT|POLLIN,
624 do_scheduled_accept, sizeof(request), &request);
625 if(!event) {
626 done = (*handler)(-ENOMEM, NULL, NULL);
627 assert(done);
629 return event;
633 do_scheduled_accept(int status, FdEventHandlerPtr event)
635 AcceptRequestPtr request = (AcceptRequestPtr)&event->data;
636 int rc, done;
637 unsigned len;
638 struct sockaddr_in addr;
640 if(status) {
641 done = request->handler(status, event, request);
642 if(done) return done;
645 len = sizeof(struct sockaddr_in);
647 rc = accept(request->fd, (struct sockaddr*)&addr, &len);
649 if(rc >= 0)
650 done = request->handler(rc, event, request);
651 else
652 done = request->handler(-errno, event, request);
653 return done;
656 FdEventHandlerPtr
657 create_listener(char *address, int port,
658 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
659 void *data)
661 int fd, rc;
662 int one = 1;
663 int done;
664 struct sockaddr_in addr;
665 #ifdef HAVE_IPv6
666 int inet6 = 1;
667 struct sockaddr_in6 addr6;
668 #else
669 int inet6 = 0;
670 #endif
672 if(inet6 && address) {
673 struct in_addr buf;
674 rc = inet_aton(address, &buf);
675 if(rc == 1)
676 inet6 = 0;
678 fd = -1;
679 errno = EAFNOSUPPORT;
681 #ifdef HAVE_IPv6
682 if(inet6) {
683 fd = socket(PF_INET6, SOCK_STREAM, 0);
685 #endif
687 if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) {
688 inet6 = 0;
689 fd = socket(PF_INET, SOCK_STREAM, 0);
692 if(fd < 0) {
693 done = (*handler)(-errno, NULL, NULL);
694 assert(done);
695 return NULL;
698 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
699 if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR");
701 if(inet6) {
702 #ifdef HAVE_IPv6
703 rc = setV6only(fd, 0);
704 if(rc < 0)
705 /* Reportedly OpenBSD returns an error for that. So only
706 log it as a debugging message. */
707 do_log_error(D_CLIENT_CONN, errno, "Couldn't reset IPV6_V6ONLY");
709 memset(&addr6, 0, sizeof(addr6));
710 rc = inet_pton(AF_INET6, address, &addr6.sin6_addr);
711 if(rc != 1) {
712 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
713 assert(done);
714 return NULL;
716 addr6.sin6_family = AF_INET6;
717 addr6.sin6_port = htons(port);
718 rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
719 #else
720 rc = -1;
721 errno = EAFNOSUPPORT;
722 #endif
723 } else {
724 memset(&addr, 0, sizeof(addr));
725 rc = inet_aton(address, &addr.sin_addr);
726 if(rc != 1) {
727 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
728 assert(done);
729 return NULL;
731 addr.sin_family = AF_INET;
732 addr.sin_port = htons(port);
733 rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
736 if(rc < 0) {
737 do_log_error(L_ERROR, errno, "Couldn't bind");
738 CLOSE(fd);
739 done = (*handler)(-errno, NULL, NULL);
740 assert(done);
741 return NULL;
744 rc = setNonblocking(fd, 1);
745 if(rc < 0) {
746 do_log_error(L_ERROR, errno, "Couldn't set non blocking mode");
747 CLOSE(fd);
748 done = (*handler)(-errno, NULL, NULL);
749 assert(done);
750 return NULL;
753 rc = listen(fd, 32);
754 if(rc < 0) {
755 do_log_error(L_ERROR, errno, "Couldn't listen");
756 CLOSE(fd);
757 done = (*handler)(-errno, NULL, NULL);
758 assert(done);
759 return NULL;
762 return schedule_accept(fd, handler, data);
765 #ifndef SOL_TCP
766 /* BSD */
767 #define SOL_TCP IPPROTO_TCP
768 #endif
771 setNonblocking(int fd, int nonblocking)
773 #ifdef MINGW
774 return mingw_setnonblocking(fd, nonblocking);
775 #else
776 int rc;
777 rc = fcntl(fd, F_GETFL, 0);
778 if(rc < 0)
779 return -1;
781 rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
782 if(rc < 0)
783 return -1;
785 return 0;
786 #endif
790 setNodelay(int fd, int nodelay)
792 int val = nodelay ? 1 : 0;
793 int rc;
794 rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
795 if(rc < 0)
796 return -1;
797 return 0;
800 #ifdef IPV6_V6ONLY
802 setV6only(int fd, int v6only)
804 int val = v6only ? 1 : 0;
805 int rc;
806 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
807 if(rc < 0)
808 return -1;
809 return 0;
811 #else
813 setV6only(int fd, int v6only)
815 return 0;
817 #endif
819 typedef struct _LingeringClose {
820 int fd;
821 FdEventHandlerPtr handler;
822 TimeEventHandlerPtr timeout;
823 } LingeringCloseRec, *LingeringClosePtr;
825 static int
826 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
828 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
829 assert(l->timeout == event);
830 l->timeout = NULL;
831 if(l->handler)
832 pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
833 else {
834 CLOSE(l->fd);
835 free(l);
837 return 1;
840 static int
841 lingeringCloseHandler(int status, FdEventHandlerPtr event)
843 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
844 char buf[17];
845 int rc;
847 assert(l->handler == event);
849 l->handler = NULL;
850 if(status && status != -EDOGRACEFUL)
851 goto done;
853 rc = READ(l->fd, &buf, 17);
854 if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
855 goto done;
857 /* The client is still sending data. Ignore it in order to let
858 TCP's flow control do its work. The timeout will close the
859 connection. */
860 return 1;
862 done:
863 if(l->timeout) {
864 cancelTimeEvent(l->timeout);
865 l->timeout = NULL;
867 CLOSE(l->fd);
868 free(l);
869 return 1;
873 lingeringClose(int fd)
875 int rc;
876 LingeringClosePtr l;
878 rc = shutdown(fd, 1);
879 if(rc < 0) {
880 if(errno != ENOTCONN) {
881 do_log_error(L_ERROR, errno, "Shutdown failed");
882 } else if(errno == EFAULT || errno == EBADF) {
883 abort();
885 CLOSE(fd);
886 return 1;
889 l = malloc(sizeof(LingeringCloseRec));
890 if(l == NULL)
891 goto fail;
892 l->fd = fd;
893 l->handler = NULL;
894 l->timeout = NULL;
896 l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
897 sizeof(LingeringClosePtr), &l);
898 if(l->timeout == NULL) {
899 free(l);
900 goto fail;
903 l->handler = registerFdEvent(fd, POLLIN,
904 lingeringCloseHandler,
905 sizeof(LingeringClosePtr), &l);
906 if(l->handler == NULL) {
907 do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
908 /* But don't close -- the timeout will do its work. */
910 return 1;
912 fail:
913 do_log(L_ERROR, "Couldn't schedule lingering close.\n");
914 CLOSE(fd);
915 return 1;
918 NetAddressPtr
919 parseNetAddress(AtomListPtr list)
921 NetAddressPtr nl;
922 int i, rc, rc6;
923 char buf[100];
924 struct in_addr ina;
925 #ifdef HAVE_IPv6
926 struct in6_addr ina6;
927 #endif
929 nl = malloc((list->length + 1) * sizeof(NetAddressRec));
930 if(nl == NULL) {
931 do_log(L_ERROR, "Couldn't allocate network list.\n");
932 return NULL;
935 for(i = 0; i < list->length; i++) {
936 int prefix;
937 char *s = list->list[i]->string, *p;
938 int n = list->list[i]->length;
939 char *suffix;
941 while(*s == ' ' || *s == '\t') {
942 s++;
943 n--;
946 if(n >= 100) {
947 do_log(L_ERROR, "Network name too long.\n");
948 goto fail;
950 p = memchr(s, '/', n);
951 if(p) {
952 memcpy(buf, s, p - s);
953 buf[p - s] = '\0';
954 prefix = strtol(p + 1, &suffix, 10);
955 } else {
956 char *s1, *s2;
957 prefix = -1;
958 strcpy(buf, s);
959 s1 = strchr(s, ' ');
960 s2 = strchr(s, '\t');
961 if(s1 == NULL) suffix = s2;
962 else if(s2 == NULL) suffix = s1;
963 else if(s1 < s2) suffix = s1;
964 else suffix = s2;
965 if(suffix == NULL)
966 suffix = s + n;
969 if(!isWhitespace(suffix)) {
970 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
971 goto fail;
974 rc = 0; rc6 = 0;
975 rc = inet_aton(buf, &ina);
976 #ifdef HAVE_IPv6
977 if(rc == 0) {
978 rc6 = inet_pton(AF_INET6, buf, &ina6);
980 #endif
981 if(rc == 0 && rc6 == 0) {
982 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
983 goto fail;
985 nl[i].prefix = prefix;
986 if(rc) {
987 nl[i].af = 4;
988 memcpy(nl[i].data, &ina, 4);
989 } else {
990 #ifdef HAVE_IPv6
991 nl[i].af = 6;
992 memcpy(nl[i].data, &ina6, 16);
993 #else
994 abort();
995 #endif
998 nl[i].af = 0;
999 return nl;
1001 fail:
1002 free(nl);
1003 return NULL;
1006 /* Returns 1 if the first n bits of a and b are equal */
1007 static int
1008 bitmatch(const unsigned char *a, const unsigned char *b, int n)
1010 if(n >= 8) {
1011 if(memcmp(a, b, n / 8) != 0)
1012 return 0;
1015 if(n % 8 != 0) {
1016 int mask = (~0) << (8 - n % 8);
1017 if((a[n / 8] & mask) != (b[n / 8] & mask))
1018 return 0;
1021 return 1;
1024 /* Returns 1 if the address in data is in list */
1025 static int
1026 match(int af, unsigned char *data, NetAddressPtr list)
1028 int i;
1029 #ifdef HAVE_IPv6
1030 static const unsigned char v6mapped[] =
1031 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1032 #endif
1034 i = 0;
1035 while(list[i].af != 0) {
1036 if(af == 4 && list[i].af == 4) {
1037 if(bitmatch(data, list[i].data,
1038 list[i].prefix >= 0 ? list[i].prefix : 32))
1039 return 1;
1040 #ifdef HAVE_IPv6
1041 } else if(af == 6 && list[i].af == 6) {
1042 if(bitmatch(data, list[i].data,
1043 list[i].prefix >= 0 ? list[i].prefix : 128))
1044 return 1;
1045 } else if(af == 6 && list[i].af == 4) {
1046 if(bitmatch(data, v6mapped, 96)) {
1047 if(bitmatch(data + 12, list[i].data,
1048 list[i].prefix >= 0 ? list[i].prefix : 32))
1049 return 1;
1051 } else if(af == 4 && list[i].af == 6) {
1052 if(bitmatch(list[i].data, v6mapped, 96)) {
1053 if(bitmatch(data, list[i].data + 12,
1054 list[i].prefix >= 96 ?
1055 list[i].prefix - 96 : 32))
1056 return 1;
1058 #endif
1059 } else {
1060 abort();
1062 i++;
1064 return 0;
1068 netAddressMatch(int fd, NetAddressPtr list)
1070 int rc;
1071 unsigned int len;
1072 struct sockaddr_in sain;
1073 #ifdef HAVE_IPv6
1074 struct sockaddr_in6 sain6;
1075 #endif
1077 len = sizeof(sain);
1078 rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1079 if(rc < 0) {
1080 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1081 return -1;
1084 if(sain.sin_family == AF_INET) {
1085 return match(4, (unsigned char*)&sain.sin_addr, list);
1086 #ifdef HAVE_IPv6
1087 } else if(sain.sin_family == AF_INET6) {
1088 len = sizeof(sain6);
1089 rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1090 if(rc < 0) {
1091 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1092 return -1;
1094 if(sain6.sin6_family != AF_INET6) {
1095 do_log(L_ERROR, "Inconsistent peer name");
1096 return -1;
1098 return match(6, (unsigned char*)&sain6.sin6_addr, list);
1099 #endif
1100 } else {
1101 do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1102 return -1;
1104 return 0;