Fix an integer overflow in processing client connections.
[polipo.git] / io.c
bloba64bc817f4b83c3da2d25814fc0ca04225a54cf9
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, chunk_trailer_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 chunk_trailer_len = 2;
252 } else {
253 chunk_header_len = 0;
254 chunk_trailer_len = 0;
257 if(request->offset < -chunk_header_len) {
258 assert(request->offset >= -(request->u.h.hlen + chunk_header_len));
259 iov[i].iov_base = request->u.h.header;
260 iov[i].iov_len = -request->offset - chunk_header_len;
261 i++;
264 if(chunk_header_len > 0) {
265 chunkHeader(chunk_header, 10, len123);
266 if(request->offset < -chunk_header_len) {
267 iov[i].iov_base = chunk_header;
268 iov[i].iov_len = chunk_header_len;
269 } else {
270 iov[i].iov_base = chunk_header +
271 chunk_header_len + request->offset;
272 iov[i].iov_len = -request->offset;
274 i++;
278 if(request->len > 0) {
279 if(request->buf == NULL &&
280 (request->operation & IO_BUF_LOCATION)) {
281 assert(*request->u.l.buf_location == NULL);
282 request->buf = *request->u.l.buf_location = get_chunk();
283 if(request->buf == NULL) {
284 done = request->handler(-ENOMEM, event, request);
285 return done;
288 if(request->offset <= 0) {
289 iov[i].iov_base = request->buf;
290 iov[i].iov_len = request->len;
291 i++;
292 } else if(request->offset < request->len) {
293 iov[i].iov_base = request->buf + request->offset;
294 iov[i].iov_len = request->len - request->offset;
295 i++;
299 if(request->len2 > 0) {
300 if(request->offset <= request->len) {
301 iov[i].iov_base = request->buf2;
302 iov[i].iov_len = request->len2;
303 i++;
304 } else if(request->offset < request->len + request->len2) {
305 iov[i].iov_base = request->buf2 + request->offset - request->len;
306 iov[i].iov_len = request->len2 - request->offset + request->len;
307 i++;
311 if((request->operation & IO_BUF3) && request->u.b.len3 > 0) {
312 if(request->offset <= len12) {
313 iov[i].iov_base = request->u.b.buf3;
314 iov[i].iov_len = request->u.b.len3;
315 i++;
316 } else if(request->offset < len12 + request->u.b.len3) {
317 iov[i].iov_base = request->u.b.buf3 + request->offset - len12;
318 iov[i].iov_len = request->u.b.len3 - request->offset + len12;
319 i++;
323 if((request->operation & IO_CHUNKED)) {
324 int l;
325 const char *trailer;
326 if(request->operation & IO_END) {
327 if(len123 == 0) {
328 trailer = endChunkTrailer + 2;
329 l = 5;
330 } else {
331 trailer = endChunkTrailer;
332 l = 7;
334 } else {
335 trailer = endChunkTrailer;
336 l = 2;
339 if(request->offset <= len123) {
340 iov[i].iov_base = (char*)trailer;
341 iov[i].iov_len = l;
342 i++;
343 } else if(request->offset < len123 + l) {
344 iov[i].iov_base =
345 (char*)endChunkTrailer + request->offset - len123;
346 iov[i].iov_len = l - request->offset + len123;
347 i++;
351 assert(i > 0);
353 if((request->operation & IO_MASK) == IO_WRITE) {
354 if(i > 1)
355 rc = WRITEV(request->fd, iov, i);
356 else
357 rc = WRITE(request->fd, iov[0].iov_base, iov[0].iov_len);
358 } else {
359 if(i > 1)
360 rc = READV(request->fd, iov, i);
361 else
362 rc = READ(request->fd, iov[0].iov_base, iov[0].iov_len);
365 if(rc > 0) {
366 request->offset += rc;
367 if(request->offset < 0) return 0;
368 done = request->handler(0, event, request);
369 return done;
370 } else if(rc == 0 || errno == EPIPE) {
371 done = request->handler(1, event, request);
372 } else if(errno == EAGAIN || errno == EINTR) {
373 return 0;
374 } else if(errno == EFAULT || errno == EBADF) {
375 abort();
376 } else {
377 done = request->handler(-errno, event, request);
379 assert(done);
380 return done;
384 streamRequestDone(StreamRequestPtr request)
386 int len123 =
387 request->len + request->len2 +
388 ((request->operation & IO_BUF3) ? request->u.b.len3 : 0);
390 if(request->offset < 0)
391 return 0;
392 else if(request->offset < len123)
393 return 0;
394 else if(request->operation & IO_CHUNKED) {
395 if(request->operation & IO_END) {
396 if(request->offset < len123 + (len123 ? 7 : 5))
397 return 0;
398 } else {
399 if(request->offset < len123 + 2)
400 return 0;
404 return 1;
407 static int
408 serverSocket(int af)
410 int fd, rc;
411 if(af == 4) {
412 fd = socket(PF_INET, SOCK_STREAM, 0);
413 } else if(af == 6) {
414 #ifdef HAVE_IPv6
415 fd = socket(PF_INET6, SOCK_STREAM, 0);
416 #else
417 fd = -1;
418 errno = EAFNOSUPPORT;
419 #endif
420 } else {
421 abort();
424 if(fd >= 0) {
425 rc = setNonblocking(fd, 1);
426 if(rc < 0) {
427 int errno_save = errno;
428 CLOSE(fd);
429 errno = errno_save;
430 return -1;
432 #ifdef HAVE_IPV6_PREFER_TEMPADDR
433 if (af == 6 && useTemporarySourceAddress != 1) {
434 int value;
435 value = (useTemporarySourceAddress == 2) ? 1 : 0;
436 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
437 &value, sizeof(value));
438 if (rc < 0) {
439 /* no error, warning only */
440 do_log_error(L_WARN, errno, "Couldn't set IPV6CTL_USETEMPADDR");
444 #endif
446 return fd;
449 FdEventHandlerPtr
450 do_connect(AtomPtr addr, int index, int port,
451 int (*handler)(int, FdEventHandlerPtr, ConnectRequestPtr),
452 void *data)
454 ConnectRequestRec request;
455 FdEventHandlerPtr event;
456 int done, fd, af;
458 assert(addr->length > 0 && addr->string[0] == DNS_A);
459 assert(addr->length % sizeof(HostAddressRec) == 1);
461 if(index >= (addr->length - 1)/ sizeof(HostAddressRec))
462 index = 0;
464 request.firstindex = index;
465 request.port = port;
466 request.handler = handler;
467 request.data = data;
468 again:
469 af = addr->string[1 + index * sizeof(HostAddressRec)];
470 fd = serverSocket(af);
472 request.fd = fd;
473 request.af = af;
474 request.addr = addr;
475 request.index = index;
477 if(fd < 0) {
478 int n = (addr->length - 1) / sizeof(HostAddressRec);
479 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
480 if((index + 1) % n != request.firstindex) {
481 index = (index + 1) % n;
482 goto again;
485 do_log_error(L_ERROR, errno, "Couldn't create socket");
486 done = (*handler)(-errno, NULL, &request);
487 assert(done);
488 return NULL;
491 /* POLLIN is apparently needed on Windows */
492 event = registerFdEvent(fd, POLLIN | POLLOUT,
493 do_scheduled_connect,
494 sizeof(ConnectRequestRec), &request);
495 if(event == NULL) {
496 done = (*handler)(-ENOMEM, NULL, &request);
497 assert(done);
498 return NULL;
501 done = event->handler(0, event);
502 if(done) {
503 unregisterFdEvent(event);
504 return NULL;
506 return event;
510 do_scheduled_connect(int status, FdEventHandlerPtr event)
512 ConnectRequestPtr request = (ConnectRequestPtr)&event->data;
513 AtomPtr addr = request->addr;
514 int done;
515 int rc;
516 HostAddressPtr host;
517 struct sockaddr_in servaddr;
518 #ifdef HAVE_IPv6
519 struct sockaddr_in6 servaddr6;
520 #endif
522 assert(addr->length > 0 && addr->string[0] == DNS_A);
523 assert(addr->length % sizeof(HostAddressRec) == 1);
524 assert(request->index < (addr->length - 1) / sizeof(HostAddressRec));
526 if(status) {
527 done = request->handler(status, event, request);
528 if(done) {
529 releaseAtom(addr);
530 request->addr = NULL;
531 return 1;
533 return 0;
536 again:
537 host = (HostAddressPtr)&addr->string[1 +
538 request->index *
539 sizeof(HostAddressRec)];
540 if(host->af != request->af) {
541 int newfd;
542 /* Ouch. Our socket has a different protocol than the host
543 address. */
544 CLOSE(request->fd);
545 newfd = serverSocket(host->af);
546 if(newfd < 0) {
547 if(errno == EAFNOSUPPORT || errno == EPROTONOSUPPORT) {
548 int n = request->addr->length / sizeof(HostAddressRec);
549 if((request->index + 1) % n != request->firstindex) {
550 request->index = (request->index + 1) % n;
551 goto again;
554 request->fd = -1;
555 done = request->handler(-errno, event, request);
556 assert(done);
557 return 1;
559 if(newfd != request->fd) {
560 request->fd = dup2(newfd, request->fd);
561 CLOSE(newfd);
562 if(request->fd < 0) {
563 done = request->handler(-errno, event, request);
564 assert(done);
565 return 1;
568 request->af = host->af;
570 switch(host->af) {
571 case 4:
572 memset(&servaddr, 0, sizeof(servaddr));
573 servaddr.sin_family = AF_INET;
574 servaddr.sin_port = htons(request->port);
575 memcpy(&servaddr.sin_addr, &host->data, sizeof(struct in_addr));
576 rc = connect(request->fd,
577 (struct sockaddr*)&servaddr, sizeof(servaddr));
578 break;
579 case 6:
580 #ifdef HAVE_IPv6
581 memset(&servaddr6, 0, sizeof(servaddr6));
582 servaddr6.sin6_family = AF_INET6;
583 servaddr6.sin6_port = htons(request->port);
584 memcpy(&servaddr6.sin6_addr, &host->data, sizeof(struct in6_addr));
585 rc = connect(request->fd,
586 (struct sockaddr*)&servaddr6, sizeof(servaddr6));
587 #else
588 rc = -1;
589 errno = EAFNOSUPPORT;
590 #endif
591 break;
592 default:
593 abort();
596 if(rc >= 0 || errno == EISCONN) {
597 done = request->handler(1, event, request);
598 assert(done);
599 releaseAtom(request->addr);
600 request->addr = NULL;
601 return 1;
604 if(errno == EINPROGRESS || errno == EINTR) {
605 return 0;
606 } else if(errno == EFAULT || errno == EBADF) {
607 abort();
608 } else {
609 int n = request->addr->length / sizeof(HostAddressRec);
610 if((request->index + 1) % n != request->firstindex) {
611 request->index = (request->index + 1) % n;
612 goto again;
614 done = request->handler(-errno, event, request);
615 assert(done);
616 releaseAtom(request->addr);
617 request->addr = NULL;
618 return 1;
622 FdEventHandlerPtr
623 do_accept(int fd,
624 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
625 void *data)
627 FdEventHandlerPtr event;
628 int done;
630 event = schedule_accept(fd, handler, data);
631 if(event == NULL) {
632 done = (*handler)(-ENOMEM, NULL, NULL);
633 assert(done);
636 /* But don't invoke it now - this will delay accept if under load. */
637 return event;
640 FdEventHandlerPtr
641 schedule_accept(int fd,
642 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
643 void *data)
645 FdEventHandlerPtr event;
646 AcceptRequestRec request;
647 int done;
649 request.fd = fd;
650 request.handler = handler;
651 request.data = data;
652 event = registerFdEvent(fd, POLLOUT|POLLIN,
653 do_scheduled_accept, sizeof(request), &request);
654 if(!event) {
655 done = (*handler)(-ENOMEM, NULL, NULL);
656 assert(done);
658 return event;
662 do_scheduled_accept(int status, FdEventHandlerPtr event)
664 AcceptRequestPtr request = (AcceptRequestPtr)&event->data;
665 int rc, done;
666 unsigned len;
667 struct sockaddr_in addr;
669 if(status) {
670 done = request->handler(status, event, request);
671 if(done) return done;
674 len = sizeof(struct sockaddr_in);
676 rc = accept(request->fd, (struct sockaddr*)&addr, &len);
678 if(rc >= 0)
679 done = request->handler(rc, event, request);
680 else
681 done = request->handler(-errno, event, request);
682 return done;
685 FdEventHandlerPtr
686 create_listener(char *address, int port,
687 int (*handler)(int, FdEventHandlerPtr, AcceptRequestPtr),
688 void *data)
690 int fd, rc;
691 int one = 1;
692 int done;
693 struct sockaddr_in addr;
694 #ifdef HAVE_IPv6
695 int inet6 = 1;
696 struct sockaddr_in6 addr6;
697 #else
698 int inet6 = 0;
699 #endif
701 if(inet6 && address) {
702 struct in_addr buf;
703 rc = inet_aton(address, &buf);
704 if(rc == 1)
705 inet6 = 0;
707 fd = -1;
708 errno = EAFNOSUPPORT;
710 #ifdef HAVE_IPv6
711 if(inet6) {
712 fd = socket(PF_INET6, SOCK_STREAM, 0);
714 #endif
716 if(fd < 0 && (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT)) {
717 inet6 = 0;
718 fd = socket(PF_INET, SOCK_STREAM, 0);
721 if(fd < 0) {
722 done = (*handler)(-errno, NULL, NULL);
723 assert(done);
724 return NULL;
727 rc = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one));
728 if(rc < 0) do_log_error(L_WARN, errno, "Couldn't set SO_REUSEADDR");
730 if(inet6) {
731 #ifdef HAVE_IPv6
732 rc = setV6only(fd, 0);
733 if(rc < 0)
734 /* Reportedly OpenBSD returns an error for that. So only
735 log it as a debugging message. */
736 do_log_error(D_CLIENT_CONN, errno, "Couldn't reset IPV6_V6ONLY");
738 memset(&addr6, 0, sizeof(addr6));
739 rc = inet_pton(AF_INET6, address, &addr6.sin6_addr);
740 if(rc != 1) {
741 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
742 assert(done);
743 return NULL;
745 addr6.sin6_family = AF_INET6;
746 addr6.sin6_port = htons(port);
747 rc = bind(fd, (struct sockaddr*)&addr6, sizeof(addr6));
748 #else
749 rc = -1;
750 errno = EAFNOSUPPORT;
751 #endif
752 } else {
753 memset(&addr, 0, sizeof(addr));
754 rc = inet_aton(address, &addr.sin_addr);
755 if(rc != 1) {
756 done = (*handler)(rc == 0 ? -ESYNTAX : -errno, NULL, NULL);
757 assert(done);
758 return NULL;
760 addr.sin_family = AF_INET;
761 addr.sin_port = htons(port);
762 rc = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
765 if(rc < 0) {
766 do_log_error(L_ERROR, errno, "Couldn't bind");
767 CLOSE(fd);
768 done = (*handler)(-errno, NULL, NULL);
769 assert(done);
770 return NULL;
773 rc = setNonblocking(fd, 1);
774 if(rc < 0) {
775 do_log_error(L_ERROR, errno, "Couldn't set non blocking mode");
776 CLOSE(fd);
777 done = (*handler)(-errno, NULL, NULL);
778 assert(done);
779 return NULL;
782 rc = listen(fd, 1024);
783 if(rc < 0) {
784 do_log_error(L_ERROR, errno, "Couldn't listen");
785 CLOSE(fd);
786 done = (*handler)(-errno, NULL, NULL);
787 assert(done);
788 return NULL;
791 do_log(L_INFO, "Established listening socket on port %d.\n", port);
793 return schedule_accept(fd, handler, data);
796 #ifndef SOL_TCP
797 /* BSD */
798 #define SOL_TCP IPPROTO_TCP
799 #endif
802 setNonblocking(int fd, int nonblocking)
804 #ifdef MINGW
805 return mingw_setnonblocking(fd, nonblocking);
806 #else
807 int rc;
808 rc = fcntl(fd, F_GETFL, 0);
809 if(rc < 0)
810 return -1;
812 rc = fcntl(fd, F_SETFL, nonblocking?(rc | O_NONBLOCK):(rc & ~O_NONBLOCK));
813 if(rc < 0)
814 return -1;
816 return 0;
817 #endif
821 setNodelay(int fd, int nodelay)
823 int val = nodelay ? 1 : 0;
824 int rc;
825 rc = setsockopt(fd, SOL_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
826 if(rc < 0)
827 return -1;
828 return 0;
831 #ifdef IPV6_V6ONLY
833 setV6only(int fd, int v6only)
835 int val = v6only ? 1 : 0;
836 int rc;
837 rc = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&val, sizeof(val));
838 if(rc < 0)
839 return -1;
840 return 0;
842 #else
844 setV6only(int fd, int v6only)
846 return 0;
848 #endif
850 typedef struct _LingeringClose {
851 int fd;
852 FdEventHandlerPtr handler;
853 TimeEventHandlerPtr timeout;
854 } LingeringCloseRec, *LingeringClosePtr;
856 static int
857 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event)
859 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
860 assert(l->timeout == event);
861 l->timeout = NULL;
862 if(l->handler)
863 pokeFdEvent(l->fd, -ESHUTDOWN, POLLIN | POLLOUT);
864 else {
865 CLOSE(l->fd);
866 free(l);
868 return 1;
871 static int
872 lingeringCloseHandler(int status, FdEventHandlerPtr event)
874 LingeringClosePtr l = *(LingeringClosePtr*)event->data;
875 char buf[17];
876 int rc;
878 assert(l->handler == event);
880 l->handler = NULL;
881 if(status && status != -EDOGRACEFUL)
882 goto done;
884 rc = READ(l->fd, &buf, 17);
885 if(rc == 0 || (rc < 0 && errno != EAGAIN && errno != EINTR))
886 goto done;
888 /* The client is still sending data. Ignore it in order to let
889 TCP's flow control do its work. The timeout will close the
890 connection. */
891 return 1;
893 done:
894 if(l->timeout) {
895 cancelTimeEvent(l->timeout);
896 l->timeout = NULL;
898 CLOSE(l->fd);
899 free(l);
900 return 1;
904 lingeringClose(int fd)
906 int rc;
907 LingeringClosePtr l;
909 rc = shutdown(fd, 1);
910 if(rc < 0) {
911 if(errno != ENOTCONN) {
912 do_log_error(L_ERROR, errno, "Shutdown failed");
913 } else if(errno == EFAULT || errno == EBADF) {
914 abort();
916 CLOSE(fd);
917 return 1;
920 l = malloc(sizeof(LingeringCloseRec));
921 if(l == NULL)
922 goto fail;
923 l->fd = fd;
924 l->handler = NULL;
925 l->timeout = NULL;
927 l->timeout = scheduleTimeEvent(10, lingeringCloseTimeoutHandler,
928 sizeof(LingeringClosePtr), &l);
929 if(l->timeout == NULL) {
930 free(l);
931 goto fail;
934 l->handler = registerFdEvent(fd, POLLIN,
935 lingeringCloseHandler,
936 sizeof(LingeringClosePtr), &l);
937 if(l->handler == NULL) {
938 do_log(L_ERROR, "Couldn't schedule lingering close handler.\n");
939 /* But don't close -- the timeout will do its work. */
941 return 1;
943 fail:
944 do_log(L_ERROR, "Couldn't schedule lingering close.\n");
945 CLOSE(fd);
946 return 1;
949 NetAddressPtr
950 parseNetAddress(AtomListPtr list)
952 NetAddressPtr nl;
953 int i, rc, rc6;
954 char buf[100];
955 struct in_addr ina;
956 #ifdef HAVE_IPv6
957 struct in6_addr ina6;
958 #endif
960 nl = malloc((list->length + 1) * sizeof(NetAddressRec));
961 if(nl == NULL) {
962 do_log(L_ERROR, "Couldn't allocate network list.\n");
963 return NULL;
966 for(i = 0; i < list->length; i++) {
967 int prefix;
968 char *s = list->list[i]->string, *p;
969 int n = list->list[i]->length;
970 char *suffix;
972 while(*s == ' ' || *s == '\t') {
973 s++;
974 n--;
977 if(n >= 100) {
978 do_log(L_ERROR, "Network name too long.\n");
979 goto fail;
981 p = memchr(s, '/', n);
982 if(p) {
983 memcpy(buf, s, p - s);
984 buf[p - s] = '\0';
985 prefix = strtol(p + 1, &suffix, 10);
986 } else {
987 char *s1, *s2;
988 prefix = -1;
989 strcpy(buf, s);
990 s1 = strchr(s, ' ');
991 s2 = strchr(s, '\t');
992 if(s1 == NULL) suffix = s2;
993 else if(s2 == NULL) suffix = s1;
994 else if(s1 < s2) suffix = s1;
995 else suffix = s2;
996 if(suffix == NULL)
997 suffix = s + n;
1000 if(!isWhitespace(suffix)) {
1001 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1002 goto fail;
1005 rc = 0; rc6 = 0;
1006 rc = inet_aton(buf, &ina);
1007 #ifdef HAVE_IPv6
1008 if(rc == 0) {
1009 rc6 = inet_pton(AF_INET6, buf, &ina6);
1011 #endif
1012 if(rc == 0 && rc6 == 0) {
1013 do_log(L_ERROR, "Couldn't parse network %s.\n", buf);
1014 goto fail;
1016 nl[i].prefix = prefix;
1017 if(rc) {
1018 nl[i].af = 4;
1019 memcpy(nl[i].data, &ina, 4);
1020 } else {
1021 #ifdef HAVE_IPv6
1022 nl[i].af = 6;
1023 memcpy(nl[i].data, &ina6, 16);
1024 #else
1025 abort();
1026 #endif
1029 nl[i].af = 0;
1030 return nl;
1032 fail:
1033 free(nl);
1034 return NULL;
1037 /* Returns 1 if the first n bits of a and b are equal */
1038 static int
1039 bitmatch(const unsigned char *a, const unsigned char *b, int n)
1041 if(n >= 8) {
1042 if(memcmp(a, b, n / 8) != 0)
1043 return 0;
1046 if(n % 8 != 0) {
1047 int mask = (~0) << (8 - n % 8);
1048 if((a[n / 8] & mask) != (b[n / 8] & mask))
1049 return 0;
1052 return 1;
1055 /* Returns 1 if the address in data is in list */
1056 static int
1057 match(int af, unsigned char *data, NetAddressPtr list)
1059 int i;
1060 #ifdef HAVE_IPv6
1061 static const unsigned char v6mapped[] =
1062 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1063 #endif
1065 i = 0;
1066 while(list[i].af != 0) {
1067 if(af == 4 && list[i].af == 4) {
1068 if(bitmatch(data, list[i].data,
1069 list[i].prefix >= 0 ? list[i].prefix : 32))
1070 return 1;
1071 #ifdef HAVE_IPv6
1072 } else if(af == 6 && list[i].af == 6) {
1073 if(bitmatch(data, list[i].data,
1074 list[i].prefix >= 0 ? list[i].prefix : 128))
1075 return 1;
1076 } else if(af == 6 && list[i].af == 4) {
1077 if(bitmatch(data, v6mapped, 96)) {
1078 if(bitmatch(data + 12, list[i].data,
1079 list[i].prefix >= 0 ? list[i].prefix : 32))
1080 return 1;
1082 } else if(af == 4 && list[i].af == 6) {
1083 if(bitmatch(list[i].data, v6mapped, 96)) {
1084 if(bitmatch(data, list[i].data + 12,
1085 list[i].prefix >= 96 ?
1086 list[i].prefix - 96 : 32))
1087 return 1;
1089 #endif
1090 } else {
1091 abort();
1093 i++;
1095 return 0;
1099 netAddressMatch(int fd, NetAddressPtr list)
1101 int rc;
1102 unsigned int len;
1103 struct sockaddr_in sain;
1104 #ifdef HAVE_IPv6
1105 struct sockaddr_in6 sain6;
1106 #endif
1108 len = sizeof(sain);
1109 rc = getpeername(fd, (struct sockaddr*)&sain, &len);
1110 if(rc < 0) {
1111 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1112 return -1;
1115 if(sain.sin_family == AF_INET) {
1116 return match(4, (unsigned char*)&sain.sin_addr, list);
1117 #ifdef HAVE_IPv6
1118 } else if(sain.sin_family == AF_INET6) {
1119 len = sizeof(sain6);
1120 rc = getpeername(fd, (struct sockaddr*)&sain6, &len);
1121 if(rc < 0) {
1122 do_log_error(L_ERROR, errno, "Couldn't get peer name");
1123 return -1;
1125 if(sain6.sin6_family != AF_INET6) {
1126 do_log(L_ERROR, "Inconsistent peer name");
1127 return -1;
1129 return match(6, (unsigned char*)&sain6.sin6_addr, list);
1130 #endif
1131 } else {
1132 do_log(L_ERROR, "Unknown address family %d\n", sain.sin_family);
1133 return -1;
1135 return 0;