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
29 /* Load the winsock dll */
31 WORD wVersionRequested
= MAKEWORD(2, 2);
32 int err
= WSAStartup( wVersionRequested
, &wsaData
);
34 do_log_error(L_ERROR
, err
, "Couldn't load winsock dll");
48 do_stream(int operation
, int fd
, int offset
, char *buf
, int len
,
49 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
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
,
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
),
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
,
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
),
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
,
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
),
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
,
95 do_stream_buf(int operation
, int fd
, int offset
, char **buf_location
, int len
,
96 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
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
,
108 chunkHeaderLen(int i
)
125 chunkHeader(char *buf
, int buflen
, int i
)
130 n
= snprintf(buf
, buflen
, "%x\r\n", i
);
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
,
140 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
143 StreamRequestRec request
;
144 FdEventHandlerPtr event
;
147 request
.operation
= operation
;
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
) {
156 request
.u
.l
.buf_location
= buf_location
;
157 request
.operation
|= IO_BUF_LOCATION
;
159 request
.u
.h
.hlen
= hlen
;
160 request
.u
.h
.header
= header
;
166 if((operation
& IO_CHUNKED
) ||
167 (!(request
.operation
& (IO_BUF3
| IO_BUF_LOCATION
)) && hlen
> 0)) {
169 request
.offset
= -hlen
;
170 if(operation
& IO_CHUNKED
)
171 request
.offset
+= -chunkHeaderLen(len
+ len2
);
173 request
.offset
= offset
;
175 request
.handler
= handler
;
177 event
= makeFdEvent(fd
,
178 (operation
& IO_MASK
) == IO_WRITE
?
181 sizeof(StreamRequestRec
), &request
);
183 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
188 if(!(operation
& IO_NOTNOW
)) {
189 done
= event
->handler(0, event
);
196 if(operation
& IO_IMMEDIATE
) {
197 assert(hlen
== 0 && !(operation
& IO_CHUNKED
));
198 done
= (*handler
)(0, event
, &request
);
204 event
= registerFdEventHelper(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
;
216 int chunk_header_len
, chunk_trailer_len
;
217 char chunk_header
[10];
218 int len12
= request
->len
+ request
->len2
;
220 request
->len
+ request
->len2
+
221 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
224 done
= request
->handler(status
, event
, request
);
230 if(request
->offset
< 0) {
231 assert((request
->operation
& (IO_MASK
| IO_BUF3
| IO_BUF_LOCATION
)) ==
233 if(request
->operation
& IO_CHUNKED
) {
234 chunk_header_len
= chunkHeaderLen(len123
);
235 chunk_trailer_len
= 2;
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
;
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
;
254 iov
[i
].iov_base
= chunk_header
+
255 chunk_header_len
+ request
->offset
;
256 iov
[i
].iov_len
= -request
->offset
;
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
);
272 if(request
->offset
<= 0) {
273 iov
[i
].iov_base
= request
->buf
;
274 iov
[i
].iov_len
= request
->len
;
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
;
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
;
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
;
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
;
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
;
307 if((request
->operation
& IO_CHUNKED
)) {
310 if(request
->operation
& IO_END
) {
312 trailer
= endChunkTrailer
+ 2;
315 trailer
= endChunkTrailer
;
319 trailer
= endChunkTrailer
;
323 if(request
->offset
<= len123
) {
324 iov
[i
].iov_base
= (char*)trailer
;
327 } else if(request
->offset
< len123
+ l
) {
329 (char*)endChunkTrailer
+ request
->offset
- len123
;
330 iov
[i
].iov_len
= l
- request
->offset
+ len123
;
337 if((request
->operation
& IO_MASK
) == IO_WRITE
) {
339 rc
= WRITEV(request
->fd
, iov
, i
);
341 rc
= WRITE(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
344 rc
= READV(request
->fd
, iov
, i
);
346 rc
= READ(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
350 request
->offset
+= rc
;
351 if(request
->offset
< 0) return 0;
352 done
= request
->handler(0, event
, request
);
354 } else if(rc
== 0 || errno
== EPIPE
) {
355 done
= request
->handler(1, event
, request
);
356 } else if(errno
== EAGAIN
|| errno
== EINTR
) {
358 } else if(errno
== EFAULT
|| errno
== EBADF
) {
361 done
= request
->handler(-errno
, event
, request
);
368 streamRequestDone(StreamRequestPtr request
)
371 request
->len
+ request
->len2
+
372 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
374 if(request
->offset
< 0)
376 else if(request
->offset
< len123
)
378 else if(request
->operation
& IO_CHUNKED
) {
379 if(request
->operation
& IO_END
) {
380 if(request
->offset
< len123
+ (len123
? 7 : 5))
383 if(request
->offset
< len123
+ 2)
396 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
399 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
402 errno
= EAFNOSUPPORT
;
409 rc
= setNonblocking(fd
, 1);
411 int errno_save
= errno
;
421 do_connect(AtomPtr addr
, int index
, int port
,
422 int (*handler
)(int, FdEventHandlerPtr
, ConnectRequestPtr
),
425 ConnectRequestRec request
;
426 FdEventHandlerPtr event
;
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
))
435 request
.firstindex
= index
;
437 request
.handler
= handler
;
440 af
= addr
->string
[1 + index
* sizeof(HostAddressRec
)];
441 fd
= serverSocket(af
);
446 request
.index
= index
;
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
;
456 do_log_error(L_ERROR
, errno
, "Couldn't create socket");
457 done
= (*handler
)(-errno
, NULL
, &request
);
462 /* POLLIN is apparently needed on Windows */
463 event
= registerFdEvent(fd
, POLLIN
| POLLOUT
,
464 do_scheduled_connect
,
465 sizeof(ConnectRequestRec
), &request
);
467 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
472 done
= event
->handler(0, event
);
474 unregisterFdEvent(event
);
481 do_scheduled_connect(int status
, FdEventHandlerPtr event
)
483 ConnectRequestPtr request
= (ConnectRequestPtr
)&event
->data
;
484 AtomPtr addr
= request
->addr
;
488 struct sockaddr_in servaddr
;
490 struct sockaddr_in6 servaddr6
;
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
));
498 done
= request
->handler(status
, event
, request
);
501 request
->addr
= NULL
;
508 host
= (HostAddressPtr
)&addr
->string
[1 +
510 sizeof(HostAddressRec
)];
511 if(host
->af
!= request
->af
) {
513 /* Ouch. Our socket has a different protocol than the host
516 newfd
= serverSocket(host
->af
);
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
;
526 done
= request
->handler(-errno
, event
, request
);
530 if(newfd
!= request
->fd
) {
531 request
->fd
= dup2(newfd
, request
->fd
);
533 if(request
->fd
< 0) {
534 done
= request
->handler(-errno
, event
, request
);
539 request
->af
= host
->af
;
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
));
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
));
560 errno
= EAFNOSUPPORT
;
567 if(rc
>= 0 || errno
== EISCONN
) {
568 done
= request
->handler(1, event
, request
);
570 releaseAtom(request
->addr
);
571 request
->addr
= NULL
;
575 if(errno
== EINPROGRESS
|| errno
== EINTR
) {
577 } else if(errno
== EFAULT
|| errno
== EBADF
) {
580 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
581 if((request
->index
+ 1) % n
!= request
->firstindex
) {
582 request
->index
= (request
->index
+ 1) % n
;
585 done
= request
->handler(-errno
, event
, request
);
587 releaseAtom(request
->addr
);
588 request
->addr
= NULL
;
595 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
598 FdEventHandlerPtr event
;
601 event
= schedule_accept(fd
, handler
, data
);
603 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
607 /* But don't invoke it now - this will delay accept if under load. */
612 schedule_accept(int fd
,
613 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
616 FdEventHandlerPtr event
;
617 AcceptRequestRec request
;
621 request
.handler
= handler
;
623 event
= registerFdEvent(fd
, POLLOUT
|POLLIN
,
624 do_scheduled_accept
, sizeof(request
), &request
);
626 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
633 do_scheduled_accept(int status
, FdEventHandlerPtr event
)
635 AcceptRequestPtr request
= (AcceptRequestPtr
)&event
->data
;
638 struct sockaddr_in addr
;
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
);
650 done
= request
->handler(rc
, event
, request
);
652 done
= request
->handler(-errno
, event
, request
);
657 create_listener(char *address
, int port
,
658 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
664 struct sockaddr_in addr
;
667 struct sockaddr_in6 addr6
;
672 if(inet6
&& address
) {
674 rc
= inet_aton(address
, &buf
);
679 errno
= EAFNOSUPPORT
;
683 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
687 if(fd
< 0 && (errno
== EPROTONOSUPPORT
|| errno
== EAFNOSUPPORT
)) {
689 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
693 done
= (*handler
)(-errno
, NULL
, 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");
703 rc
= setV6only(fd
, 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
);
712 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
716 addr6
.sin6_family
= AF_INET6
;
717 addr6
.sin6_port
= htons(port
);
718 rc
= bind(fd
, (struct sockaddr
*)&addr6
, sizeof(addr6
));
721 errno
= EAFNOSUPPORT
;
724 memset(&addr
, 0, sizeof(addr
));
725 rc
= inet_aton(address
, &addr
.sin_addr
);
727 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
731 addr
.sin_family
= AF_INET
;
732 addr
.sin_port
= htons(port
);
733 rc
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
737 do_log_error(L_ERROR
, errno
, "Couldn't bind");
739 done
= (*handler
)(-errno
, NULL
, NULL
);
744 rc
= setNonblocking(fd
, 1);
746 do_log_error(L_ERROR
, errno
, "Couldn't set non blocking mode");
748 done
= (*handler
)(-errno
, NULL
, NULL
);
755 do_log_error(L_ERROR
, errno
, "Couldn't listen");
757 done
= (*handler
)(-errno
, NULL
, NULL
);
762 do_log(L_INFO
, "Established listening socket on port %d.\n", port
);
764 return schedule_accept(fd
, handler
, data
);
769 #define SOL_TCP IPPROTO_TCP
773 setNonblocking(int fd
, int nonblocking
)
776 return mingw_setnonblocking(fd
, nonblocking
);
779 rc
= fcntl(fd
, F_GETFL
, 0);
783 rc
= fcntl(fd
, F_SETFL
, nonblocking
?(rc
| O_NONBLOCK
):(rc
& ~O_NONBLOCK
));
792 setNodelay(int fd
, int nodelay
)
794 int val
= nodelay
? 1 : 0;
796 rc
= setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, (char *)&val
, sizeof(val
));
804 setV6only(int fd
, int v6only
)
806 int val
= v6only
? 1 : 0;
808 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
815 setV6only(int fd
, int v6only
)
821 typedef struct _LingeringClose
{
823 FdEventHandlerPtr handler
;
824 TimeEventHandlerPtr timeout
;
825 } LingeringCloseRec
, *LingeringClosePtr
;
828 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event
)
830 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
831 assert(l
->timeout
== event
);
834 pokeFdEvent(l
->fd
, -ESHUTDOWN
, POLLIN
| POLLOUT
);
843 lingeringCloseHandler(int status
, FdEventHandlerPtr event
)
845 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
849 assert(l
->handler
== event
);
852 if(status
&& status
!= -EDOGRACEFUL
)
855 rc
= READ(l
->fd
, &buf
, 17);
856 if(rc
== 0 || (rc
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
))
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
866 cancelTimeEvent(l
->timeout
);
875 lingeringClose(int fd
)
880 rc
= shutdown(fd
, 1);
882 if(errno
!= ENOTCONN
) {
883 do_log_error(L_ERROR
, errno
, "Shutdown failed");
884 } else if(errno
== EFAULT
|| errno
== EBADF
) {
891 l
= malloc(sizeof(LingeringCloseRec
));
898 l
->timeout
= scheduleTimeEvent(10, lingeringCloseTimeoutHandler
,
899 sizeof(LingeringClosePtr
), &l
);
900 if(l
->timeout
== NULL
) {
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. */
915 do_log(L_ERROR
, "Couldn't schedule lingering close.\n");
921 parseNetAddress(AtomListPtr list
)
928 struct in6_addr ina6
;
931 nl
= malloc((list
->length
+ 1) * sizeof(NetAddressRec
));
933 do_log(L_ERROR
, "Couldn't allocate network list.\n");
937 for(i
= 0; i
< list
->length
; i
++) {
939 char *s
= list
->list
[i
]->string
, *p
;
940 int n
= list
->list
[i
]->length
;
943 while(*s
== ' ' || *s
== '\t') {
949 do_log(L_ERROR
, "Network name too long.\n");
952 p
= memchr(s
, '/', n
);
954 memcpy(buf
, s
, p
- s
);
956 prefix
= strtol(p
+ 1, &suffix
, 10);
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
;
971 if(!isWhitespace(suffix
)) {
972 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
977 rc
= inet_aton(buf
, &ina
);
980 rc6
= inet_pton(AF_INET6
, buf
, &ina6
);
983 if(rc
== 0 && rc6
== 0) {
984 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
987 nl
[i
].prefix
= prefix
;
990 memcpy(nl
[i
].data
, &ina
, 4);
994 memcpy(nl
[i
].data
, &ina6
, 16);
1008 /* Returns 1 if the first n bits of a and b are equal */
1010 bitmatch(const unsigned char *a
, const unsigned char *b
, int n
)
1013 if(memcmp(a
, b
, n
/ 8) != 0)
1018 int mask
= (~0) << (8 - n
% 8);
1019 if((a
[n
/ 8] & mask
) != (b
[n
/ 8] & mask
))
1026 /* Returns 1 if the address in data is in list */
1028 match(int af
, unsigned char *data
, NetAddressPtr list
)
1032 static const unsigned char v6mapped
[] =
1033 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
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))
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))
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))
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))
1070 netAddressMatch(int fd
, NetAddressPtr list
)
1074 struct sockaddr_in sain
;
1076 struct sockaddr_in6 sain6
;
1080 rc
= getpeername(fd
, (struct sockaddr
*)&sain
, &len
);
1082 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1086 if(sain
.sin_family
== AF_INET
) {
1087 return match(4, (unsigned char*)&sain
.sin_addr
, list
);
1089 } else if(sain
.sin_family
== AF_INET6
) {
1090 len
= sizeof(sain6
);
1091 rc
= getpeername(fd
, (struct sockaddr
*)&sain6
, &len
);
1093 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1096 if(sain6
.sin6_family
!= AF_INET6
) {
1097 do_log(L_ERROR
, "Inconsistent peer name");
1100 return match(6, (unsigned char*)&sain6
.sin6_addr
, list
);
1103 do_log(L_ERROR
, "Unknown address family %d\n", sain
.sin_family
);