OpenDNSSEC-signer 2.1.12
sock.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2011 NLNet Labs. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *
25 */
26
32#include "config.h"
33#include "daemon/engine.h"
34#include "log.h"
35#include "signer/zone.h"
36#include "wire/axfr.h"
37#include "wire/netio.h"
38#include "wire/sock.h"
39#include "wire/xfrd.h"
40
41#include <errno.h>
42#include <fcntl.h>
43#include <ldns/ldns.h>
44#include <unistd.h>
45
46#define SOCK_TCP_BACKLOG 5
47
48static const char* sock_str = "socket";
49
50
55static ods_status
56sock_fcntl_and_bind(sock_type* sock, const char* node, const char* port,
57 const char* stype, const char* fam)
58{
59 ods_log_assert(sock);
60 ods_log_assert(port);
61 ods_log_assert(stype);
62 ods_log_assert(fam);
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;
68 }
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;
77 }
78 return ODS_STATUS_OK;
79}
80
81
86static ods_status
87sock_v6only(sock_type* sock, const char* node, const char* port, int on,
88 const char* stype)
89{
90 ods_log_assert(sock);
91 ods_log_assert(port);
92 ods_log_assert(stype);
93#ifdef IPV6_V6ONLY
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;
102 }
103#endif
104#endif /* IPV6_V6ONLY */
105 return ODS_STATUS_OK;
106}
107
108
113static void
114sock_tcp_reuseaddr(sock_type* sock, const char* node, const char* port,
115 int on, const char* fam)
116{
117 ods_log_assert(sock);
118 ods_log_assert(port);
119 ods_log_assert(fam);
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));
124 }
125}
126
127
132static ods_status
133sock_tcp_listen(sock_type* sock, const char* node, const char* port,
134 const char* fam)
135{
136 ods_log_assert(sock);
137 ods_log_assert(port);
138 ods_log_assert(fam);
139 if (listen(sock->s, SOCK_TCP_BACKLOG) == -1) {
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;
144 }
145 return ODS_STATUS_OK;
146}
147
148
153static ods_status
154sock_server_udp(sock_type* sock, const char* node, const char* port,
155 unsigned* ip6_support)
156{
157 int on = 0;
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)
162 on = 1;
163#endif
164 *ip6_support = 1;
165 /* socket */
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,
171 strerror(errno));
172 if (sock->addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
173 *ip6_support = 0;
174 }
175 return ODS_STATUS_SOCK_SOCKET_UDP;
176 }
177 /* ipv4 */
178 if (sock->addr->ai_family == AF_INET) {
179 status = sock_fcntl_and_bind(sock, node, port, "udp", "ipv4");
180 }
181 /* ipv6 */
182 else if (sock->addr->ai_family == AF_INET6) {
183 status = sock_v6only(sock, node, port, on, "udp");
184 if (status != ODS_STATUS_OK) {
185 return status;
186 }
187 status = sock_fcntl_and_bind(sock, node, port, "udp", "ipv6");
188 }
189 return status;
190}
191
192
197static ods_status
198sock_server_tcp(sock_type* sock, const char* node, const char* port,
199 unsigned* ip6_support)
200{
201 int on = 0;
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)
206 on = 1;
207#endif
208 *ip6_support = 1;
209 /* socket */
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,
215 strerror(errno));
216 if (sock->addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
217 *ip6_support = 0;
218 }
219 return ODS_STATUS_SOCK_SOCKET_TCP;
220 }
221 /* ipv4 */
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");
227 }
228 }
229 /* ipv6 */
230 else if (sock->addr->ai_family == AF_INET6) {
231 status = sock_v6only(sock, node, port, on, "tcp");
232 if (status != ODS_STATUS_OK) {
233 return status;
234 }
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");
239 }
240 }
241 return status;
242}
243
244
249static ods_status
250socket_listen(sock_type* sock, struct addrinfo hints, int socktype,
251 const char* node, const char* port, unsigned* ip6_support)
252{
253 ods_status status = ODS_STATUS_OK;
254 int r = 0;
255 ods_log_assert(sock);
256 ods_log_assert(port);
257 *ip6_support = 1;
258 hints.ai_socktype = socktype;
259 /* getaddrinfo */
260 if ((r = getaddrinfo(node, port, &hints, &sock->addr)) != 0 ||
261 !sock->addr) {
262 ods_log_error("[%s] unable to parse address '%s:%s': getaddrinfo() "
263 "failed (%s %s)", sock_str, node?node:"localhost", port,
264 gai_strerror(r),
265#ifdef EAI_SYSTEM
266 r==EAI_SYSTEM?(char*)strerror(errno):"");
267#else
268 "");
269#endif
270 if (hints.ai_family == AF_INET6 && r==EAFNOSUPPORT) {
271 *ip6_support = 0;
272 }
273 return ODS_STATUS_SOCK_GETADDRINFO;
274 }
275 /* socket */
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);
280 }
281 ods_log_debug("[%s] socket listening to %s:%s", sock_str,
282 node?node:"localhost", port);
283 return status;
284}
285
286
291ods_status
293{
294 ods_status status = ODS_STATUS_OK;
295 struct addrinfo hints[MAX_INTERFACES];
296 const char* node = NULL;
297 const char* port = NULL;
298 size_t i = 0;
299 unsigned ip6_support = 1;
300
301 if (!sockets || !listener) {
302 return ODS_STATUS_ASSERT_ERR;
303 }
304 /* Initialize values */
305 for (i = 0; i < MAX_INTERFACES; i++) {
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;
311 }
312 /* Walk interfaces */
313 for (i=0; i < listener->count; i++) {
314 node = NULL;
315 if (strlen(listener->interfaces[i].address) > 0) {
316 node = listener->interfaces[i].address;
317 }
318 port = DNS_PORT_STRING;
319 if (listener->interfaces[i].port) {
320 port = listener->interfaces[i].port;
321 }
322 if (node != NULL) {
323 hints[i].ai_flags |= AI_NUMERICHOST;
324 } else {
325 hints[i].ai_family = listener->interfaces[i].family;
326 }
327 /* udp */
328 status = socket_listen(&sockets->udp[i], hints[i], SOCK_DGRAM,
329 node, port, &ip6_support);
330 if (status != ODS_STATUS_OK) {
331 if (!ip6_support) {
332 ods_log_warning("[%s] fallback to udp/ipv4, no udp/ipv6: "
333 "not supported", sock_str);
334 status = ODS_STATUS_OK;
335 } else {
336 return status;
337 }
338 }
339 /* tcp */
340 status = socket_listen(&sockets->tcp[i], hints[i], SOCK_STREAM,
341 node, port, &ip6_support);
342 if (status != ODS_STATUS_OK) {
343 if (!ip6_support) {
344 ods_log_warning("[%s] fallback to udp/ipv4, no udp/ipv6: "
345 "not supported", sock_str);
346 status = ODS_STATUS_OK;
347 } else {
348 return status;
349 }
350 }
351
352 }
353 /* All ok */
354 return ODS_STATUS_OK;
355}
356
357
362static void
363send_udp(struct udp_data* data, query_type* q)
364{
365 ssize_t nb;
366 ods_log_deeebug("[%s] sending %d bytes over udp", sock_str,
367 (int)buffer_remaining(q->buffer));
368 nb = sendto(data->socket->s, buffer_begin(q->buffer),
370 (struct sockaddr*) &q->addr, q->addrlen);
371 if (nb == -1) {
372 ods_log_error("[%s] unable to send data over udp: sendto() failed "
373 "(%s)", sock_str, strerror(errno));
374 ods_log_debug("[%s] len=%lu", sock_str, (unsigned long)buffer_remaining(q->buffer));
375 } else if ((size_t) nb != buffer_remaining(q->buffer)) {
376 ods_log_error("[%s] unable to send data over udp: only sent %d of %d "
377 "octets", sock_str, (int)nb,
378 (int)buffer_remaining(q->buffer));
379 }
380}
381
382
387void
388sock_handle_udp(netio_type* ATTR_UNUSED(netio), netio_handler_type* handler,
389 netio_events_type event_types)
390{
391 struct udp_data* data = (struct udp_data*) handler->user_data;
392 int received = 0;
393 query_type* q = data->query;
395
396 if (!(event_types & NETIO_EVENT_READ)) {
397 return;
398 }
399 ods_log_debug("[%s] incoming udp message", sock_str);
401 received = recvfrom(handler->fd, buffer_begin(q->buffer),
402 buffer_remaining(q->buffer), 0, (struct sockaddr*) &q->addr,
403 &q->addrlen);
404 if (received < 1) {
405 if (errno != EAGAIN && errno != EINTR) {
406 ods_log_error("[%s] recvfrom() failed: %s", sock_str,
407 strerror(errno));
408 }
409 return;
410 }
411 buffer_skip(q->buffer, received);
413 qstate = query_process(q, data->engine);
414 if (qstate != QUERY_DISCARDED) {
415 ods_log_debug("[%s] query processed qstate=%d", sock_str, qstate);
416 query_add_optional(q, data->engine);
418 send_udp(data, q);
419 }
420}
421
422
427static void
428cleanup_tcp_handler(netio_type* netio, netio_handler_type* handler)
429{
430 struct tcp_data* data = (struct tcp_data*) handler->user_data;
431 netio_remove_handler(netio, handler);
432 close(handler->fd);
433 free(handler->timeout);
434 free(handler);
435 query_cleanup(data->query);
436 free(data);
437}
438
439
444void
446 netio_events_type event_types)
447{
448 struct tcp_accept_data* accept_data = (struct tcp_accept_data*)
449 handler->user_data;
450 int s = 0;
451 struct tcp_data* tcp_data = NULL;
452 netio_handler_type* tcp_handler = NULL;
453 struct sockaddr_storage addr;
454 socklen_t addrlen = 0;
455 if (!(event_types & NETIO_EVENT_READ)) {
456 return;
457 }
458 ods_log_debug("[%s] handle incoming tcp connection", sock_str);
459 addrlen = sizeof(addr);
460 s = accept(handler->fd, (struct sockaddr *) &addr, &addrlen);
461 if (s == -1) {
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));
465 }
466 return;
467 }
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));
471 close(s);
472 return;
473 }
474 /* create tcp handler data */
475 CHECKALLOC(tcp_data = (struct tcp_data*) malloc(sizeof(struct tcp_data)));
477 if (!tcp_data->query) {
478 ods_log_error("[%s] unable to handle incoming tcp connection: "
479 "query_create() failed", sock_str);
480 free(tcp_data);
481 close(s);
482 return;
483 }
484 tcp_data->engine = accept_data->engine;
486 accept_data->tcp_accept_handler_count;
490 memcpy(&tcp_data->query->addr, &addr, addrlen);
491 tcp_data->query->addrlen = addrlen;
492 CHECKALLOC(tcp_handler = (netio_handler_type*) malloc(sizeof(netio_handler_type)));
493 tcp_handler->fd = s;
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);
498 free(tcp_handler);
500 free(tcp_data);
501 close(s);
502 return;
503 }
504 tcp_handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
505 tcp_handler->timeout->tv_nsec = 0L;
506 timespec_add(tcp_handler->timeout, netio_current_time(netio));
507 tcp_handler->user_data = tcp_data;
508 tcp_handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT;
509 tcp_handler->event_handler = sock_handle_tcp_read;
510 netio_add_handler(netio, tcp_handler);
511}
512
513
518void
520 netio_events_type event_types)
521{
522 struct tcp_data* data = (struct tcp_data *) handler->user_data;
523 ssize_t received = 0;
525
526 if (event_types & NETIO_EVENT_TIMEOUT) {
527 cleanup_tcp_handler(netio, handler);
528 return;
529 }
530 ods_log_assert(event_types & NETIO_EVENT_READ);
531 ods_log_debug("[%s] incoming tcp message", sock_str);
532 if (data->bytes_transmitted == 0) {
533 ods_log_debug("[%s] TCP_READ: reset query", sock_str);
535 }
536 /* check if we received the leading packet length bytes yet. */
537 if (data->bytes_transmitted < sizeof(uint16_t)) {
538 received = read(handler->fd,
539 (char *) &data->query->tcplen + data->bytes_transmitted,
540 sizeof(uint16_t) - data->bytes_transmitted);
541 if (received == -1) {
542 if (errno == EAGAIN || errno == EINTR) {
543 /* read would block, wait until more data is available. */
544 return;
545 } else {
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);
549 return;
550 }
551 } else if (received == 0) {
552 cleanup_tcp_handler(netio, handler);
553 return;
554 }
555 data->bytes_transmitted += received;
556 ods_log_debug("[%s] TCP_READ: bytes transmitted %lu (received %lu)",
557 sock_str, (unsigned long)data->bytes_transmitted, (unsigned long)received);
558 if (data->bytes_transmitted < sizeof(uint16_t)) {
559 /* not done with the tcplen yet, wait for more. */
560 ods_log_debug("[%s] TCP_READ: bytes transmitted %lu, while "
561 "sizeof uint16_t %lu", sock_str, (unsigned long)data->bytes_transmitted,
562 (unsigned long)sizeof(uint16_t));
563 return;
564 }
565 ods_log_assert(data->bytes_transmitted == sizeof(uint16_t));
566 data->query->tcplen = ntohs(data->query->tcplen);
567 /* minimum query size is: 12 + 1 + 2 + 2:
568 * header size + root dname + qclass + qtype */
569 if (data->query->tcplen < 17) {
570 ods_log_warning("[%s] unable to handle incoming tcp query: "
571 "packet too small", sock_str);
572 cleanup_tcp_handler(netio, handler);
573 return;
574 }
575 if (data->query->tcplen > data->query->maxlen) {
576 ods_log_warning("[%s] unable to handle incoming tcp query: "
577 "insufficient tcp buffer", sock_str);
578 cleanup_tcp_handler(netio, handler);
579 return;
580 }
581 buffer_set_limit(data->query->buffer, data->query->tcplen);
582 }
583 ods_log_assert(buffer_remaining(data->query->buffer) > 0);
584 /* read the (remaining) query data. */
585 received = read(handler->fd, buffer_current(data->query->buffer),
587 if (received == -1) {
588 if (errno == EAGAIN || errno == EINTR) {
589 /* read would block, wait until more data is available. */
590 return;
591 } else {
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);
595 return;
596 }
597 } else if (received == 0) {
598 cleanup_tcp_handler(netio, handler);
599 return;
600 }
601 data->bytes_transmitted += received;
602 ods_log_debug("[%s] TCP_READ: bytes transmitted %lu (received %lu)",
603 sock_str, (unsigned long)data->bytes_transmitted, (unsigned long)received);
604
605 buffer_skip(data->query->buffer, received);
606 if (buffer_remaining(data->query->buffer) > 0) {
607 /* not done with message yet, wait for more. */
608 ods_log_debug("[%s] TCP_READ: remaining %lu", sock_str,
609 (unsigned long)buffer_remaining(data->query->buffer));
610 return;
611 }
612 ods_log_assert(buffer_position(data->query->buffer) ==
613 data->query->tcplen);
614 /* we have a complete query, process it. */
615 buffer_flip(data->query->buffer);
616 qstate = query_process(data->query, data->engine);
617 if (qstate == QUERY_DISCARDED) {
618 cleanup_tcp_handler(netio, handler);
619 return;
620 }
621 ods_log_debug("[%s] query processed qstate=%d", sock_str, qstate);
622 data->qstate = qstate;
623 /* edns, tsig */
624 query_add_optional(data->query, data->engine);
625 /* switch to tcp write handler. */
626 buffer_flip(data->query->buffer);
627 data->query->tcplen = buffer_remaining(data->query->buffer);
628 ods_log_debug("[%s] TCP_READ: new tcplen %u", sock_str,
629 data->query->tcplen);
630 data->bytes_transmitted = 0;
631 handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
632 handler->timeout->tv_nsec = 0L;
633 timespec_add(handler->timeout, netio_current_time(netio));
636}
637
638
643void
645 netio_events_type event_types)
646{
647 struct tcp_data* data = (struct tcp_data *) handler->user_data;
648 ssize_t sent = 0;
649 query_type* q = data->query;
650
651 if (event_types & NETIO_EVENT_TIMEOUT) {
652 cleanup_tcp_handler(netio, handler);
653 return;
654 }
655 ods_log_assert(event_types & NETIO_EVENT_WRITE);
656
657 if (data->bytes_transmitted < sizeof(q->tcplen)) {
658 uint16_t n_tcplen = htons(q->tcplen);
659 sent = write(handler->fd,
660 (const char*) &n_tcplen + data->bytes_transmitted,
661 sizeof(n_tcplen) - data->bytes_transmitted);
662 if (sent == -1) {
663 if (errno == EAGAIN || errno == EINTR) {
664 /* write would block, wait until socket becomes writeable. */
665 return;
666 } else {
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);
670 return;
671 }
672 } else if (sent == 0) {
673 cleanup_tcp_handler(netio, handler);
674 return;
675 }
676 data->bytes_transmitted += sent;
677 ods_log_debug("[%s] TCP_WRITE: bytes transmitted %lu (sent %ld)",
678 sock_str, (unsigned long)data->bytes_transmitted, (long)sent);
679 if (data->bytes_transmitted < sizeof(q->tcplen)) {
680 /* writing not complete, wait until socket becomes writable. */
681 ods_log_debug("[%s] TCP_WRITE: bytes transmitted %lu, while "
682 "sizeof tcplen %lu", sock_str, (unsigned long)data->bytes_transmitted,
683 (unsigned long)sizeof(q->tcplen));
684 return;
685 }
686 ods_log_assert(data->bytes_transmitted == sizeof(q->tcplen));
687 }
688 ods_log_assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen));
689
690 sent = write(handler->fd, buffer_current(q->buffer),
692 if (sent == -1) {
693 if (errno == EAGAIN || errno == EINTR) {
694 /* write would block, wait until socket becomes writeable. */
695 return;
696 } else {
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);
700 return;
701 }
702 } else if (sent == 0) {
703 cleanup_tcp_handler(netio, handler);
704 return;
705 }
706
707 buffer_skip(q->buffer, sent);
708 data->bytes_transmitted += sent;
709 if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) {
710 /* still more data to write when socket becomes writable. */
711 ods_log_debug("[%s] TCP_WRITE: bytes transmitted %lu, while tcplen "
712 "%u and sizeof tcplen %lu", sock_str, (unsigned long) data->bytes_transmitted,
713 q->tcplen, (unsigned long)sizeof(q->tcplen));
714 return;
715 }
716
717 ods_log_debug("[%s] TCP_WRITE: bytes transmitted %lu",
718 sock_str, (unsigned long)data->bytes_transmitted);
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));
722 ods_log_assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen));
723 if (data->qstate == QUERY_AXFR || data->qstate == QUERY_IXFR) {
724 /* continue processing AXFR and writing back results. */
726 if (data->qstate == QUERY_IXFR) {
727 data->qstate = ixfr(q, data->engine);
728 } else {
729 data->qstate = axfr(q, data->engine, 0);
730 }
731 if (data->qstate != QUERY_PROCESSED) {
732 /* edns, tsig */
733 query_add_optional(q, data->engine);
736 data->bytes_transmitted = 0;
737 handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
738 handler->timeout->tv_nsec = 0L;
739 timespec_add(handler->timeout, netio_current_time(netio));
740 return;
741 }
742 }
743 /* done sending, wait for the next request. */
744 data->bytes_transmitted = 0;
745 handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
746 handler->timeout->tv_nsec = 0L;
747 timespec_add(handler->timeout, netio_current_time(netio));
750}
query_state ixfr(query_type *q, engine_type *engine)
Definition: axfr.c:389
query_state axfr(query_type *q, engine_type *engine, int fallback)
Definition: axfr.c:152
void buffer_clear(buffer_type *buffer)
Definition: buffer.c:99
uint8_t * buffer_current(buffer_type *buffer)
Definition: buffer.c:438
void buffer_set_limit(buffer_type *buffer, size_t limit)
Definition: buffer.c:385
uint8_t * buffer_begin(buffer_type *buffer)
Definition: buffer.c:426
void buffer_flip(buffer_type *buffer)
Definition: buffer.c:112
size_t buffer_position(buffer_type *buffer)
Definition: buffer.c:125
void buffer_skip(buffer_type *buffer, ssize_t count)
Definition: buffer.c:150
size_t buffer_remaining(buffer_type *buffer)
Definition: buffer.c:463
#define DNS_PORT_STRING
Definition: listener.h:51
#define MAX_INTERFACES
Definition: listener.h:53
const struct timespec * netio_current_time(netio_type *netio)
Definition: netio.c:163
void netio_remove_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:72
void timespec_add(struct timespec *left, const struct timespec *right)
Definition: netio.c:131
void netio_add_handler(netio_type *netio, netio_handler_type *handler)
Definition: netio.c:53
enum netio_events_enum netio_events_type
Definition: netio.h:76
@ NETIO_EVENT_WRITE
Definition: netio.h:72
@ NETIO_EVENT_TIMEOUT
Definition: netio.h:74
@ NETIO_EVENT_READ
Definition: netio.h:71
query_type * query_create(void)
Definition: query.c:48
void query_reset(query_type *q, size_t maxlen, int is_tcp)
Definition: query.c:80
void query_add_optional(query_type *q, engine_type *engine)
Definition: query.c:962
void query_cleanup(query_type *q)
Definition: query.c:1098
query_state query_process(query_type *q, engine_type *engine)
Definition: query.c:842
#define UDP_MAX_MESSAGE_LEN
Definition: query.h:42
#define TCP_MAX_MESSAGE_LEN
Definition: query.h:43
@ QUERY_IXFR
Definition: query.h:50
@ QUERY_AXFR
Definition: query.h:49
@ QUERY_DISCARDED
Definition: query.h:48
@ QUERY_PROCESSED
Definition: query.h:47
enum query_enum query_state
Definition: query.h:52
void sock_handle_udp(netio_type *ATTR_UNUSED(netio), netio_handler_type *handler, netio_events_type event_types)
Definition: sock.c:388
#define SOCK_TCP_BACKLOG
Definition: sock.c:46
void sock_handle_tcp_write(netio_type *netio, netio_handler_type *handler, netio_events_type event_types)
Definition: sock.c:644
void sock_handle_tcp_accept(netio_type *netio, netio_handler_type *handler, netio_events_type event_types)
Definition: sock.c:445
ods_status sock_listen(socklist_type *sockets, listener_type *listener)
Definition: sock.c:292
void sock_handle_tcp_read(netio_type *netio, netio_handler_type *handler, netio_events_type event_types)
Definition: sock.c:519
char * address
Definition: listener.h:71
size_t count
Definition: listener.h:83
interface_type * interfaces
Definition: listener.h:82
struct timespec * timeout
Definition: netio.h:115
netio_events_type event_types
Definition: netio.h:124
netio_event_handler_type event_handler
Definition: netio.h:131
void * user_data
Definition: netio.h:119
size_t maxlen
Definition: query.h:64
buffer_type * buffer
Definition: query.h:73
struct sockaddr_storage addr
Definition: query.h:61
uint16_t tcplen
Definition: query.h:72
socklen_t addrlen
Definition: query.h:62
struct addrinfo * addr
Definition: sock.h:47
int s
Definition: sock.h:48
sock_type udp[MAX_INTERFACES]
Definition: sock.h:58
sock_type tcp[MAX_INTERFACES]
Definition: sock.h:57
netio_handler_type * tcp_accept_handlers
Definition: sock.h:79
size_t tcp_accept_handler_count
Definition: sock.h:78
engine_type * engine
Definition: sock.h:76
Definition: sock.h:86
size_t bytes_transmitted
Definition: sock.h:92
query_type * query
Definition: sock.h:88
query_state qstate
Definition: sock.h:91
size_t tcp_accept_handler_count
Definition: sock.h:89
netio_handler_type * tcp_accept_handlers
Definition: sock.h:90
engine_type * engine
Definition: sock.h:87
Definition: sock.h:65
query_type * query
Definition: sock.h:68
engine_type * engine
Definition: sock.h:66
sock_type * socket
Definition: sock.h:67
#define XFRD_TCP_TIMEOUT
Definition: xfrd.h:68