43 #include <ldns/ldns.h>
46 #define SOCK_TCP_BACKLOG 5
48 static const char* sock_str =
"socket";
56 sock_fcntl_and_bind(
sock_type* sock,
const char* node,
const char* port,
57 const char* stype,
const char* fam)
61 ods_log_assert(stype);
63 if (fcntl(sock->
s, F_SETFL, O_NONBLOCK) == -1) {
64 ods_log_error(
"[%s] unable to set %s/%s socket '%s:%s' to "
65 "non-blocking: fcntl() failed (%s)", sock_str, stype, fam,
66 node?node:
"localhost", port, strerror(errno));
67 return ODS_STATUS_SOCK_FCNTL_NONBLOCK;
69 ods_log_debug(
"[%s] bind %s/%s socket '%s:%s': %s", sock_str, stype, fam,
70 node?node:
"localhost", port, strerror(errno));
71 if (bind(sock->
s, (
struct sockaddr *) sock->
addr->ai_addr,
72 sock->
addr->ai_addrlen) != 0) {
73 ods_log_error(
"[%s] unable to bind %s/%s socket '%s:%s': bind() "
74 "failed (%s)", sock_str, stype, fam, node?node:
"localhost",
75 port, strerror(errno));
76 return ODS_STATUS_SOCK_BIND;
87 sock_v6only(
sock_type* sock,
const char* node,
const char* port,
int on,
92 ods_log_assert(stype);
94 #if defined(IPPROTO_IPV6)
95 ods_log_debug(
"[%s] set %s/ipv6 socket '%s:%s' v6only", sock_str,
96 stype, node?node:
"localhost", port);
97 if (setsockopt(sock->
s, IPPROTO_IPV6, IPV6_V6ONLY, &on,
sizeof(on)) < 0) {
98 ods_log_error(
"[%s] unable to set %s/ipv6 socket '%s:%s' to "
99 "ipv6-only: setsockopt() failed (%s)", sock_str, stype,
100 node?node:
"localhost", port, strerror(errno));
101 return ODS_STATUS_SOCK_SETSOCKOPT_V6ONLY;
105 return ODS_STATUS_OK;
114 sock_tcp_reuseaddr(
sock_type* sock,
const char* node,
const char* port,
115 int on,
const char* fam)
117 ods_log_assert(sock);
118 ods_log_assert(port);
120 if (setsockopt(sock->
s, SOL_SOCKET, SO_REUSEADDR, &on,
sizeof(on)) < 0) {
121 ods_log_error(
"[%s] unable to set tcp/%s socket '%s:%s' to "
122 "reuse-addr: setsockopt() failed (%s)", sock_str, fam,
123 node?node:
"localhost", port, strerror(errno));
133 sock_tcp_listen(
sock_type* sock,
const char* node,
const char* port,
136 ods_log_assert(sock);
137 ods_log_assert(port);
140 ods_log_error(
"[%s] unable to listen on tcp/%s socket '%s:%s': "
141 "listen() failed (%s)", sock_str, fam, node?node:
"localhost",
142 port, strerror(errno));
143 return ODS_STATUS_SOCK_LISTEN;
145 return ODS_STATUS_OK;
154 sock_server_udp(
sock_type* sock,
const char* node,
const char* port,
155 unsigned* ip6_support)
158 ods_status status = ODS_STATUS_OK;
159 ods_log_assert(sock);
160 ods_log_assert(port);
161 #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
166 ods_log_debug(
"[%s] create udp socket '%s:%s': %s", sock_str,
167 node?node:
"localhost", port, strerror(errno));
168 if ((sock->
s = socket(sock->
addr->ai_family, SOCK_DGRAM, 0))== -1) {
169 ods_log_error(
"[%s] unable to create udp/ipv4 socket '%s:%s': "
170 "socket() failed (%s)", sock_str, node?node:
"localhost", port,
172 if (sock->
addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
175 return ODS_STATUS_SOCK_SOCKET_UDP;
178 if (sock->
addr->ai_family == AF_INET) {
179 status = sock_fcntl_and_bind(sock, node, port,
"udp",
"ipv4");
182 else if (sock->
addr->ai_family == AF_INET6) {
183 status = sock_v6only(sock, node, port, on,
"udp");
184 if (status != ODS_STATUS_OK) {
187 status = sock_fcntl_and_bind(sock, node, port,
"udp",
"ipv6");
198 sock_server_tcp(
sock_type* sock,
const char* node,
const char* port,
199 unsigned* ip6_support)
202 ods_status status = ODS_STATUS_OK;
203 ods_log_assert(sock);
204 ods_log_assert(port);
205 #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
210 ods_log_debug(
"[%s] create tcp socket '%s:%s': %s", sock_str,
211 node?node:
"localhost", port, strerror(errno));
212 if ((sock->
s = socket(sock->
addr->ai_family, SOCK_STREAM, 0))== -1) {
213 ods_log_error(
"[%s] unable to create tcp/ipv4 socket '%s:%s': "
214 "socket() failed (%s)", sock_str, node?node:
"localhost", port,
216 if (sock->
addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
219 return ODS_STATUS_SOCK_SOCKET_TCP;
222 if (sock->
addr->ai_family == AF_INET) {
223 sock_tcp_reuseaddr(sock, node, port, on,
"ipv4");
224 status = sock_fcntl_and_bind(sock, node, port,
"tcp",
"ipv4");
225 if (status == ODS_STATUS_OK) {
226 status = sock_tcp_listen(sock, node, port,
"ipv4");
230 else if (sock->
addr->ai_family == AF_INET6) {
231 status = sock_v6only(sock, node, port, on,
"tcp");
232 if (status != ODS_STATUS_OK) {
235 sock_tcp_reuseaddr(sock, node, port, on,
"ipv6");
236 status = sock_fcntl_and_bind(sock, node, port,
"tcp",
"ipv6");
237 if (status == ODS_STATUS_OK) {
238 status = sock_tcp_listen(sock, node, port,
"ipv6");
250 socket_listen(
sock_type* sock,
struct addrinfo hints,
int socktype,
251 const char* node,
const char* port,
unsigned* ip6_support)
253 ods_status status = ODS_STATUS_OK;
255 ods_log_assert(sock);
256 ods_log_assert(port);
258 hints.ai_socktype = socktype;
260 if ((r = getaddrinfo(node, port, &hints, &sock->
addr)) != 0 ||
262 ods_log_error(
"[%s] unable to parse address '%s:%s': getaddrinfo() "
263 "failed (%s %s)", sock_str, node?node:
"localhost", port,
266 r==EAI_SYSTEM?(
char*)strerror(errno):
"");
270 if (hints.ai_family == AF_INET6 && r==EAFNOSUPPORT) {
273 return ODS_STATUS_SOCK_GETADDRINFO;
276 if (socktype == SOCK_DGRAM) {
277 status = sock_server_udp(sock, node, port, ip6_support);
278 }
else if (socktype == SOCK_STREAM) {
279 status = sock_server_tcp(sock, node, port, ip6_support);
281 ods_log_debug(
"[%s] socket listening to %s:%s", sock_str,
282 node?node:
"localhost", port);
294 ods_status status = ODS_STATUS_OK;
296 const char* node = NULL;
297 const char* port = NULL;
299 unsigned ip6_support = 1;
301 if (!sockets || !listener) {
302 return ODS_STATUS_ASSERT_ERR;
306 memset(&hints[i], 0,
sizeof(hints[i]));
307 hints[i].ai_family = AF_UNSPEC;
308 hints[i].ai_flags = AI_PASSIVE;
309 sockets->
udp[i].
s = -1;
310 sockets->
tcp[i].
s = -1;
313 for (i=0; i < listener->
count; i++) {
323 hints[i].ai_flags |= AI_NUMERICHOST;
328 status = socket_listen(&sockets->
udp[i], hints[i], SOCK_DGRAM,
329 node, port, &ip6_support);
330 if (status != ODS_STATUS_OK) {
332 ods_log_warning(
"[%s] fallback to udp/ipv4, no udp/ipv6: "
333 "not supported", sock_str);
334 status = ODS_STATUS_OK;
340 status = socket_listen(&sockets->
tcp[i], hints[i], SOCK_STREAM,
341 node, port, &ip6_support);
342 if (status != ODS_STATUS_OK) {
344 ods_log_warning(
"[%s] fallback to udp/ipv4, no udp/ipv6: "
345 "not supported", sock_str);
346 status = ODS_STATUS_OK;
354 return ODS_STATUS_OK;
366 ods_log_deeebug(
"[%s] sending %d bytes over udp", sock_str,
372 ods_log_error(
"[%s] unable to send data over udp: sendto() failed "
373 "(%s)", sock_str, strerror(errno));
376 ods_log_error(
"[%s] unable to send data over udp: only sent %d of %d "
377 "octets", sock_str, (
int)nb,
399 ods_log_debug(
"[%s] incoming udp message", sock_str);
405 if (errno != EAGAIN && errno != EINTR) {
406 ods_log_error(
"[%s] recvfrom() failed: %s", sock_str,
415 ods_log_debug(
"[%s] query processed qstate=%d", sock_str, qstate);
453 struct sockaddr_storage addr;
454 socklen_t addrlen = 0;
458 ods_log_debug(
"[%s] handle incoming tcp connection", sock_str);
459 addrlen =
sizeof(addr);
460 s = accept(handler->
fd, (
struct sockaddr *) &addr, &addrlen);
462 if (errno != EINTR && errno != EWOULDBLOCK) {
463 ods_log_error(
"[%s] unable to handle incoming tcp connection: "
464 "accept() failed (%s)", sock_str, strerror(errno));
468 if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
469 ods_log_error(
"[%s] unable to handle incoming tcp connection: "
470 "fcntl() failed: %s", sock_str, strerror(errno));
478 ods_log_error(
"[%s] unable to handle incoming tcp connection: "
479 "query_create() failed", sock_str);
494 CHECKALLOC(tcp_handler->timeout = (
struct timespec*) malloc(
sizeof(
struct timespec)));
495 if (!tcp_handler->timeout) {
496 ods_log_error(
"[%s] unable to handle incoming tcp connection: "
497 "allocator_alloc() timeout failed", sock_str);
505 tcp_handler->timeout->tv_nsec = 0L;
523 ssize_t received = 0;
527 cleanup_tcp_handler(netio, handler);
531 ods_log_debug(
"[%s] incoming tcp message", sock_str);
533 ods_log_debug(
"[%s] TCP_READ: reset query", sock_str);
538 received = read(handler->
fd,
541 if (received == -1) {
542 if (errno == EAGAIN || errno == EINTR) {
546 ods_log_error(
"[%s] unable to handle incoming tcp query: "
547 "read() failed (%s)", sock_str, strerror(errno));
548 cleanup_tcp_handler(netio, handler);
551 }
else if (received == 0) {
552 cleanup_tcp_handler(netio, handler);
556 ods_log_debug(
"[%s] TCP_READ: bytes transmitted %lu (received %lu)",
560 ods_log_debug(
"[%s] TCP_READ: bytes transmitted %lu, while "
562 (
unsigned long)
sizeof(uint16_t));
570 ods_log_warning(
"[%s] unable to handle incoming tcp query: "
571 "packet too small", sock_str);
572 cleanup_tcp_handler(netio, handler);
576 ods_log_warning(
"[%s] unable to handle incoming tcp query: "
577 "insufficient tcp buffer", sock_str);
578 cleanup_tcp_handler(netio, handler);
587 if (received == -1) {
588 if (errno == EAGAIN || errno == EINTR) {
592 ods_log_error(
"[%s] unable to handle incoming tcp query: "
593 "read() failed (%s)", sock_str, strerror(errno));
594 cleanup_tcp_handler(netio, handler);
597 }
else if (received == 0) {
598 cleanup_tcp_handler(netio, handler);
602 ods_log_debug(
"[%s] TCP_READ: bytes transmitted %lu (received %lu)",
608 ods_log_debug(
"[%s] TCP_READ: remaining %lu", sock_str,
618 cleanup_tcp_handler(netio, handler);
621 ods_log_debug(
"[%s] query processed qstate=%d", sock_str,
qstate);
628 ods_log_debug(
"[%s] TCP_READ: new tcplen %u", sock_str,
632 handler->
timeout->tv_nsec = 0L;
652 cleanup_tcp_handler(netio, handler);
658 uint16_t n_tcplen = htons(q->
tcplen);
659 sent = write(handler->
fd,
663 if (errno == EAGAIN || errno == EINTR) {
667 ods_log_error(
"[%s] unable to handle outgoing tcp response: "
668 "write() failed (%s)", sock_str, strerror(errno));
669 cleanup_tcp_handler(netio, handler);
672 }
else if (sent == 0) {
673 cleanup_tcp_handler(netio, handler);
677 ods_log_debug(
"[%s] TCP_WRITE: bytes transmitted %lu (sent %ld)",
681 ods_log_debug(
"[%s] TCP_WRITE: bytes transmitted %lu, while "
683 (
unsigned long)
sizeof(q->
tcplen));
693 if (errno == EAGAIN || errno == EINTR) {
697 ods_log_error(
"[%s] unable to handle outgoing tcp response: "
698 "write() failed (%s)", sock_str, strerror(errno));
699 cleanup_tcp_handler(netio, handler);
702 }
else if (sent == 0) {
703 cleanup_tcp_handler(netio, handler);
711 ods_log_debug(
"[%s] TCP_WRITE: bytes transmitted %lu, while tcplen "
717 ods_log_debug(
"[%s] TCP_WRITE: bytes transmitted %lu",
719 ods_log_debug(
"[%s] TCP_WRITE: tcplen %u", sock_str, q->
tcplen);
720 ods_log_debug(
"[%s] TCP_WRITE: sizeof tcplen %lu", sock_str,
721 (
unsigned long)
sizeof(q->
tcplen));
738 handler->
timeout->tv_nsec = 0L;
746 handler->
timeout->tv_nsec = 0L;