2 Copyright (c) 2003 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
38 do_stream(int operation
, int fd
, int offset
, char *buf
, int len
,
39 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
42 assert(len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
43 return schedule_stream(operation
, fd
, offset
,
44 NULL
, 0, buf
, len
, NULL
, 0, NULL
, 0, NULL
,
49 do_stream_2(int operation
, int fd
, int offset
,
50 char *buf
, int len
, char *buf2
, int len2
,
51 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
54 assert(len
+ len2
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
55 return schedule_stream(operation
, fd
, offset
,
56 NULL
, 0, buf
, len
, buf2
, len2
, NULL
, 0, NULL
,
61 do_stream_3(int operation
, int fd
, int offset
,
62 char *buf
, int len
, char *buf2
, int len2
, char *buf3
, int len3
,
63 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
66 assert(len
+ len2
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
67 return schedule_stream(operation
, fd
, offset
,
68 NULL
, 0, buf
, len
, buf2
, len2
, buf3
, len3
, NULL
,
73 do_stream_h(int operation
, int fd
, int offset
,
74 char *header
, int hlen
, char *buf
, int len
,
75 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
78 assert(hlen
+ len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)));
79 return schedule_stream(operation
, fd
, offset
,
80 header
, hlen
, buf
, len
, NULL
, 0, NULL
, 0, NULL
,
85 do_stream_buf(int operation
, int fd
, int offset
, char **buf_location
, int len
,
86 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
89 assert((len
> offset
|| (operation
& (IO_END
| IO_IMMEDIATE
)))
90 && len
<= CHUNK_SIZE
);
91 return schedule_stream(operation
, fd
, offset
,
92 NULL
, 0, *buf_location
, len
,
93 NULL
, 0, NULL
, 0, buf_location
,
115 chunkHeader(char *buf
, int buflen
, int i
)
120 n
= snprintf(buf
, buflen
, "%x\r\n", i
);
126 schedule_stream(int operation
, int fd
, int offset
,
127 char *header
, int hlen
,
128 char *buf
, int len
, char *buf2
, int len2
, char *buf3
, int len3
,
130 int (*handler
)(int, FdEventHandlerPtr
, StreamRequestPtr
),
133 StreamRequestRec request
;
134 FdEventHandlerPtr event
;
137 request
.operation
= operation
;
140 assert(hlen
== 0 && buf_location
== NULL
);
141 request
.u
.b
.len3
= len3
;
142 request
.u
.b
.buf3
= buf3
;
143 request
.operation
|= IO_BUF3
;
144 } else if(buf_location
) {
146 request
.u
.l
.buf_location
= buf_location
;
147 request
.operation
|= IO_BUF_LOCATION
;
149 request
.u
.h
.hlen
= hlen
;
150 request
.u
.h
.header
= header
;
156 if((operation
& IO_CHUNKED
) ||
157 (!(request
.operation
& (IO_BUF3
| IO_BUF_LOCATION
)) && hlen
> 0)) {
159 request
.offset
= -hlen
;
160 if(operation
& IO_CHUNKED
)
161 request
.offset
+= -chunkHeaderLen(len
+ len2
);
163 request
.offset
= offset
;
165 request
.handler
= handler
;
167 event
= makeFdEvent(fd
,
168 (operation
& IO_MASK
) == IO_WRITE
?
171 sizeof(StreamRequestRec
), &request
);
173 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
178 if(!(operation
& IO_NOTNOW
)) {
179 done
= event
->handler(0, event
);
186 if(operation
& IO_IMMEDIATE
) {
187 assert(hlen
== 0 && !(operation
& IO_CHUNKED
));
188 done
= (*handler
)(0, event
, &request
);
194 event
= registerFdEventHelper(event
);
198 static const char *endChunkTrailer
= "\r\n0\r\n\r\n";
201 do_scheduled_stream(int status
, FdEventHandlerPtr event
)
203 StreamRequestPtr request
= (StreamRequestPtr
)&event
->data
;
206 int chunk_header_len
, chunk_trailer_len
;
207 char chunk_header
[10];
208 int len12
= request
->len
+ request
->len2
;
210 request
->len
+ request
->len2
+
211 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
214 done
= request
->handler(status
, event
, request
);
220 if(request
->offset
< 0) {
221 assert((request
->operation
& (IO_MASK
| IO_BUF3
| IO_BUF_LOCATION
)) ==
223 if(request
->operation
& IO_CHUNKED
) {
224 chunk_header_len
= chunkHeaderLen(len123
);
225 chunk_trailer_len
= 2;
227 chunk_header_len
= 0;
228 chunk_trailer_len
= 0;
231 if(request
->offset
< -chunk_header_len
) {
232 assert(request
->offset
>= -(request
->u
.h
.hlen
+ chunk_header_len
));
233 iov
[i
].iov_base
= request
->u
.h
.header
;
234 iov
[i
].iov_len
= -request
->offset
- chunk_header_len
;
238 if(chunk_header_len
> 0) {
239 chunkHeader(chunk_header
, 10, len123
);
240 if(request
->offset
< -chunk_header_len
) {
241 iov
[i
].iov_base
= chunk_header
;
242 iov
[i
].iov_len
= chunk_header_len
;
244 iov
[i
].iov_base
= chunk_header
+
245 chunk_header_len
+ request
->offset
;
246 iov
[i
].iov_len
= -request
->offset
;
252 if(request
->len
> 0) {
253 if(request
->buf
== NULL
&&
254 (request
->operation
& IO_BUF_LOCATION
)) {
255 assert(*request
->u
.l
.buf_location
== NULL
);
256 request
->buf
= *request
->u
.l
.buf_location
= get_chunk();
257 if(request
->buf
== NULL
) {
258 done
= request
->handler(-ENOMEM
, event
, request
);
262 if(request
->offset
<= 0) {
263 iov
[i
].iov_base
= request
->buf
;
264 iov
[i
].iov_len
= request
->len
;
266 } else if(request
->offset
< request
->len
) {
267 iov
[i
].iov_base
= request
->buf
+ request
->offset
;
268 iov
[i
].iov_len
= request
->len
- request
->offset
;
273 if(request
->len2
> 0) {
274 if(request
->offset
<= request
->len
) {
275 iov
[i
].iov_base
= request
->buf2
;
276 iov
[i
].iov_len
= request
->len2
;
278 } else if(request
->offset
< request
->len
+ request
->len2
) {
279 iov
[i
].iov_base
= request
->buf2
+ request
->offset
- request
->len
;
280 iov
[i
].iov_len
= request
->len2
- request
->offset
+ request
->len
;
285 if((request
->operation
& IO_BUF3
) && request
->u
.b
.len3
> 0) {
286 if(request
->offset
<= len12
) {
287 iov
[i
].iov_base
= request
->u
.b
.buf3
;
288 iov
[i
].iov_len
= request
->u
.b
.len3
;
290 } else if(request
->offset
< len12
+ request
->u
.b
.len3
) {
291 iov
[i
].iov_base
= request
->u
.b
.buf3
+ request
->offset
- len12
;
292 iov
[i
].iov_len
= request
->u
.b
.len3
- request
->offset
+ len12
;
297 if((request
->operation
& IO_CHUNKED
)) {
300 if(request
->operation
& IO_END
) {
302 trailer
= endChunkTrailer
+ 2;
305 trailer
= endChunkTrailer
;
309 trailer
= endChunkTrailer
;
313 if(request
->offset
<= len123
) {
314 iov
[i
].iov_base
= (char*)trailer
;
317 } else if(request
->offset
< len123
+ l
) {
319 (char*)endChunkTrailer
+ request
->offset
- len123
;
320 iov
[i
].iov_len
= l
- request
->offset
+ len123
;
327 if((request
->operation
& IO_MASK
) == IO_WRITE
) {
329 rc
= writev(request
->fd
, iov
, i
);
331 rc
= write(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
334 rc
= readv(request
->fd
, iov
, i
);
336 rc
= read(request
->fd
, iov
[0].iov_base
, iov
[0].iov_len
);
340 request
->offset
+= rc
;
341 if(request
->offset
< 0) return 0;
342 done
= request
->handler(0, event
, request
);
344 } else if(rc
== 0 || errno
== EPIPE
) {
345 done
= request
->handler(1, event
, request
);
346 } else if(errno
== EAGAIN
|| errno
== EINTR
) {
348 } else if(errno
== EFAULT
|| errno
== EBADF
) {
351 done
= request
->handler(-errno
, event
, request
);
358 streamRequestDone(StreamRequestPtr request
)
361 request
->len
+ request
->len2
+
362 ((request
->operation
& IO_BUF3
) ? request
->u
.b
.len3
: 0);
364 if(request
->offset
< 0)
366 else if(request
->offset
< len123
)
368 else if(request
->operation
& IO_CHUNKED
) {
369 if(request
->operation
& IO_END
) {
370 if(request
->offset
< len123
+ (len123
? 7 : 5))
373 if(request
->offset
< len123
+ 2)
386 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
389 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
392 errno
= EAFNOSUPPORT
;
399 rc
= setNonblocking(fd
, 1);
401 int errno_save
= errno
;
411 do_connect(AtomPtr addr
, int index
, int port
,
412 int (*handler
)(int, FdEventHandlerPtr
, ConnectRequestPtr
),
415 ConnectRequestRec request
;
416 FdEventHandlerPtr event
;
419 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
420 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
422 if(index
>= (addr
->length
- 1)/ sizeof(HostAddressRec
))
425 request
.firstindex
= index
;
427 request
.handler
= handler
;
430 af
= addr
->string
[1 + index
* sizeof(HostAddressRec
)];
431 fd
= serverSocket(af
);
436 request
.index
= index
;
439 int n
= (addr
->length
- 1) / sizeof(HostAddressRec
);
440 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
441 if((index
+ 1) % n
!= request
.firstindex
) {
442 index
= (index
+ 1) % n
;
446 do_log_error(L_ERROR
, errno
, "Couldn't create socket");
447 done
= (*handler
)(-errno
, NULL
, &request
);
452 event
= registerFdEvent(fd
, POLLOUT
,
453 do_scheduled_connect
,
454 sizeof(ConnectRequestRec
), &request
);
456 done
= (*handler
)(-ENOMEM
, NULL
, &request
);
461 done
= event
->handler(0, event
);
463 unregisterFdEvent(event
);
470 do_scheduled_connect(int status
, FdEventHandlerPtr event
)
472 ConnectRequestPtr request
= (ConnectRequestPtr
)&event
->data
;
473 AtomPtr addr
= request
->addr
;
477 struct sockaddr_in servaddr
;
479 struct sockaddr_in6 servaddr6
;
482 assert(addr
->length
> 0 && addr
->string
[0] == DNS_A
);
483 assert(addr
->length
% sizeof(HostAddressRec
) == 1);
484 assert(request
->index
< (addr
->length
- 1) / sizeof(HostAddressRec
));
487 done
= request
->handler(status
, event
, request
);
490 request
->addr
= NULL
;
497 host
= (HostAddressPtr
)&addr
->string
[1 +
499 sizeof(HostAddressRec
)];
500 if(host
->af
!= request
->af
) {
502 /* Ouch. Our socket has a different protocol than the host
505 newfd
= serverSocket(host
->af
);
507 if(errno
== EAFNOSUPPORT
|| errno
== EPROTONOSUPPORT
) {
508 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
509 if((request
->index
+ 1) % n
!= request
->firstindex
) {
510 request
->index
= (request
->index
+ 1) % n
;
515 done
= request
->handler(-errno
, event
, request
);
519 if(newfd
!= request
->fd
) {
520 request
->fd
= dup2(newfd
, request
->fd
);
522 if(request
->fd
< 0) {
523 done
= request
->handler(-errno
, event
, request
);
528 request
->af
= host
->af
;
532 memset(&servaddr
, 0, sizeof(servaddr
));
533 servaddr
.sin_family
= AF_INET
;
534 servaddr
.sin_port
= htons(request
->port
);
535 memcpy(&servaddr
.sin_addr
, &host
->data
, sizeof(struct in_addr
));
536 rc
= connect(request
->fd
,
537 (struct sockaddr
*)&servaddr
, sizeof(servaddr
));
541 memset(&servaddr6
, 0, sizeof(servaddr6
));
542 servaddr6
.sin6_family
= AF_INET6
;
543 servaddr6
.sin6_port
= htons(request
->port
);
544 memcpy(&servaddr6
.sin6_addr
, &host
->data
, sizeof(struct in6_addr
));
545 rc
= connect(request
->fd
,
546 (struct sockaddr
*)&servaddr6
, sizeof(servaddr6
));
549 errno
= EAFNOSUPPORT
;
556 if(rc
>= 0 || errno
== EISCONN
) {
557 done
= request
->handler(1, event
, request
);
559 releaseAtom(request
->addr
);
560 request
->addr
= NULL
;
564 if(errno
== EINPROGRESS
|| errno
== EINTR
) {
566 } else if(errno
== EFAULT
|| errno
== EBADF
) {
569 int n
= request
->addr
->length
/ sizeof(HostAddressRec
);
570 if((request
->index
+ 1) % n
!= request
->firstindex
) {
571 request
->index
= (request
->index
+ 1) % n
;
574 done
= request
->handler(-errno
, event
, request
);
576 releaseAtom(request
->addr
);
577 request
->addr
= NULL
;
584 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
587 FdEventHandlerPtr event
;
590 event
= schedule_accept(fd
, handler
, data
);
592 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
596 /* But don't invoke it now - this will delay accept if under load. */
601 schedule_accept(int fd
,
602 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
605 FdEventHandlerPtr event
;
606 AcceptRequestRec request
;
610 request
.handler
= handler
;
612 event
= registerFdEvent(fd
, POLLOUT
|POLLIN
,
613 do_scheduled_accept
, sizeof(request
), &request
);
615 done
= (*handler
)(-ENOMEM
, NULL
, NULL
);
622 do_scheduled_accept(int status
, FdEventHandlerPtr event
)
624 AcceptRequestPtr request
= (AcceptRequestPtr
)&event
->data
;
627 struct sockaddr_in addr
;
630 done
= request
->handler(status
, event
, request
);
631 if(done
) return done
;
634 len
= sizeof(struct sockaddr_in
);
636 rc
= accept(request
->fd
, (struct sockaddr
*)&addr
, &len
);
639 done
= request
->handler(rc
, event
, request
);
641 done
= request
->handler(-errno
, event
, request
);
646 create_listener(char *address
, int port
,
647 int (*handler
)(int, FdEventHandlerPtr
, AcceptRequestPtr
),
653 struct sockaddr_in addr
;
656 struct sockaddr_in6 addr6
;
661 if(inet6
&& address
) {
663 rc
= inet_aton(address
, &buf
);
668 errno
= EAFNOSUPPORT
;
672 fd
= socket(PF_INET6
, SOCK_STREAM
, 0);
676 if(fd
< 0 && (errno
== EPROTONOSUPPORT
|| errno
== EAFNOSUPPORT
)) {
678 fd
= socket(PF_INET
, SOCK_STREAM
, 0);
682 done
= (*handler
)(-errno
, NULL
, NULL
);
687 rc
= setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *)&one
, sizeof(one
));
688 if(rc
< 0) do_log_error(L_WARN
, errno
, "Couldn't set SO_REUSEADDR");
692 memset(&addr6
, 0, sizeof(addr6
));
693 rc
= inet_pton(AF_INET6
, address
, &addr6
.sin6_addr
);
695 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
699 addr6
.sin6_family
= AF_INET6
;
700 addr6
.sin6_port
= htons(port
);
701 rc
= bind(fd
, (struct sockaddr
*)&addr6
, sizeof(addr6
));
704 errno
= EAFNOSUPPORT
;
707 memset(&addr
, 0, sizeof(addr
));
708 rc
= inet_aton(address
, &addr
.sin_addr
);
710 done
= (*handler
)(rc
== 0 ? -ESYNTAX
: -errno
, NULL
, NULL
);
714 addr
.sin_family
= AF_INET
;
715 addr
.sin_port
= htons(port
);
716 rc
= bind(fd
, (struct sockaddr
*)&addr
, sizeof(addr
));
720 do_log_error(L_ERROR
, errno
, "Couldn't bind");
722 done
= (*handler
)(-errno
, NULL
, NULL
);
727 rc
= setNonblocking(fd
, 1);
729 do_log_error(L_ERROR
, errno
, "Couldn't set non blocking mode");
731 done
= (*handler
)(-errno
, NULL
, NULL
);
738 do_log_error(L_ERROR
, errno
, "Couldn't listen");
740 done
= (*handler
)(-errno
, NULL
, NULL
);
745 return schedule_accept(fd
, handler
, data
);
749 setNonblocking(int fd
, int nonblocking
)
752 rc
= fcntl(fd
, F_GETFL
, 0);
756 rc
= fcntl(fd
, F_SETFL
, nonblocking
?(rc
| O_NONBLOCK
):(rc
& ~O_NONBLOCK
));
765 #define SOL_TCP IPPROTO_TCP
769 setNodelay(int fd
, int nodelay
)
771 int val
= nodelay
? 1 : 0;
773 rc
= setsockopt(fd
, SOL_TCP
, TCP_NODELAY
, (char *)&val
, sizeof(val
));
779 typedef struct _LingeringClose
{
781 FdEventHandlerPtr handler
;
782 TimeEventHandlerPtr timeout
;
783 } LingeringCloseRec
, *LingeringClosePtr
;
786 lingeringCloseTimeoutHandler(TimeEventHandlerPtr event
)
788 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
789 assert(l
->timeout
== event
);
792 pokeFdEvent(l
->fd
, -ESHUTDOWN
, POLLIN
| POLLOUT
);
801 lingeringCloseHandler(int status
, FdEventHandlerPtr event
)
803 LingeringClosePtr l
= *(LingeringClosePtr
*)event
->data
;
807 assert(l
->handler
== event
);
810 if(status
&& status
!= -EDOGRACEFUL
)
813 rc
= read(l
->fd
, &buf
, 17);
814 if(rc
== 0 || (rc
< 0 && errno
!= EAGAIN
&& errno
!= EINTR
))
817 /* The client is still sending data. Ignore it in order to let
818 TCP's flow control do its work. The timeout will close the
824 cancelTimeEvent(l
->timeout
);
833 lingeringClose(int fd
)
838 rc
= shutdown(fd
, 1);
840 if(errno
!= ENOTCONN
) {
841 do_log_error(L_ERROR
, errno
, "Shutdown failed");
842 } else if(errno
== EFAULT
|| errno
== EBADF
) {
849 l
= malloc(sizeof(LingeringCloseRec
));
856 l
->timeout
= scheduleTimeEvent(10, lingeringCloseTimeoutHandler
,
857 sizeof(LingeringClosePtr
), &l
);
858 if(l
->timeout
== NULL
) {
863 l
->handler
= registerFdEvent(fd
, POLLIN
,
864 lingeringCloseHandler
,
865 sizeof(LingeringClosePtr
), &l
);
866 if(l
->handler
== NULL
) {
867 do_log(L_ERROR
, "Couldn't schedule lingering close handler.\n");
868 /* But don't close -- the timeout will do its work. */
873 do_log(L_ERROR
, "Couldn't schedule lingering close.\n");
879 parseNetAddress(AtomListPtr list
)
886 struct in6_addr ina6
;
889 nl
= malloc((list
->length
+ 1) * sizeof(NetAddressRec
));
891 do_log(L_ERROR
, "Couldn't allocate network list.\n");
895 for(i
= 0; i
< list
->length
; i
++) {
897 char *s
= list
->list
[i
]->string
, *p
;
898 if(list
->list
[i
]->length
>= 100) {
899 do_log(L_ERROR
, "Network name too long.\n");
902 p
= memchr(s
, '/', list
->list
[i
]->length
);
904 memcpy(buf
, s
, p
- s
);
906 prefix
= atol(p
+ 1);
909 strcpy(buf
, list
->list
[i
]->string
);
913 rc
= inet_aton(buf
, &ina
);
916 rc6
= inet_pton(AF_INET6
, buf
, &ina6
);
919 if(rc
== 0 && rc6
== 0) {
920 do_log(L_ERROR
, "Couldn't parse network %s.\n", buf
);
923 nl
[i
].prefix
= prefix
;
926 memcpy(nl
[i
].data
, &ina
, 4);
930 memcpy(nl
[i
].data
, &ina6
, 16);
945 bitmatch(const unsigned char *a
, const unsigned char *b
, int n
)
948 if(memcmp(a
, b
, n
/ 8) != 0)
953 int mask
= (~0) << (8 - n
% 8);
954 if((a
[n
/ 8] & mask
) != (b
[n
/ 8] & mask
))
962 match(int af
, char *data
, NetAddressPtr list
)
966 static const char v6mapped
[] =
967 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF };
971 while(list
[i
].af
!= 0) {
972 if(af
== 4 && list
[i
].af
== 4) {
973 if(bitmatch(data
, list
[i
].data
,
974 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
977 } else if(af
== 6 && list
[i
].af
== 6) {
978 if(bitmatch(data
, list
[i
].data
,
979 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 128))
981 } else if(af
== 6 && list
[i
].af
== 4) {
982 if(bitmatch(data
, v6mapped
, 96)) {
983 if(bitmatch(data
+ 12, list
[i
].data
,
984 list
[i
].prefix
>= 0 ? list
[i
].prefix
: 32))
987 } else if(af
== 4 && list
[i
].af
== 6) {
988 if(bitmatch(list
[i
].data
, v6mapped
, 96)) {
989 if(bitmatch(data
, list
[i
].data
+ 12,
990 list
[i
].prefix
>= 96 ?
991 list
[i
].prefix
- 96 : 32))
1004 netAddressMatch(int fd
, NetAddressPtr list
)
1008 struct sockaddr_in sain
;
1010 struct sockaddr_in6 sain6
;
1014 rc
= getpeername(fd
, (struct sockaddr
*)&sain
, &len
);
1016 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1020 if(sain
.sin_family
== AF_INET
) {
1021 return match(4, (char*)&sain
.sin_addr
, list
);
1023 } else if(sain
.sin_family
== AF_INET6
) {
1024 len
= sizeof(sain6
);
1025 rc
= getpeername(fd
, (struct sockaddr
*)&sain6
, &len
);
1027 do_log_error(L_ERROR
, errno
, "Couldn't get peer name");
1030 if(sain6
.sin6_family
!= AF_INET6
) {
1031 do_log(L_ERROR
, "Inconsistent peer name");
1034 return match(6, (char*)&sain6
.sin6_addr
, list
);
1037 do_log(L_ERROR
, "Unknown address family %d\n", sain
.sin_family
);