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 return schedule_accept(fd
, handler
, data
);
767 #define SOL_TCP IPPROTO_TCP
771 setNonblocking(int fd
, int nonblocking
)
774 return mingw_setnonblocking(fd
, nonblocking
);
777 rc
= fcntl(fd
, F_GETFL
, 0);
781 rc
= fcntl(fd
, F_SETFL
, nonblocking
?(rc
| O_NONBLOCK
):(rc
& ~O_NONBLOCK
));
790 setNodelay(int fd
, int nodelay
)
792 int val
= nodelay
? 1 : 0;
794 rc
= setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, (char *)&val
, sizeof(val
));
802 setV6only(int fd
, int v6only
)
804 int val
= v6only
? 1 : 0;
806 rc
= setsockopt(fd
, IPPROTO_IPV6
, IPV6_V6ONLY
, (char *)&val
, sizeof(val
));
813 setV6only(int fd
, int v6only
)
819 typedef struct _LingeringClose
{
821 FdEventHandlerPtr handler
;
822 TimeEventHandlerPtr timeout
;
823 } LingeringCloseRec
, *LingeringClosePtr
;
826 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event
)
828 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
829 assert(l
->timeout
== event
);
832 pokeFdEvent(l
->fd
, -ESHUTDOWN
, POLLIN
| POLLOUT
);
841 lingeringCloseHandler(int status
, FdEventHandlerPtr event
)
843 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
847 assert(l
->handler
== event
);
850 if(status
&& status
!= -EDOGRACEFUL
)
853 rc
= READ(l
->fd
, &buf
, 17);
854 if(rc
== 0 || (rc
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
))
857 /* The client is still sending data. Ignore it in order to let
858 TCP's flow control do its work. The timeout will close the
864 cancelTimeEvent(l
->timeout
);
873 lingeringClose(int fd
)
878 rc
= shutdown(fd
, 1);
880 if(errno
!= ENOTCONN
) {
881 do_log_error(L_ERROR
, errno
, "Shutdown failed");
882 } else if(errno
== EFAULT
|| errno
== EBADF
) {
889 l
= malloc(sizeof(LingeringCloseRec
));
896 l
->timeout
= scheduleTimeEvent(10, lingeringCloseTimeoutHandler
,
897 sizeof(LingeringClosePtr
), &l
);
898 if(l
->timeout
== NULL
) {
903 l
->handler
= registerFdEvent(fd
, POLLIN
,
904 lingeringCloseHandler
,
905 sizeof(LingeringClosePtr
), &l
);
906 if(l
->handler
== NULL
) {
907 do_log(L_ERROR
, "Couldn't schedule lingering close handler.\n");
908 /* But don't close -- the timeout will do its work. */
913 do_log(L_ERROR
, "Couldn't schedule lingering close.\n");
919 parseNetAddress(AtomListPtr list
)
926 struct in6_addr ina6
;
929 nl
= malloc((list
->length
+ 1) * sizeof(NetAddressRec
));
931 do_log(L_ERROR
, "Couldn't allocate network list.\n");
935 for(i
= 0; i
< list
->length
; i
++) {
937 char *s
= list
->list
[i
]->string
, *p
;
938 int n
= list
->list
[i
]->length
;
941 while(*s
== ' ' || *s
== '\t') {
947 do_log(L_ERROR
, "Network name too long.\n");
950 p
= memchr(s
, '/', n
);
952 memcpy(buf
, s
, p
- s
);
954 prefix
= strtol(p
+ 1, &suffix
, 10);
960 s2
= strchr(s
, '\t');
961 if(s1
== NULL
) suffix
= s2
;
962 else if(s2
== NULL
) suffix
= s1
;
963 else if(s1
< s2
) suffix
= s1
;
969 if(!isWhitespace(suffix
)) {
970 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
975 rc
= inet_aton(buf
, &ina
);
978 rc6
= inet_pton(AF_INET6
, buf
, &ina6
);
981 if(rc
== 0 && rc6
== 0) {
982 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
985 nl
[i
].prefix
= prefix
;
988 memcpy(nl
[i
].data
, &ina
, 4);
992 memcpy(nl
[i
].data
, &ina6
, 16);
1006 /* Returns 1 if the first n bits of a and b are equal */
1008 bitmatch(const unsigned char *a
, const unsigned char *b
, int n
)
1011 if(memcmp(a
, b
, n
/ 8) != 0)
1016 int mask
= (~0) << (8 - n
% 8);
1017 if((a
[n
/ 8] & mask
) != (b
[n
/ 8] & mask
))
1024 /* Returns 1 if the address in data is in list */
1026 match(int af
, unsigned char *data
, NetAddressPtr list
)
1030 static const unsigned char v6mapped
[] =
1031 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
1035 while(list
[i
].af
!= 0) {
1036 if(af
== 4 && list
[i
].af
== 4) {
1037 if(bitmatch(data
, list
[i
].data
,
1038 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1041 } else if(af
== 6 && list
[i
].af
== 6) {
1042 if(bitmatch(data
, list
[i
].data
,
1043 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 128))
1045 } else if(af
== 6 && list
[i
].af
== 4) {
1046 if(bitmatch(data
, v6mapped
, 96)) {
1047 if(bitmatch(data
+ 12, list
[i
].data
,
1048 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
1051 } else if(af
== 4 && list
[i
].af
== 6) {
1052 if(bitmatch(list
[i
].data
, v6mapped
, 96)) {
1053 if(bitmatch(data
, list
[i
].data
+ 12,
1054 list
[i
].prefix
>= 96 ?
1055 list
[i
].prefix
- 96 : 32))
1068 netAddressMatch(int fd
, NetAddressPtr list
)
1072 struct sockaddr_in sain
;
1074 struct sockaddr_in6 sain6
;
1078 rc
= getpeername(fd
, (struct sockaddr
*)&sain
, &len
);
1080 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1084 if(sain
.sin_family
== AF_INET
) {
1085 return match(4, (unsigned char*)&sain
.sin_addr
, list
);
1087 } else if(sain
.sin_family
== AF_INET6
) {
1088 len
= sizeof(sain6
);
1089 rc
= getpeername(fd
, (struct sockaddr
*)&sain6
, &len
);
1091 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1094 if(sain6
.sin6_family
!= AF_INET6
) {
1095 do_log(L_ERROR
, "Inconsistent peer name");
1098 return match(6, (unsigned char*)&sain6
.sin6_addr
, list
);
1101 do_log(L_ERROR
, "Unknown address family %d\n", sain
.sin_family
);