OpenDNSSEC-signer  1.4.1
sock.c
Go to the documentation of this file.
1 /*
2  * $Id: sock.h 4958 2011-04-18 07:11:09Z matthijs $
3  *
4  * Copyright (c) 2011 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "daemon/engine.h"
36 #include "shared/log.h"
37 #include "signer/zone.h"
38 #include "wire/axfr.h"
39 #include "wire/netio.h"
40 #include "wire/sock.h"
41 #include "wire/xfrd.h"
42 
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <ldns/ldns.h>
46 #include <unistd.h>
47 
48 #define SOCK_TCP_BACKLOG 5
49 
50 static const char* sock_str = "socket";
51 
52 
57 static ods_status
58 sock_fcntl_and_bind(sock_type* sock, const char* node, const char* port,
59  const char* stype, const char* fam)
60 {
61  ods_log_assert(sock);
62  ods_log_assert(port);
63  ods_log_assert(stype);
64  ods_log_assert(fam);
65  if (fcntl(sock->s, F_SETFL, O_NONBLOCK) == -1) {
66  ods_log_error("[%s] unable to set %s/%s socket '%s:%s' to "
67  "non-blocking: fcntl() failed (%s)", sock_str, stype, fam,
68  node?node:"localhost", port, strerror(errno));
70  }
71  ods_log_debug("[%s] bind %s/%s socket '%s:%s'", sock_str, stype, fam,
72  node?node:"localhost", port, strerror(errno));
73  if (bind(sock->s, (struct sockaddr *) sock->addr->ai_addr,
74  sock->addr->ai_addrlen) != 0) {
75  ods_log_error("[%s] unable to bind %s/%s socket '%s:%s': bind() "
76  "failed (%s)", sock_str, stype, fam, node?node:"localhost",
77  port, strerror(errno));
78  return ODS_STATUS_SOCK_BIND;
79  }
80  return ODS_STATUS_OK;
81 }
82 
83 
88 static ods_status
89 sock_v6only(sock_type* sock, const char* node, const char* port, int on,
90  const char* stype)
91 {
92  ods_log_assert(sock);
93  ods_log_assert(port);
94  ods_log_assert(stype);
95 #ifdef IPV6_V6ONLY
96 #if defined(IPPROTO_IPV6)
97  ods_log_debug("[%s] set %s/ipv6 socket '%s:%s' v6only", sock_str,
98  stype, node?node:"localhost", port);
99  if (setsockopt(sock->s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0) {
100  ods_log_error("[%s] unable to set %s/ipv6 socket '%s:%s' to "
101  "ipv6-only: setsockopt() failed (%s)", sock_str, stype,
102  node?node:"localhost", port, strerror(errno));
104  }
105 #endif
106 #endif /* IPV6_V6ONLY */
107  return ODS_STATUS_OK;
108 }
109 
110 
115 static void
116 sock_tcp_reuseaddr(sock_type* sock, const char* node, const char* port,
117  int on, const char* fam)
118 {
119  ods_log_assert(sock);
120  ods_log_assert(port);
121  ods_log_assert(fam);
122  if (setsockopt(sock->s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
123  ods_log_error("[%s] unable to set tcp/%s socket '%s:%s' to "
124  "reuse-addr: setsockopt() failed (%s)", sock_str, fam,
125  node?node:"localhost", port, strerror(errno));
126  }
127  return;
128 }
129 
130 
135 static ods_status
136 sock_tcp_listen(sock_type* sock, const char* node, const char* port,
137  const char* fam)
138 {
139  ods_log_assert(sock);
140  ods_log_assert(port);
141  ods_log_assert(fam);
142  if (listen(sock->s, SOCK_TCP_BACKLOG) == -1) {
143  ods_log_error("[%s] unable to listen on tcp/%s socket '%s:%s': "
144  "listen() failed (%s)", sock_str, fam, node?node:"localhost",
145  port, strerror(errno));
146  return ODS_STATUS_SOCK_LISTEN;
147  }
148  return ODS_STATUS_OK;
149 }
150 
151 
156 static ods_status
157 sock_server_udp(sock_type* sock, const char* node, const char* port,
158  unsigned* ip6_support)
159 {
160  int on = 0;
161  ods_status status = ODS_STATUS_OK;
162  ods_log_assert(sock);
163  ods_log_assert(port);
164 #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
165  on = 1;
166 #endif
167  *ip6_support = 1;
168  /* socket */
169  ods_log_debug("[%s] create udp socket '%s:%s'", sock_str,
170  node?node:"localhost", port, strerror(errno));
171  if ((sock->s = socket(sock->addr->ai_family, SOCK_DGRAM, 0))== -1) {
172  ods_log_error("[%s] unable to create udp/ipv4 socket '%s:%s': "
173  "socket() failed (%s)", sock_str, node?node:"localhost", port,
174  strerror(errno));
175  if (sock->addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
176  *ip6_support = 0;
177  }
179  }
180  /* ipv4 */
181  if (sock->addr->ai_family == AF_INET) {
182  status = sock_fcntl_and_bind(sock, node, port, "udp", "ipv4");
183  }
184  /* ipv6 */
185  else if (sock->addr->ai_family == AF_INET6) {
186  status = sock_v6only(sock, node, port, on, "udp");
187  if (status != ODS_STATUS_OK) {
188  return status;
189  }
190  status = sock_fcntl_and_bind(sock, node, port, "udp", "ipv6");
191  }
192  return status;
193 }
194 
195 
200 static ods_status
201 sock_server_tcp(sock_type* sock, const char* node, const char* port,
202  unsigned* ip6_support)
203 {
204  int on = 0;
205  ods_status status = ODS_STATUS_OK;
206  ods_log_assert(sock);
207  ods_log_assert(port);
208 #if defined(SO_REUSEADDR) || defined(IPV6_V6ONLY)
209  on = 1;
210 #endif
211  *ip6_support = 1;
212  /* socket */
213  ods_log_debug("[%s] create tcp socket '%s:%s'", sock_str,
214  node?node:"localhost", port, strerror(errno));
215  if ((sock->s = socket(sock->addr->ai_family, SOCK_STREAM, 0))== -1) {
216  ods_log_error("[%s] unable to create tcp/ipv4 socket '%s:%s': "
217  "socket() failed (%s)", sock_str, node?node:"localhost", port,
218  strerror(errno));
219  if (sock->addr->ai_family == AF_INET6 && errno == EAFNOSUPPORT) {
220  *ip6_support = 0;
221  }
223  }
224  /* ipv4 */
225  if (sock->addr->ai_family == AF_INET) {
226  sock_tcp_reuseaddr(sock, node, port, on, "ipv4");
227  status = sock_fcntl_and_bind(sock, node, port, "tcp", "ipv4");
228  if (status == ODS_STATUS_OK) {
229  status = sock_tcp_listen(sock, node, port, "ipv4");
230  }
231  }
232  /* ipv6 */
233  else if (sock->addr->ai_family == AF_INET6) {
234  status = sock_v6only(sock, node, port, on, "tcp");
235  if (status != ODS_STATUS_OK) {
236  return status;
237  }
238  sock_tcp_reuseaddr(sock, node, port, on, "ipv6");
239  status = sock_fcntl_and_bind(sock, node, port, "tcp", "ipv6");
240  if (status == ODS_STATUS_OK) {
241  status = sock_tcp_listen(sock, node, port, "ipv6");
242  }
243  }
244  return status;
245 }
246 
247 
252 static ods_status
253 socket_listen(sock_type* sock, struct addrinfo hints, int socktype,
254  const char* node, const char* port, unsigned* ip6_support)
255 {
256  ods_status status = ODS_STATUS_OK;
257  int r = 0;
258  ods_log_assert(sock);
259  ods_log_assert(port);
260  *ip6_support = 1;
261  hints.ai_socktype = socktype;
262  /* getaddrinfo */
263  if ((r = getaddrinfo(node, port, &hints, &sock->addr)) != 0 ||
264  !sock->addr) {
265  ods_log_error("[%s] unable to parse address '%s:%s': getaddrinfo() "
266  "failed (%s %s)", sock_str, node?node:"localhost", port,
267  gai_strerror(r),
268 #ifdef EAI_SYSTEM
269  r==EAI_SYSTEM?(char*)strerror(errno):"");
270 #else
271  "");
272 #endif
273  if (hints.ai_family == AF_INET6 && r==EAFNOSUPPORT) {
274  *ip6_support = 0;
275  }
277  }
278  /* socket */
279  if (socktype == SOCK_DGRAM) {
280  status = sock_server_udp(sock, node, port, ip6_support);
281  } else if (socktype == SOCK_STREAM) {
282  status = sock_server_tcp(sock, node, port, ip6_support);
283  }
284  ods_log_debug("[%s] socket listening to %s:%s", sock_str,
285  node?node:"localhost", port);
286  return status;
287 }
288 
289 
296 {
297  ods_status status = ODS_STATUS_OK;
298  struct addrinfo hints[MAX_INTERFACES];
299  const char* node = NULL;
300  const char* port = NULL;
301  size_t i = 0;
302  unsigned ip6_support = 1;
303 
304  if (!sockets || !listener) {
305  return ODS_STATUS_ASSERT_ERR;
306  }
307  /* Initialize values */
308  for (i = 0; i < MAX_INTERFACES; i++) {
309  memset(&hints[i], 0, sizeof(hints[i]));
310  hints[i].ai_family = AF_UNSPEC;
311  hints[i].ai_flags = AI_PASSIVE;
312  sockets->udp[i].s = -1;
313  sockets->tcp[i].s = -1;
314  }
315  /* Walk interfaces */
316  for (i=0; i < listener->count; i++) {
317  node = NULL;
318  if (strlen(listener->interfaces[i].address) > 0) {
319  node = listener->interfaces[i].address;
320  }
321  port = DNS_PORT_STRING;
322  if (listener->interfaces[i].port) {
323  port = listener->interfaces[i].port;
324  }
325  if (node != NULL) {
326  hints[i].ai_flags |= AI_NUMERICHOST;
327  } else {
328  hints[i].ai_family = listener->interfaces[i].family;
329  }
330  /* udp */
331  status = socket_listen(&sockets->udp[i], hints[i], SOCK_DGRAM,
332  node, port, &ip6_support);
333  if (status != ODS_STATUS_OK) {
334  if (!ip6_support) {
335  ods_log_warning("[%s] fallback to udp/ipv4, no udp/ipv6: "
336  "not supported", sock_str);
337  status = ODS_STATUS_OK;
338  } else {
339  return status;
340  }
341  }
342  /* tcp */
343  status = socket_listen(&sockets->tcp[i], hints[i], SOCK_STREAM,
344  node, port, &ip6_support);
345  if (status != ODS_STATUS_OK) {
346  if (!ip6_support) {
347  ods_log_warning("[%s] fallback to udp/ipv4, no udp/ipv6: "
348  "not supported", sock_str);
349  status = ODS_STATUS_OK;
350  } else {
351  return status;
352  }
353  }
354 
355  }
356  /* All ok */
357  return ODS_STATUS_OK;
358 }
359 
360 
365 static void
366 send_udp(struct udp_data* data, query_type* q)
367 {
368  ssize_t nb;
369  ods_log_deeebug("[%s] sending %d bytes over udp", sock_str,
370  (int)buffer_remaining(q->buffer));
371  nb = sendto(data->socket->s, buffer_begin(q->buffer),
372  buffer_remaining(q->buffer), 0,
373  (struct sockaddr*) &q->addr, q->addrlen);
374  if (nb == -1) {
375  ods_log_error("[%s] unable to send data over udp: sendto() failed "
376  "(%s)", sock_str, strerror(errno));
377  ods_log_debug("[%s] len=%u", sock_str, buffer_remaining(q->buffer));
378  } else if ((size_t) nb != buffer_remaining(q->buffer)) {
379  ods_log_error("[%s] unable to send data over udp: only sent %d of %d "
380  "octets", sock_str, (int)nb,
381  (int)buffer_remaining(q->buffer));
382  }
383  return;
384 }
385 
386 
391 void
392 sock_handle_udp(netio_type* ATTR_UNUSED(netio), netio_handler_type* handler,
393  netio_events_type event_types)
394 {
395  struct udp_data* data = (struct udp_data*) handler->user_data;
396  int received = 0;
397  query_type* q = data->query;
398  query_state qstate = QUERY_PROCESSED;
399 
400  if (!(event_types & NETIO_EVENT_READ)) {
401  return;
402  }
403  ods_log_debug("[%s] incoming udp message", sock_str);
405  received = recvfrom(handler->fd, buffer_begin(q->buffer),
406  buffer_remaining(q->buffer), 0, (struct sockaddr*) &q->addr,
407  &q->addrlen);
408  if (received < 1) {
409  if (errno != EAGAIN && errno != EINTR) {
410  ods_log_error("[%s] recvfrom() failed: %s", sock_str,
411  strerror(errno));
412  }
413  return;
414  }
415  buffer_skip(q->buffer, received);
416  buffer_flip(q->buffer);
417  qstate = query_process(q, data->engine);
418  if (qstate != QUERY_DISCARDED) {
419  ods_log_debug("[%s] query processed qstate=%d", sock_str, qstate);
420  query_add_optional(q, data->engine);
421  buffer_flip(q->buffer);
422  send_udp(data, q);
423  }
424  return;
425 }
426 
427 
432 static void
433 cleanup_tcp_handler(netio_type* netio, netio_handler_type* handler)
434 {
435  struct tcp_data* data = (struct tcp_data*) handler->user_data;
437  netio_remove_handler(netio, handler);
438  close(handler->fd);
439  allocator_deallocate(allocator, (void*) handler->timeout);
440  allocator_deallocate(allocator, (void*) handler);
441  query_cleanup(data->query);
442  allocator_deallocate(allocator, (void*) data);
444  return;
445 }
446 
447 
452 void
454  netio_events_type event_types)
455 {
456  allocator_type* allocator = NULL;
457  struct tcp_accept_data* accept_data = (struct tcp_accept_data*)
458  handler->user_data;
459  int s = 0;
460  struct tcp_data* tcp_data = NULL;
461  netio_handler_type* tcp_handler = NULL;
462  struct sockaddr_storage addr;
463  socklen_t addrlen = 0;
464  if (!(event_types & NETIO_EVENT_READ)) {
465  return;
466  }
467  ods_log_debug("[%s] handle incoming tcp connection", sock_str);
468  addrlen = sizeof(addr);
469  s = accept(handler->fd, (struct sockaddr *) &addr, &addrlen);
470  if (s == -1) {
471  if (errno != EINTR && errno != EWOULDBLOCK) {
472  ods_log_error("[%s] unable to handle incoming tcp connection: "
473  "accept() failed (%s)", sock_str, strerror(errno));
474  }
475  return;
476  }
477  if (fcntl(s, F_SETFL, O_NONBLOCK) == -1) {
478  ods_log_error("[%s] unable to handle incoming tcp connection: "
479  "fcntl() failed: %s", sock_str, strerror(errno));
480  close(s);
481  return;
482  }
483  /* create tcp handler data */
484  allocator = allocator_create(malloc, free);
485  if (!allocator) {
486  ods_log_error("[%s] unable to handle incoming tcp connection: "
487  "allocator_create() failed", sock_str);
488  close(s);
489  return;
490  }
491  tcp_data = (struct tcp_data*) allocator_alloc(allocator,
492  sizeof(struct tcp_data));
493  if (!tcp_data) {
494  ods_log_error("[%s] unable to handle incoming tcp connection: "
495  "allocator_alloc() data failed", sock_str);
496  allocator_cleanup(allocator);
497  close(s);
498  return;
499  }
502  if (!tcp_data->query) {
503  ods_log_error("[%s] unable to handle incoming tcp connection: "
504  "query_create() failed", sock_str);
505  allocator_deallocate(allocator, (void*) tcp_data);
506  allocator_cleanup(allocator);
507  close(s);
508  return;
509  }
510  tcp_data->engine = accept_data->engine;
512  accept_data->tcp_accept_handler_count;
516  memcpy(&tcp_data->query->addr, &addr, addrlen);
517  tcp_data->query->addrlen = addrlen;
518  tcp_handler = (netio_handler_type*) allocator_alloc(allocator,
519  sizeof(netio_handler_type));
520  if (!tcp_handler) {
521  ods_log_error("[%s] unable to handle incoming tcp connection: "
522  "allocator_alloc() handler failed", sock_str);
524  allocator_deallocate(allocator, (void*) tcp_data);
525  allocator_cleanup(allocator);
526  close(s);
527  return;
528  }
529  tcp_handler->fd = s;
530  tcp_handler->timeout = (struct timespec*) allocator_alloc(allocator,
531  sizeof(struct timespec));
532  if (!tcp_handler->timeout) {
533  ods_log_error("[%s] unable to handle incoming tcp connection: "
534  "allocator_alloc() timeout failed", sock_str);
535  allocator_deallocate(allocator, (void*) tcp_handler);
537  allocator_deallocate(allocator, (void*) tcp_data);
538  allocator_cleanup(allocator);
539  close(s);
540  return;
541  }
542  tcp_handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
543  tcp_handler->timeout->tv_nsec = 0L;
544  timespec_add(tcp_handler->timeout, netio_current_time(netio));
545  tcp_handler->user_data = tcp_data;
546  tcp_handler->event_types = NETIO_EVENT_READ | NETIO_EVENT_TIMEOUT;
547  tcp_handler->event_handler = sock_handle_tcp_read;
548  netio_add_handler(netio, tcp_handler);
549  return;
550 }
551 
552 
557 void
559  netio_events_type event_types)
560 {
561  struct tcp_data* data = (struct tcp_data *) handler->user_data;
562  ssize_t received = 0;
564 
565  if (event_types & NETIO_EVENT_TIMEOUT) {
566  cleanup_tcp_handler(netio, handler);
567  return;
568  }
569  ods_log_assert(event_types & NETIO_EVENT_READ);
570  ods_log_debug("[%s] incoming tcp message", sock_str);
571  if (data->bytes_transmitted == 0) {
572  ods_log_debug("[%s] TCP_READ: reset query", sock_str);
574  }
575  /* check if we received the leading packet length bytes yet. */
576  if (data->bytes_transmitted < sizeof(uint16_t)) {
577  received = read(handler->fd,
578  (char *) &data->query->tcplen + data->bytes_transmitted,
579  sizeof(uint16_t) - data->bytes_transmitted);
580  if (received == -1) {
581  if (errno == EAGAIN || errno == EINTR) {
582  /* read would block, wait until more data is available. */
583  return;
584  } else {
585  ods_log_error("[%s] unable to handle incoming tcp query: "
586  "read() failed (%s)", sock_str, strerror(errno));
587  cleanup_tcp_handler(netio, handler);
588  return;
589  }
590  } else if (received == 0) {
591  cleanup_tcp_handler(netio, handler);
592  return;
593  }
594  data->bytes_transmitted += received;
595  ods_log_debug("[%s] TCP_READ: bytes transmitted %u (received %u)",
596  sock_str, data->bytes_transmitted, received);
597  if (data->bytes_transmitted < sizeof(uint16_t)) {
598  /* not done with the tcplen yet, wait for more. */
599  ods_log_debug("[%s] TCP_READ: bytes transmitted %u, while ",
600  "sizeof uint16_t %u", sock_str, data->bytes_transmitted,
601  sizeof(uint16_t));
602  return;
603  }
604  ods_log_assert(data->bytes_transmitted == sizeof(uint16_t));
605  data->query->tcplen = ntohs(data->query->tcplen);
606  /* minimum query size is: 12 + 1 + 2 + 2:
607  * header size + root dname + qclass + qtype */
608  if (data->query->tcplen < 17) {
609  ods_log_warning("[%s] unable to handle incoming tcp query: "
610  "packet too small", sock_str);
611  cleanup_tcp_handler(netio, handler);
612  return;
613  }
614  if (data->query->tcplen > data->query->maxlen) {
615  ods_log_warning("[%s] unable to handle incoming tcp query: "
616  "insufficient tcp buffer", sock_str);
617  cleanup_tcp_handler(netio, handler);
618  return;
619  }
620  buffer_set_limit(data->query->buffer, data->query->tcplen);
621  }
623  /* read the (remaining) query data. */
624  received = read(handler->fd, buffer_current(data->query->buffer),
625  buffer_remaining(data->query->buffer));
626  if (received == -1) {
627  if (errno == EAGAIN || errno == EINTR) {
628  /* read would block, wait until more data is available. */
629  return;
630  } else {
631  ods_log_error("[%s] unable to handle incoming tcp query: "
632  "read() failed (%s)", sock_str, strerror(errno));
633  cleanup_tcp_handler(netio, handler);
634  return;
635  }
636  } else if (received == 0) {
637  cleanup_tcp_handler(netio, handler);
638  return;
639  }
640  data->bytes_transmitted += received;
641  ods_log_debug("[%s] TCP_READ: bytes transmitted %u (received %u)",
642  sock_str, data->bytes_transmitted, received);
643 
644  buffer_skip(data->query->buffer, received);
645  if (buffer_remaining(data->query->buffer) > 0) {
646  /* not done with message yet, wait for more. */
647  ods_log_debug("[%s] TCP_READ: remaining %u", sock_str,
648  buffer_remaining(data->query->buffer));
649  return;
650  }
652  data->query->tcplen);
653  /* we have a complete query, process it. */
654  buffer_flip(data->query->buffer);
655  qstate = query_process(data->query, data->engine);
656  if (qstate == QUERY_DISCARDED) {
657  cleanup_tcp_handler(netio, handler);
658  return;
659  }
660  ods_log_debug("[%s] query processed qstate=%d", sock_str, qstate);
661  data->qstate = qstate;
662  /* edns, tsig */
663  query_add_optional(data->query, data->engine);
664  /* switch to tcp write handler. */
665  buffer_flip(data->query->buffer);
666  data->query->tcplen = buffer_remaining(data->query->buffer);
667  ods_log_debug("[%s] TCP_READ: new tcplen %u", sock_str,
668  data->query->tcplen);
669  data->bytes_transmitted = 0;
670  handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
671  handler->timeout->tv_nsec = 0L;
672  timespec_add(handler->timeout, netio_current_time(netio));
675  return;
676 }
677 
678 
683 void
685  netio_events_type event_types)
686 {
687  struct tcp_data* data = (struct tcp_data *) handler->user_data;
688  ssize_t sent = 0;
689  query_type* q = data->query;
690 
691  if (event_types & NETIO_EVENT_TIMEOUT) {
692  cleanup_tcp_handler(netio, handler);
693  return;
694  }
695  ods_log_assert(event_types & NETIO_EVENT_WRITE);
696 
697  if (data->bytes_transmitted < sizeof(q->tcplen)) {
698  uint16_t n_tcplen = htons(q->tcplen);
699  sent = write(handler->fd,
700  (const char*) &n_tcplen + data->bytes_transmitted,
701  sizeof(n_tcplen) - data->bytes_transmitted);
702  if (sent == -1) {
703  if (errno == EAGAIN || errno == EINTR) {
704  /* write would block, wait until socket becomes writeable. */
705  return;
706  } else {
707  ods_log_error("[%s] unable to handle outgoing tcp response: "
708  "write() failed (%s)", sock_str, strerror(errno));
709  cleanup_tcp_handler(netio, handler);
710  return;
711  }
712  } else if (sent == 0) {
713  cleanup_tcp_handler(netio, handler);
714  return;
715  }
716  data->bytes_transmitted += sent;
717  ods_log_debug("[%s] TCP_WRITE: bytes transmitted %u (sent %u)",
718  sock_str, data->bytes_transmitted, sent);
719  if (data->bytes_transmitted < sizeof(q->tcplen)) {
720  /* writing not complete, wait until socket becomes writable. */
721  ods_log_debug("[%s] TCP_WRITE: bytes transmitted %u, while ",
722  "sizeof tcplen %u", sock_str, data->bytes_transmitted,
723  sizeof(q->tcplen));
724  return;
725  }
726  ods_log_assert(data->bytes_transmitted == sizeof(q->tcplen));
727  }
728  ods_log_assert(data->bytes_transmitted < q->tcplen + sizeof(q->tcplen));
729 
730  sent = write(handler->fd, buffer_current(q->buffer),
732  if (sent == -1) {
733  if (errno == EAGAIN || errno == EINTR) {
734  /* write would block, wait until socket becomes writeable. */
735  return;
736  } else {
737  ods_log_error("[%s] unable to handle outgoing tcp response: "
738  "write() failed (%s)", sock_str, strerror(errno));
739  cleanup_tcp_handler(netio, handler);
740  return;
741  }
742  } else if (sent == 0) {
743  cleanup_tcp_handler(netio, handler);
744  return;
745  }
746 
747  buffer_skip(q->buffer, sent);
748  data->bytes_transmitted += sent;
749  if (data->bytes_transmitted < q->tcplen + sizeof(q->tcplen)) {
750  /* still more data to write when socket becomes writable. */
751  ods_log_debug("[%s] TCP_WRITE: bytes transmitted %u, while tcplen "
752  "%u and sizeof tcplen %u", sock_str, data->bytes_transmitted,
753  q->tcplen, sizeof(q->tcplen));
754  return;
755  }
756 
757  ods_log_debug("[%s] TCP_WRITE: bytes transmitted %u",
758  sock_str, data->bytes_transmitted);
759  ods_log_debug("[%s] TCP_WRITE: tcplen %u", sock_str, q->tcplen);
760  ods_log_debug("[%s] TCP_WRITE: sizeof tcplen %u", sock_str,
761  sizeof(q->tcplen));
762  ods_log_assert(data->bytes_transmitted == q->tcplen + sizeof(q->tcplen));
763  if (data->qstate == QUERY_AXFR || data->qstate == QUERY_IXFR) {
764  /* continue processing AXFR and writing back results. */
765  buffer_clear(q->buffer);
766  if (data->qstate == QUERY_IXFR) {
767  data->qstate = ixfr(q, data->engine);
768  } else {
769  data->qstate = axfr(q, data->engine);
770  }
771  if (data->qstate != QUERY_PROCESSED) {
772  /* edns, tsig */
773  query_add_optional(q, data->engine);
774  buffer_flip(q->buffer);
775  q->tcplen = buffer_remaining(q->buffer);
776  data->bytes_transmitted = 0;
777  handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
778  handler->timeout->tv_nsec = 0L;
779  timespec_add(handler->timeout, netio_current_time(netio));
780  return;
781  }
782  }
783  /* done sending, wait for the next request. */
784  data->bytes_transmitted = 0;
785  handler->timeout->tv_sec = XFRD_TCP_TIMEOUT;
786  handler->timeout->tv_nsec = 0L;
787  timespec_add(handler->timeout, netio_current_time(netio));
790  return;
791 }