Add a record of 1.0.4.1 to CHANGES.
[polipo.git] / io.c
blob95de1a523fe889effb3b3d6b18dcb78134035cdd
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 #ifdef HAVE_IPv6
26 #ifdef IPV6_PREFER_TEMPADDR
27 #define HAVE_IPV6_PREFER_TEMPADDR 1
28 #endif
29 #endif
31 #ifdef HAVE_IPV6_PREFER_TEMPADDR
32 int useTemporarySourceAddress = 1;
33 #endif
35 void
36 preinitIo()
38 #ifdef HAVE_IPV6_PREFER_TEMPADDR
39 CONFIG_VARIABLE_SETTABLE(useTemporarySourceAddress, CONFIG_TRISTATE,
40 configIntSetter,
41 "Prefer IPv6 temporary source address.");
42 #endif
44 #ifdef HAVE_WINSOCK
45 /* Load the winsock dll */
46 WSADATA wsaData;
47 WORD wVersionRequested = MAKEWORD(2, 2);
48 int err = WSAStartup( wVersionRequested, &wsaData );
49 if (err != 0) {
50 do_log_error(L_ERROR, err, "Couldn't load winsock dll");
51 exit(-1);
53 #endif
54 return;
57 void
58 initIo()
60 return;
63 FdEventHandlerPtr
64 do_stream(int operation, int fd, int offset, char *buf, int len,
65 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
66 void *data)
68 assert(len > offset || (operation & (IO_END | IO_IMMEDIATE)));
69 return schedule_stream(operation, fd, offset,
70 NULL, 0, buf, len, NULL, 0, NULL, 0, NULL,
71 handler, data);
74 FdEventHandlerPtr
75 do_stream_2(int operation, int fd, int offset,
76 char *buf, int len, char *buf2, int len2,
77 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
78 void *data)
80 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
81 return schedule_stream(operation, fd, offset,
82 NULL, 0, buf, len, buf2, len2, NULL, 0, NULL,
83 handler, data);
86 FdEventHandlerPtr
87 do_stream_3(int operation, int fd, int offset,
88 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
89 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
90 void *data)
92 assert(len + len2 > offset || (operation & (IO_END | IO_IMMEDIATE)));
93 return schedule_stream(operation, fd, offset,
94 NULL, 0, buf, len, buf2, len2, buf3, len3, NULL,
95 handler, data);
98 FdEventHandlerPtr
99 do_stream_h(int operation, int fd, int offset,
100 char *header, int hlen, char *buf, int len,
101 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
102 void *data)
104 assert(hlen + len > offset || (operation & (IO_END | IO_IMMEDIATE)));
105 return schedule_stream(operation, fd, offset,
106 header, hlen, buf, len, NULL, 0, NULL, 0, NULL,
107 handler, data);
110 FdEventHandlerPtr
111 do_stream_buf(int operation, int fd, int offset, char **buf_location, int len,
112 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
113 void *data)
115 assert((len > offset || (operation & (IO_END | IO_IMMEDIATE)))
116 && len <= CHUNK_SIZE);
117 return schedule_stream(operation, fd, offset,
118 NULL, 0, *buf_location, len,
119 NULL, 0, NULL, 0, buf_location,
120 handler, data);
123 static int
124 chunkHeaderLen(int i)
126 if(i <= 0)
127 return 0;
128 if(i < 0x10)
129 return 3;
130 else if(i < 0x100)
131 return 4;
132 else if(i < 0x1000)
133 return 5;
134 else if(i < 0x10000)
135 return 6;
136 else
137 abort();
140 static int
141 chunkHeader(char *buf, int buflen, int i)
143 int n;
144 if(i <= 0)
145 return 0;
146 n = snprintf(buf, buflen, "%x\r\n", i);
147 return n;
151 FdEventHandlerPtr
152 schedule_stream(int operation, int fd, int offset,
153 char *header, int hlen,
154 char *buf, int len, char *buf2, int len2, char *buf3, int len3,
155 char **buf_location,
156 int (*handler)(int, FdEventHandlerPtr, StreamRequestPtr),
157 void *data)
159 StreamRequestRec request;
160 FdEventHandlerPtr event;
161 int done;
163 request.operation = operation;
164 request.fd = fd;
165 if(len3) {
166 assert(hlen == 0 && buf_location == NULL);
167 request.u.b.len3 = len3;
168 request.u.b.buf3 = buf3;
169 request.operation |= IO_BUF3;
170 } else if(buf_location) {
171 assert(hlen == 0);
172 request.u.l.buf_location = buf_location;
173 request.operation |= IO_BUF_LOCATION;
174 } else {
175 request.u.h.hlen = hlen;
176 request.u.h.header = header;
178 request.buf = buf;
179 request.len = len;
180 request.buf2 = buf2;
181 request.len2 = len2;
182 if((operation & IO_CHUNKED) ||
183 (!(request.operation & (IO_BUF3 | IO_BUF_LOCATION)) && hlen > 0)) {
184 assert(offset == 0);
185 request.offset = -hlen;
186 if(operation & IO_CHUNKED)
187 request.offset += -chunkHeaderLen(len + len2);
188 } else {
189 request.offset = offset;
191 request.handler = handler;
192 request.data = data;
193 event = makeFdEvent(fd,
194 (operation & IO_MASK) == IO_WRITE ?
195 POLLOUT : POLLIN,
196 do_scheduled_stream,
197 sizeof(StreamRequestRec), &request);
198 if(!event) {
199 done = (*handler)(-ENOMEM, NULL, &request);
200 assert(done);
201 return NULL;
204 if(!(operation & IO_NOTNOW)) {
205 done = event->handler(0, event);
206 if(done) {
207 free(event);
208 return NULL;
212 if(operation & IO_IMMEDIATE) {
213 assert(hlen == 0 && !(operation & IO_CHUNKED));
214 done = (*handler)(0, event, &request);
215 if(done) {
216 free(event);
217 return NULL;
220 event = registerFdEventHelper(event);
221 return event;
224 static const char *endChunkTrailer = "\r\n0\r\n\r\n";
227 do_scheduled_stream(int status, FdEventHandlerPtr event)
229 StreamRequestPtr request = (StreamRequestPtr)&event->data;
230 int rc, done, i;
231 struct iovec iov[6];
232 int chunk_header_len;
233 char chunk_header[10];
234 int len12 = request->len + request->len2;
235 int len123 =
236 request->len + request->len2 +
237 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
239 if(status) {
240 done = request->handler(status, event, request);
241 return done;
244 i = 0;
246 if(request->offset < 0) {
247 assert((request->operation & (IO_MASK | IO_BUF3 | IO_BUF_LOCATION)) ==
248 IO_WRITE);
249 if(request->operation & IO_CHUNKED) {
250 chunk_header_len = chunkHeaderLen(len123);
251 } else {
252 chunk_header_len = 0;
255 if(request->offset < -chunk_header_len) {
256 assert(request->offset >= -(request->u.h.hlen + chunk_header_len));
257 iov[i].iov_base = request->u.h.header;
258 iov[i].iov_len = -request->offset - chunk_header_len;
259 i++;
262 if(chunk_header_len > 0) {
263 chunkHeader(chunk_header, 10, len123);
264 if(request->offset < -chunk_header_len) {
265 iov[i].iov_base = chunk_header;
266 iov[i].iov_len = chunk_header_len;
267 } else {
268 iov[i].iov_base = chunk_header +
269 chunk_header_len + request->offset;
270 iov[i].iov_len = -request->offset;
272 i++;
276 if(request->len > 0) {
277 if(request->buf == NULL &&
278 (request->operation & IO_BUF_LOCATION)) {
279 assert(*request->u.l.buf_location == NULL);
280 request->buf = *request->u.l.buf_location = get_chunk();
281 if(request->buf == NULL) {
282 done = request->handler(-ENOMEM, event, request);
283 return done;
286 if(request->offset <= 0) {
287 iov[i].iov_base = request->buf;
288 iov[i].iov_len = request->len;
289 i++;
290 } else if(request->offset < request->len) {
291 iov[i].iov_base = request->buf + request->offset;
292 iov[i].iov_len = request->len - request->offset;
293 i++;
297 if(request->len2 > 0) {
298 if(request->offset <= request->len) {
299 iov[i].iov_base = request->buf2;
300 iov[i].iov_len = request->len2;
301 i++;
302 } else if(request->offset < request->len + request->len2) {
303 iov[i].iov_base = request->buf2 + request->offset - request->len;
304 iov[i].iov_len = request->len2 - request->offset + request->len;
305 i++;
309 if((request->operation & IO_BUF3) && request->u.b.len3 > 0) {
310 if(request->offset <= len12) {
311 iov[i].iov_base = request->u.b.buf3;
312 iov[i].iov_len = request->u.b.len3;
313 i++;
314 } else if(request->offset < len12 + request->u.b.len3) {
315 iov[i].iov_base = request->u.b.buf3 + request->offset - len12;
316 iov[i].iov_len = request->u.b.len3 - request->offset + len12;
317 i++;
321 if((request->operation & IO_CHUNKED)) {
322 int l;
323 const char *trailer;
324 if(request->operation & IO_END) {
325 if(len123 == 0) {
326 trailer = endChunkTrailer + 2;
327 l = 5;
328 } else {
329 trailer = endChunkTrailer;
330 l = 7;
332 } else {
333 trailer = endChunkTrailer;
334 l = 2;
337 if(request->offset <= len123) {
338 iov[i].iov_base = (char*)trailer;
339 iov[i].iov_len = l;
340 i++;
341 } else if(request->offset < len123 + l) {
342 iov[i].iov_base =
343 (char*)endChunkTrailer + request->offset - len123;
344 iov[i].iov_len = l - request->offset + len123;
345 i++;
349 assert(i > 0);
351 if((request->operation & IO_MASK) == IO_WRITE) {
352 if(i > 1)
353 rc = WRITEV(request->fd, iov, i);
354 else
355 rc = WRITE(request->fd, iov[0].iov_base, iov[0].iov_len);
356 } else {
357 if(i > 1)
358 rc = READV(request->fd, iov, i);
359 else
360 rc = READ(request->fd, iov[0].iov_base, iov[0].iov_len);
363 if(rc > 0) {
364 request->offset += rc;
365 if(request->offset < 0) return 0;
366 done = request->handler(0, event, request);
367 return done;
368 } else if(rc == 0 || errno == EPIPE) {
369 done = request->handler(1, event, request);
370 } else if(errno == EAGAIN || errno == EINTR) {
371 return 0;
372 } else if(errno == EFAULT || errno == EBADF) {
373 abort();
374 } else {
375 done = request->handler(-errno, event, request);
377 assert(done);
378 return done;
382 streamRequestDone(StreamRequestPtr request)
384 int len123 =
385 request->len + request->len2 +
386 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
388 if(request->offset < 0)
389 return 0;
390 else if(request->offset < len123)
391 return 0;
392 else if(request->operation & IO_CHUNKED) {
393 if(request->operation & IO_END) {
394 if(request->offset < len123 + (len123 ? 7 : 5))
395 return 0;
396 } else {
397 if(request->offset < len123 + 2)
398 return 0;
402 return 1;
405 static int
406 serverSocket(int af)
408 int fd, rc;
409 if(af == 4) {
410 fd = socket(PF_INET, SOCK_STREAM, 0);
411 } else if(af == 6) {
412 #ifdef HAVE_IPv6
413 fd = socket(PF_INET6, SOCK_STREAM, 0);
414 #else
415 fd = -1;
416 errno = EAFNOSUPPORT;
417 #endif
418 } else {
419 abort();
422 if(fd >= 0) {
423 rc = setNonblocking(fd, 1);
424 if(rc < 0) {
425 int errno_save = errno;
426 CLOSE(fd);
427 errno = errno_save;
428 return -1;
430 #ifdef HAVE_IPV6_PREFER_TEMPADDR
431 if (af == 6 && useTemporarySourceAddress != 1) {
432 int value;
433 value = (useTemporarySourceAddress == 2) ? 1 : 0;
434 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
435 &value, sizeof(value));
436 if (rc < 0) {
437 /* no error, warning only */
438 do_log_error(L_WARN, errno, "Couldn't set IPV6CTL_USETEMPADDR");
442 #endif
444 return fd;
447 FdEventHandlerPtr
448 do_connect(AtomPtr addr, int index, int port,
449 int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr),
450 void *data)
452 ConnectRequestRec request;
453 FdEventHandlerPtr event;
454 int done, fd, af;
456 assert(addr->length > 0 && addr->string[0] == DNS_A);
457 assert(addr->length % sizeof(HostAddressRec) == 1);
459 if(index >= (addr->length - 1)/ sizeof(HostAddressRec))
460 index = 0;
462 request.firstindex = index;
463 request.port = port;
464 request.handler = handler;
465 request.data = data;
466 again:
467 af = addr->string[1 + index * sizeof(HostAddressRec)];
468 fd = serverSocket(af);
470 request.fd = fd;
471 request.af = af;
472 request.addr = addr;
473 request.index = index;
475 if(fd < 0) {
476 int n = (addr->length - 1) / sizeof(HostAddressRec);
477 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
478 if((index + 1) % n != request.firstindex) {
479 index = (index + 1) % n;
480 goto again;
483 do_log_error(L_ERROR, errno, "Couldn't create socket");
484 done = (*handler)(-errno, NULL, &request);
485 assert(done);
486 return NULL;
489 /* POLLIN is apparently needed on Windows */
490 event = registerFdEvent(fd, POLLIN | POLLOUT,
491 do_scheduled_connect,
492 sizeof(ConnectRequestRec), &request);
493 if(event == NULL) {
494 done = (*handler)(-ENOMEM, NULL, &request);
495 assert(done);
496 return NULL;
499 done = event->handler(0, event);
500 if(done) {
501 unregisterFdEvent(event);
502 return NULL;
504 return event;
508 do_scheduled_connect(int status, FdEventHandlerPtr event)
510 ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
511 AtomPtr addr = request->addr;
512 int done;
513 int rc;
514 HostAddressPtr host;
515 struct sockaddr_in servaddr;
516 #ifdef HAVE_IPv6
517 struct sockaddr_in6 servaddr6;
518 #endif
520 assert(addr->length > 0 && addr->string[0] == DNS_A);
521 assert(addr->length % sizeof(HostAddressRec) == 1);
522 assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));
524 if(status) {
525 done = request->handler(status, event, request);
526 if(done) {
527 releaseAtom(addr);
528 request->addr = NULL;
529 return 1;
531 return 0;
534 again:
535 host = (HostAddressPtr)&addr->string[1 +
536 request->index *
537 sizeof(HostAddressRec)];
538 if(host->af != request->af) {
539 int newfd;
540 /* Ouch. Our socket has a different protocol than the host
541 address. */
542 CLOSE(request->fd);
543 newfd = serverSocket(host->af);
544 if(newfd < 0) {
545 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
546 int n = request->addr->length / sizeof(HostAddressRec);
547 if((request->index + 1) % n != request->firstindex) {
548 request->index = (request->index + 1) % n;
549 goto again;
552 request->fd = -1;
553 done = request->handler(-errno, event, request);
554 assert(done);
555 return 1;
557 if(newfd != request->fd) {
558 request->fd = dup2(newfd, request->fd);
559 CLOSE(newfd);
560 if(request->fd < 0) {
561 done = request->handler(-errno, event, request);
562 assert(done);
563 return 1;
566 request->af = host->af;
568 switch(host->af) {
569 case 4:
570 memset(&servaddr, 0, sizeof(servaddr));
571 servaddr.sin_family = AF_INET;
572 servaddr.sin_port = htons(request->port);
573 memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
574 rc = connect(request->fd,
575 (struct sockaddr*)&servaddr, sizeof(servaddr));
576 break;
577 case 6:
578 #ifdef HAVE_IPv6
579 memset(&servaddr6, 0, sizeof(servaddr6));
580 servaddr6.sin6_family = AF_INET6;
581 servaddr6.sin6_port = htons(request->port);
582 memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
583 rc = connect(request->fd,
584 (struct sockaddr*)&servaddr6, sizeof(servaddr6));
585 #else
586 rc = -1;
587 errno = EAFNOSUPPORT;
588 #endif
589 break;
590 default:
591 abort();
594 if(rc >= 0 || errno == EISCONN) {
595 done = request->handler(1, event, request);
596 assert(done);
597 releaseAtom(request->addr);
598 request->addr = NULL;
599 return 1;
602 if(errno == EINPROGRESS || errno == EINTR) {
603 return 0;
604 } else if(errno == EFAULT || errno == EBADF) {
605 abort();
606 } else {
607 int n = request->addr->length / sizeof(HostAddressRec);
608 if((request->index + 1) % n != request->firstindex) {
609 request->index = (request->index + 1) % n;
610 goto again;
612 done = request->handler(-errno, event, request);
613 assert(done);
614 releaseAtom(request->addr);
615 request->addr = NULL;
616 return 1;
620 FdEventHandlerPtr
621 do_accept(int fd,
622 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
623 void *data)
625 FdEventHandlerPtr event;
626 int done;
628 event = schedule_accept(fd, handler, data);
629 if(event == NULL) {
630 done = (*handler)(-ENOMEM, NULL, NULL);
631 assert(done);
634 /* But don't invoke it now - this will delay accept if under load. */
635 return event;
638 FdEventHandlerPtr
639 schedule_accept(int fd,
640 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
641 void *data)
643 FdEventHandlerPtr event;
644 AcceptRequestRec request;
645 int done;
647 request.fd = fd;
648 request.handler = handler;
649 request.data = data;
650 event = registerFdEvent(fd, POLLOUT|POLLIN,
651 do_scheduled_accept, sizeof(request), &request);
652 if(!event) {
653 done = (*handler)(-ENOMEM, NULL, NULL);
654 assert(done);
656 return event;
660 do_scheduled_accept(int status, FdEventHandlerPtr event)
662 AcceptRequestPtr request = (AcceptRequestPtr)&event->data;
663 int rc, done;
664 unsigned len;
665 struct sockaddr_in addr;
667 if(status) {
668 done = request->handler(status, event, request);
669 if(done) return done;
672 len = sizeof(struct sockaddr_in);
674 rc = accept(request->fd, (struct sockaddr*)&addr, &len);
676 if(rc >= 0)
677 done = request->handler(rc, event, request);
678 else
679 done = request->handler(-errno, event, request);
680 return done;
683 FdEventHandlerPtr
684 create_listener(char *address, int port,
685 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
686 void *data)
688 int fd, rc;
689 int one = 1;
690 int done;
691 struct sockaddr_in addr;
692 #ifdef HAVE_IPv6
693 int inet6 = 1;
694 struct sockaddr_in6 addr6;
695 #else
696 int inet6 = 0;
697 #endif
699 if(inet6 && address) {
700 struct in_addr buf;
701 rc = inet_aton(address, &buf);
702 if(rc == 1)
703 inet6 = 0;
705 fd = -1;
706 errno = EAFNOSUPPORT;
708 #ifdef HAVE_IPv6
709 if(inet6) {
710 fd = socket(PF_INET6, SOCK_STREAM, 0);
712 #endif
714 if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) {
715 inet6 = 0;
716 fd = socket(PF_INET, SOCK_STREAM, 0);
719 if(fd < 0) {
720 done = (*handler)(-errno, NULL, NULL);
721 assert(done);
722 return NULL;
725 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
726 if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR");
728 if(inet6) {
729 #ifdef HAVE_IPv6
730 rc = setV6only(fd, 0);
731 if(rc < 0)
732 /* Reportedly OpenBSD returns an error for that. So only
733 log it as a debugging message. */
734 do_log_error(D_CLIENT_CONN, errno, "Couldn't reset IPV6_V6ONLY");
736 memset(&addr6, 0, sizeof(addr6));
737 rc = inet_pton(AF_INET6, address, &addr6.sin6_addr);
738 if(rc != 1) {
739 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
740 assert(done);
741 return NULL;
743 addr6.sin6_family = AF_INET6;
744 addr6.sin6_port = htons(port);
745 rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
746 #else
747 rc = -1;
748 errno = EAFNOSUPPORT;
749 #endif
750 } else {
751 memset(&addr, 0, sizeof(addr));
752 rc = inet_aton(address, &addr.sin_addr);
753 if(rc != 1) {
754 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
755 assert(done);
756 return NULL;
758 addr.sin_family = AF_INET;
759 addr.sin_port = htons(port);
760 rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
763 if(rc < 0) {
764 do_log_error(L_ERROR, errno, "Couldn't bind");
765 CLOSE(fd);
766 done = (*handler)(-errno, NULL, NULL);
767 assert(done);
768 return NULL;
771 rc = setNonblocking(fd, 1);
772 if(rc < 0) {
773 do_log_error(L_ERROR, errno, "Couldn't set non blocking mode");
774 CLOSE(fd);
775 done = (*handler)(-errno, NULL, NULL);
776 assert(done);
777 return NULL;
780 rc = listen(fd, 1024);
781 if(rc < 0) {
782 do_log_error(L_ERROR, errno, "Couldn't listen");
783 CLOSE(fd);
784 done = (*handler)(-errno, NULL, NULL);
785 assert(done);
786 return NULL;
789 do_log(L_INFO, "Established listening socket on port %d.\n", port);
791 return schedule_accept(fd, handler, data);
794 #ifndef SOL_TCP
795 /* BSD */
796 #define SOL_TCP IPPROTO_TCP
797 #endif
800 setNonblocking(int fd, int nonblocking)
802 #ifdef MINGW
803 return mingw_setnonblocking(fd, nonblocking);
804 #else
805 int rc;
806 rc = fcntl(fd, F_GETFL, 0);
807 if(rc < 0)
808 return -1;
810 rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
811 if(rc < 0)
812 return -1;
814 return 0;
815 #endif
819 setNodelay(int fd, int nodelay)
821 int val = nodelay ? 1 : 0;
822 int rc;
823 rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
824 if(rc < 0)
825 return -1;
826 return 0;
829 #ifdef IPV6_V6ONLY
831 setV6only(int fd, int v6only)
833 int val = v6only ? 1 : 0;
834 int rc;
835 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
836 if(rc < 0)
837 return -1;
838 return 0;
840 #else
842 setV6only(int fd, int v6only)
844 return 0;
846 #endif
848 typedef struct _LingeringClose {
849 int fd;
850 FdEventHandlerPtr handler;
851 TimeEventHandlerPtr timeout;
852 } LingeringCloseRec, *LingeringClosePtr;
854 static int
855 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
857 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
858 assert(l->timeout == event);
859 l->timeout = NULL;
860 if(l->handler)
861 pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
862 else {
863 CLOSE(l->fd);
864 free(l);
866 return 1;
869 static int
870 lingeringCloseHandler(int status, FdEventHandlerPtr event)
872 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
873 char buf[17];
874 int rc;
876 assert(l->handler == event);
878 l->handler = NULL;
879 if(status && status != -EDOGRACEFUL)
880 goto done;
882 rc = READ(l->fd, &buf, 17);
883 if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
884 goto done;
886 /* The client is still sending data. Ignore it in order to let
887 TCP's flow control do its work. The timeout will close the
888 connection. */
889 return 1;
891 done:
892 if(l->timeout) {
893 cancelTimeEvent(l->timeout);
894 l->timeout = NULL;
896 CLOSE(l->fd);
897 free(l);
898 return 1;
902 lingeringClose(int fd)
904 int rc;
905 LingeringClosePtr l;
907 rc = shutdown(fd, 1);
908 if(rc < 0) {
909 if(errno != ENOTCONN) {
910 do_log_error(L_ERROR, errno, "Shutdown failed");
911 } else if(errno == EFAULT || errno == EBADF) {
912 abort();
914 CLOSE(fd);
915 return 1;
918 l = malloc(sizeof(LingeringCloseRec));
919 if(l == NULL)
920 goto fail;
921 l->fd = fd;
922 l->handler = NULL;
923 l->timeout = NULL;
925 l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
926 sizeof(LingeringClosePtr), &l);
927 if(l->timeout == NULL) {
928 free(l);
929 goto fail;
932 l->handler = registerFdEvent(fd, POLLIN,
933 lingeringCloseHandler,
934 sizeof(LingeringClosePtr), &l);
935 if(l->handler == NULL) {
936 do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
937 /* But don't close -- the timeout will do its work. */
939 return 1;
941 fail:
942 do_log(L_ERROR, "Couldn't schedule lingering close.\n");
943 CLOSE(fd);
944 return 1;
947 NetAddressPtr
948 parseNetAddress(AtomListPtr list)
950 NetAddressPtr nl;
951 int i, rc, rc6;
952 char buf[100];
953 struct in_addr ina;
954 #ifdef HAVE_IPv6
955 struct in6_addr ina6;
956 #endif
958 nl = malloc((list->length + 1) * sizeof(NetAddressRec));
959 if(nl == NULL) {
960 do_log(L_ERROR, "Couldn't allocate network list.\n");
961 return NULL;
964 for(i = 0; i < list->length; i++) {
965 int prefix;
966 char *s = list->list[i]->string, *p;
967 int n = list->list[i]->length;
968 char *suffix;
970 while(*s == ' ' || *s == '\t') {
971 s++;
972 n--;
975 if(n >= 100) {
976 do_log(L_ERROR, "Network name too long.\n");
977 goto fail;
979 p = memchr(s, '/', n);
980 if(p) {
981 memcpy(buf, s, p - s);
982 buf[p - s] = '\0';
983 prefix = strtol(p + 1, &suffix, 10);
984 } else {
985 char *s1, *s2;
986 prefix = -1;
987 strcpy(buf, s);
988 s1 = strchr(s, ' ');
989 s2 = strchr(s, '\t');
990 if(s1 == NULL) suffix = s2;
991 else if(s2 == NULL) suffix = s1;
992 else if(s1 < s2) suffix = s1;
993 else suffix = s2;
994 if(suffix == NULL)
995 suffix = s + n;
998 if(!isWhitespace(suffix)) {
999 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1000 goto fail;
1003 rc6 = 0;
1004 rc = inet_aton(buf, &ina);
1005 #ifdef HAVE_IPv6
1006 if(rc == 0) {
1007 rc6 = inet_pton(AF_INET6, buf, &ina6);
1009 #endif
1010 if(rc == 0 && rc6 == 0) {
1011 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1012 goto fail;
1014 nl[i].prefix = prefix;
1015 if(rc) {
1016 nl[i].af = 4;
1017 memcpy(nl[i].data, &ina, 4);
1018 } else {
1019 #ifdef HAVE_IPv6
1020 nl[i].af = 6;
1021 memcpy(nl[i].data, &ina6, 16);
1022 #else
1023 abort();
1024 #endif
1027 nl[i].af = 0;
1028 return nl;
1030 fail:
1031 free(nl);
1032 return NULL;
1035 /* Returns 1 if the first n bits of a and b are equal */
1036 static int
1037 bitmatch(const unsigned char *a, const unsigned char *b, int n)
1039 if(n >= 8) {
1040 if(memcmp(a, b, n / 8) != 0)
1041 return 0;
1044 if(n % 8 != 0) {
1045 int mask = (~0) << (8 - n % 8);
1046 if((a[n / 8] & mask) != (b[n / 8] & mask))
1047 return 0;
1050 return 1;
1053 /* Returns 1 if the address in data is in list */
1054 static int
1055 match(int af, unsigned char *data, NetAddressPtr list)
1057 int i;
1058 #ifdef HAVE_IPv6
1059 static const unsigned char v6mapped[] =
1060 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1061 #endif
1063 i = 0;
1064 while(list[i].af != 0) {
1065 if(af == 4 && list[i].af == 4) {
1066 if(bitmatch(data, list[i].data,
1067 list[i].prefix >= 0 ? list[i].prefix : 32))
1068 return 1;
1069 #ifdef HAVE_IPv6
1070 } else if(af == 6 && list[i].af == 6) {
1071 if(bitmatch(data, list[i].data,
1072 list[i].prefix >= 0 ? list[i].prefix : 128))
1073 return 1;
1074 } else if(af == 6 && list[i].af == 4) {
1075 if(bitmatch(data, v6mapped, 96)) {
1076 if(bitmatch(data + 12, list[i].data,
1077 list[i].prefix >= 0 ? list[i].prefix : 32))
1078 return 1;
1080 } else if(af == 4 && list[i].af == 6) {
1081 if(bitmatch(list[i].data, v6mapped, 96)) {
1082 if(bitmatch(data, list[i].data + 12,
1083 list[i].prefix >= 96 ?
1084 list[i].prefix - 96 : 32))
1085 return 1;
1087 #endif
1088 } else {
1089 abort();
1091 i++;
1093 return 0;
1097 netAddressMatch(int fd, NetAddressPtr list)
1099 int rc;
1100 unsigned int len;
1101 struct sockaddr_in sain;
1102 #ifdef HAVE_IPv6
1103 struct sockaddr_in6 sain6;
1104 #endif
1106 len = sizeof(sain);
1107 rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1108 if(rc < 0) {
1109 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1110 return -1;
1113 if(sain.sin_family == AF_INET) {
1114 return match(4, (unsigned char*)&sain.sin_addr, list);
1115 #ifdef HAVE_IPv6
1116 } else if(sain.sin_family == AF_INET6) {
1117 len = sizeof(sain6);
1118 rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1119 if(rc < 0) {
1120 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1121 return -1;
1123 if(sain6.sin6_family != AF_INET6) {
1124 do_log(L_ERROR, "Inconsistent peer name");
1125 return -1;
1127 return match(6, (unsigned char*)&sain6.sin6_addr, list);
1128 #endif
1129 } else {
1130 do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1131 return -1;
1133 return 0;