Fix slightly incorrect parsing of requests.
[polipo.git] / io.c
blob2defcb9740188863c71c20fff5b0ef9fa796a0eb
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 do_log(L_INFO, "Established listening socket on port %d.\n", port);
764 return schedule_accept(fd, handler, data);
767 #ifndef SOL_TCP
768 /* BSD */
769 #define SOL_TCP IPPROTO_TCP
770 #endif
773 setNonblocking(int fd, int nonblocking)
775 #ifdef MINGW
776 return mingw_setnonblocking(fd, nonblocking);
777 #else
778 int rc;
779 rc = fcntl(fd, F_GETFL, 0);
780 if(rc < 0)
781 return -1;
783 rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
784 if(rc < 0)
785 return -1;
787 return 0;
788 #endif
792 setNodelay(int fd, int nodelay)
794 int val = nodelay ? 1 : 0;
795 int rc;
796 rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
797 if(rc < 0)
798 return -1;
799 return 0;
802 #ifdef IPV6_V6ONLY
804 setV6only(int fd, int v6only)
806 int val = v6only ? 1 : 0;
807 int rc;
808 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
809 if(rc < 0)
810 return -1;
811 return 0;
813 #else
815 setV6only(int fd, int v6only)
817 return 0;
819 #endif
821 typedef struct _LingeringClose {
822 int fd;
823 FdEventHandlerPtr handler;
824 TimeEventHandlerPtr timeout;
825 } LingeringCloseRec, *LingeringClosePtr;
827 static int
828 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
830 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
831 assert(l->timeout == event);
832 l->timeout = NULL;
833 if(l->handler)
834 pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
835 else {
836 CLOSE(l->fd);
837 free(l);
839 return 1;
842 static int
843 lingeringCloseHandler(int status, FdEventHandlerPtr event)
845 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
846 char buf[17];
847 int rc;
849 assert(l->handler == event);
851 l->handler = NULL;
852 if(status && status != -EDOGRACEFUL)
853 goto done;
855 rc = READ(l->fd, &buf, 17);
856 if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
857 goto done;
859 /* The client is still sending data. Ignore it in order to let
860 TCP's flow control do its work. The timeout will close the
861 connection. */
862 return 1;
864 done:
865 if(l->timeout) {
866 cancelTimeEvent(l->timeout);
867 l->timeout = NULL;
869 CLOSE(l->fd);
870 free(l);
871 return 1;
875 lingeringClose(int fd)
877 int rc;
878 LingeringClosePtr l;
880 rc = shutdown(fd, 1);
881 if(rc < 0) {
882 if(errno != ENOTCONN) {
883 do_log_error(L_ERROR, errno, "Shutdown failed");
884 } else if(errno == EFAULT || errno == EBADF) {
885 abort();
887 CLOSE(fd);
888 return 1;
891 l = malloc(sizeof(LingeringCloseRec));
892 if(l == NULL)
893 goto fail;
894 l->fd = fd;
895 l->handler = NULL;
896 l->timeout = NULL;
898 l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
899 sizeof(LingeringClosePtr), &l);
900 if(l->timeout == NULL) {
901 free(l);
902 goto fail;
905 l->handler = registerFdEvent(fd, POLLIN,
906 lingeringCloseHandler,
907 sizeof(LingeringClosePtr), &l);
908 if(l->handler == NULL) {
909 do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
910 /* But don't close -- the timeout will do its work. */
912 return 1;
914 fail:
915 do_log(L_ERROR, "Couldn't schedule lingering close.\n");
916 CLOSE(fd);
917 return 1;
920 NetAddressPtr
921 parseNetAddress(AtomListPtr list)
923 NetAddressPtr nl;
924 int i, rc, rc6;
925 char buf[100];
926 struct in_addr ina;
927 #ifdef HAVE_IPv6
928 struct in6_addr ina6;
929 #endif
931 nl = malloc((list->length + 1) * sizeof(NetAddressRec));
932 if(nl == NULL) {
933 do_log(L_ERROR, "Couldn't allocate network list.\n");
934 return NULL;
937 for(i = 0; i < list->length; i++) {
938 int prefix;
939 char *s = list->list[i]->string, *p;
940 int n = list->list[i]->length;
941 char *suffix;
943 while(*s == ' ' || *s == '\t') {
944 s++;
945 n--;
948 if(n >= 100) {
949 do_log(L_ERROR, "Network name too long.\n");
950 goto fail;
952 p = memchr(s, '/', n);
953 if(p) {
954 memcpy(buf, s, p - s);
955 buf[p - s] = '\0';
956 prefix = strtol(p + 1, &suffix, 10);
957 } else {
958 char *s1, *s2;
959 prefix = -1;
960 strcpy(buf, s);
961 s1 = strchr(s, ' ');
962 s2 = strchr(s, '\t');
963 if(s1 == NULL) suffix = s2;
964 else if(s2 == NULL) suffix = s1;
965 else if(s1 < s2) suffix = s1;
966 else suffix = s2;
967 if(suffix == NULL)
968 suffix = s + n;
971 if(!isWhitespace(suffix)) {
972 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
973 goto fail;
976 rc = 0; rc6 = 0;
977 rc = inet_aton(buf, &ina);
978 #ifdef HAVE_IPv6
979 if(rc == 0) {
980 rc6 = inet_pton(AF_INET6, buf, &ina6);
982 #endif
983 if(rc == 0 && rc6 == 0) {
984 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
985 goto fail;
987 nl[i].prefix = prefix;
988 if(rc) {
989 nl[i].af = 4;
990 memcpy(nl[i].data, &ina, 4);
991 } else {
992 #ifdef HAVE_IPv6
993 nl[i].af = 6;
994 memcpy(nl[i].data, &ina6, 16);
995 #else
996 abort();
997 #endif
1000 nl[i].af = 0;
1001 return nl;
1003 fail:
1004 free(nl);
1005 return NULL;
1008 /* Returns 1 if the first n bits of a and b are equal */
1009 static int
1010 bitmatch(const unsigned char *a, const unsigned char *b, int n)
1012 if(n >= 8) {
1013 if(memcmp(a, b, n / 8) != 0)
1014 return 0;
1017 if(n % 8 != 0) {
1018 int mask = (~0) << (8 - n % 8);
1019 if((a[n / 8] & mask) != (b[n / 8] & mask))
1020 return 0;
1023 return 1;
1026 /* Returns 1 if the address in data is in list */
1027 static int
1028 match(int af, unsigned char *data, NetAddressPtr list)
1030 int i;
1031 #ifdef HAVE_IPv6
1032 static const unsigned char v6mapped[] =
1033 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1034 #endif
1036 i = 0;
1037 while(list[i].af != 0) {
1038 if(af == 4 && list[i].af == 4) {
1039 if(bitmatch(data, list[i].data,
1040 list[i].prefix >= 0 ? list[i].prefix : 32))
1041 return 1;
1042 #ifdef HAVE_IPv6
1043 } else if(af == 6 && list[i].af == 6) {
1044 if(bitmatch(data, list[i].data,
1045 list[i].prefix >= 0 ? list[i].prefix : 128))
1046 return 1;
1047 } else if(af == 6 && list[i].af == 4) {
1048 if(bitmatch(data, v6mapped, 96)) {
1049 if(bitmatch(data + 12, list[i].data,
1050 list[i].prefix >= 0 ? list[i].prefix : 32))
1051 return 1;
1053 } else if(af == 4 && list[i].af == 6) {
1054 if(bitmatch(list[i].data, v6mapped, 96)) {
1055 if(bitmatch(data, list[i].data + 12,
1056 list[i].prefix >= 96 ?
1057 list[i].prefix - 96 : 32))
1058 return 1;
1060 #endif
1061 } else {
1062 abort();
1064 i++;
1066 return 0;
1070 netAddressMatch(int fd, NetAddressPtr list)
1072 int rc;
1073 unsigned int len;
1074 struct sockaddr_in sain;
1075 #ifdef HAVE_IPv6
1076 struct sockaddr_in6 sain6;
1077 #endif
1079 len = sizeof(sain);
1080 rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1081 if(rc < 0) {
1082 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1083 return -1;
1086 if(sain.sin_family == AF_INET) {
1087 return match(4, (unsigned char*)&sain.sin_addr, list);
1088 #ifdef HAVE_IPv6
1089 } else if(sain.sin_family == AF_INET6) {
1090 len = sizeof(sain6);
1091 rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1092 if(rc < 0) {
1093 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1094 return -1;
1096 if(sain6.sin6_family != AF_INET6) {
1097 do_log(L_ERROR, "Inconsistent peer name");
1098 return -1;
1100 return match(6, (unsigned char*)&sain6.sin6_addr, list);
1101 #endif
1102 } else {
1103 do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1104 return -1;
1106 return 0;