1238106Sdes/* 2238106Sdes * util/netevent.c - event notification 3238106Sdes * 4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved. 5238106Sdes * 6238106Sdes * This software is open source. 7238106Sdes * 8238106Sdes * Redistribution and use in source and binary forms, with or without 9238106Sdes * modification, are permitted provided that the following conditions 10238106Sdes * are met: 11238106Sdes * 12238106Sdes * Redistributions of source code must retain the above copyright notice, 13238106Sdes * this list of conditions and the following disclaimer. 14238106Sdes * 15238106Sdes * Redistributions in binary form must reproduce the above copyright notice, 16238106Sdes * this list of conditions and the following disclaimer in the documentation 17238106Sdes * and/or other materials provided with the distribution. 18238106Sdes * 19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may 20238106Sdes * be used to endorse or promote products derived from this software without 21238106Sdes * specific prior written permission. 22238106Sdes * 23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34238106Sdes */ 35238106Sdes 36238106Sdes/** 37238106Sdes * \file 38238106Sdes * 39238106Sdes * This file contains event notification functions. 40238106Sdes */ 41238106Sdes#include "config.h" 42238106Sdes#include "util/netevent.h" 43238106Sdes#include "util/log.h" 44238106Sdes#include "util/net_help.h" 45238106Sdes#include "util/fptr_wlist.h" 46269257Sdes#include "ldns/pkthdr.h" 47269257Sdes#include "ldns/sbuffer.h" 48249141Sdes#ifdef HAVE_OPENSSL_SSL_H 49238106Sdes#include <openssl/ssl.h> 50249141Sdes#endif 51249141Sdes#ifdef HAVE_OPENSSL_ERR_H 52238106Sdes#include <openssl/err.h> 53249141Sdes#endif 54238106Sdes 55238106Sdes/* -------- Start of local definitions -------- */ 56238106Sdes/** if CMSG_ALIGN is not defined on this platform, a workaround */ 57238106Sdes#ifndef CMSG_ALIGN 58238106Sdes# ifdef _CMSG_DATA_ALIGN 59238106Sdes# define CMSG_ALIGN _CMSG_DATA_ALIGN 60238106Sdes# else 61238106Sdes# define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1)) 62238106Sdes# endif 63238106Sdes#endif 64238106Sdes 65238106Sdes/** if CMSG_LEN is not defined on this platform, a workaround */ 66238106Sdes#ifndef CMSG_LEN 67238106Sdes# define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len)) 68238106Sdes#endif 69238106Sdes 70238106Sdes/** if CMSG_SPACE is not defined on this platform, a workaround */ 71238106Sdes#ifndef CMSG_SPACE 72238106Sdes# ifdef _CMSG_HDR_ALIGN 73238106Sdes# define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr))) 74238106Sdes# else 75238106Sdes# define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr))) 76238106Sdes# endif 77238106Sdes#endif 78238106Sdes 79238106Sdes/** The TCP reading or writing query timeout in seconds */ 80238106Sdes#define TCP_QUERY_TIMEOUT 120 81238106Sdes 82238106Sdes#ifndef NONBLOCKING_IS_BROKEN 83238106Sdes/** number of UDP reads to perform per read indication from select */ 84238106Sdes#define NUM_UDP_PER_SELECT 100 85238106Sdes#else 86238106Sdes#define NUM_UDP_PER_SELECT 1 87238106Sdes#endif 88238106Sdes 89238106Sdes/* We define libevent structures here to hide the libevent stuff. */ 90238106Sdes 91238106Sdes#ifdef USE_MINI_EVENT 92238106Sdes# ifdef USE_WINSOCK 93238106Sdes# include "util/winsock_event.h" 94238106Sdes# else 95238106Sdes# include "util/mini_event.h" 96238106Sdes# endif /* USE_WINSOCK */ 97238106Sdes#else /* USE_MINI_EVENT */ 98238106Sdes /* we use libevent */ 99249141Sdes# ifdef HAVE_EVENT_H 100249141Sdes# include <event.h> 101249141Sdes# else 102249141Sdes# include "event2/event.h" 103249141Sdes# include "event2/event_struct.h" 104249141Sdes# include "event2/event_compat.h" 105249141Sdes# endif 106238106Sdes#endif /* USE_MINI_EVENT */ 107238106Sdes 108238106Sdes/** 109238106Sdes * The internal event structure for keeping libevent info for the event. 110238106Sdes * Possibly other structures (list, tree) this is part of. 111238106Sdes */ 112238106Sdesstruct internal_event { 113238106Sdes /** the comm base */ 114238106Sdes struct comm_base* base; 115238106Sdes /** libevent event type, alloced here */ 116238106Sdes struct event ev; 117238106Sdes}; 118238106Sdes 119238106Sdes/** 120238106Sdes * Internal base structure, so that every thread has its own events. 121238106Sdes */ 122238106Sdesstruct internal_base { 123238106Sdes /** libevent event_base type. */ 124238106Sdes struct event_base* base; 125238106Sdes /** seconds time pointer points here */ 126269257Sdes time_t secs; 127238106Sdes /** timeval with current time */ 128238106Sdes struct timeval now; 129238106Sdes /** the event used for slow_accept timeouts */ 130238106Sdes struct event slow_accept; 131238106Sdes /** true if slow_accept is enabled */ 132238106Sdes int slow_accept_enabled; 133238106Sdes}; 134238106Sdes 135238106Sdes/** 136238106Sdes * Internal timer structure, to store timer event in. 137238106Sdes */ 138238106Sdesstruct internal_timer { 139238106Sdes /** the comm base */ 140238106Sdes struct comm_base* base; 141238106Sdes /** libevent event type, alloced here */ 142238106Sdes struct event ev; 143238106Sdes /** is timer enabled */ 144238106Sdes uint8_t enabled; 145238106Sdes}; 146238106Sdes 147238106Sdes/** 148238106Sdes * Internal signal structure, to store signal event in. 149238106Sdes */ 150238106Sdesstruct internal_signal { 151238106Sdes /** libevent event type, alloced here */ 152238106Sdes struct event ev; 153238106Sdes /** next in signal list */ 154238106Sdes struct internal_signal* next; 155238106Sdes}; 156238106Sdes 157238106Sdes/** create a tcp handler with a parent */ 158238106Sdesstatic struct comm_point* comm_point_create_tcp_handler( 159238106Sdes struct comm_base *base, struct comm_point* parent, size_t bufsize, 160238106Sdes comm_point_callback_t* callback, void* callback_arg); 161238106Sdes 162238106Sdes/* -------- End of local definitions -------- */ 163238106Sdes 164238106Sdes#ifdef USE_MINI_EVENT 165238106Sdes/** minievent updates the time when it blocks. */ 166238106Sdes#define comm_base_now(x) /* nothing to do */ 167238106Sdes#else /* !USE_MINI_EVENT */ 168238106Sdes/** fillup the time values in the event base */ 169238106Sdesstatic void 170238106Sdescomm_base_now(struct comm_base* b) 171238106Sdes{ 172238106Sdes if(gettimeofday(&b->eb->now, NULL) < 0) { 173238106Sdes log_err("gettimeofday: %s", strerror(errno)); 174238106Sdes } 175269257Sdes b->eb->secs = (time_t)b->eb->now.tv_sec; 176238106Sdes} 177238106Sdes#endif /* USE_MINI_EVENT */ 178238106Sdes 179238106Sdesstruct comm_base* 180238106Sdescomm_base_create(int sigs) 181238106Sdes{ 182238106Sdes struct comm_base* b = (struct comm_base*)calloc(1, 183238106Sdes sizeof(struct comm_base)); 184238106Sdes if(!b) 185238106Sdes return NULL; 186238106Sdes b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 187238106Sdes if(!b->eb) { 188238106Sdes free(b); 189238106Sdes return NULL; 190238106Sdes } 191238106Sdes#ifdef USE_MINI_EVENT 192238106Sdes (void)sigs; 193238106Sdes /* use mini event time-sharing feature */ 194238106Sdes b->eb->base = event_init(&b->eb->secs, &b->eb->now); 195238106Sdes#else 196238106Sdes# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 197238106Sdes /* libev */ 198238106Sdes if(sigs) 199238106Sdes b->eb->base=(struct event_base *)ev_default_loop(EVFLAG_AUTO); 200238106Sdes else 201238106Sdes b->eb->base=(struct event_base *)ev_loop_new(EVFLAG_AUTO); 202238106Sdes# else 203238106Sdes (void)sigs; 204238106Sdes# ifdef HAVE_EVENT_BASE_NEW 205238106Sdes b->eb->base = event_base_new(); 206238106Sdes# else 207238106Sdes b->eb->base = event_init(); 208238106Sdes# endif 209238106Sdes# endif 210238106Sdes#endif 211238106Sdes if(!b->eb->base) { 212238106Sdes free(b->eb); 213238106Sdes free(b); 214238106Sdes return NULL; 215238106Sdes } 216238106Sdes comm_base_now(b); 217238106Sdes /* avoid event_get_method call which causes crashes even when 218238106Sdes * not printing, because its result is passed */ 219238106Sdes verbose(VERB_ALGO, 220238106Sdes#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 221238106Sdes "libev" 222238106Sdes#elif defined(USE_MINI_EVENT) 223238106Sdes "event " 224238106Sdes#else 225238106Sdes "libevent " 226238106Sdes#endif 227238106Sdes "%s uses %s method.", 228238106Sdes event_get_version(), 229238106Sdes#ifdef HAVE_EVENT_BASE_GET_METHOD 230238106Sdes event_base_get_method(b->eb->base) 231238106Sdes#else 232238106Sdes "not_obtainable" 233238106Sdes#endif 234238106Sdes ); 235238106Sdes return b; 236238106Sdes} 237238106Sdes 238269257Sdesstruct comm_base* 239269257Sdescomm_base_create_event(struct event_base* base) 240269257Sdes{ 241269257Sdes struct comm_base* b = (struct comm_base*)calloc(1, 242269257Sdes sizeof(struct comm_base)); 243269257Sdes if(!b) 244269257Sdes return NULL; 245269257Sdes b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 246269257Sdes if(!b->eb) { 247269257Sdes free(b); 248269257Sdes return NULL; 249269257Sdes } 250269257Sdes b->eb->base = base; 251269257Sdes comm_base_now(b); 252269257Sdes return b; 253269257Sdes} 254269257Sdes 255238106Sdesvoid 256238106Sdescomm_base_delete(struct comm_base* b) 257238106Sdes{ 258238106Sdes if(!b) 259238106Sdes return; 260238106Sdes if(b->eb->slow_accept_enabled) { 261238106Sdes if(event_del(&b->eb->slow_accept) != 0) { 262238106Sdes log_err("could not event_del slow_accept"); 263238106Sdes } 264238106Sdes } 265238106Sdes#ifdef USE_MINI_EVENT 266238106Sdes event_base_free(b->eb->base); 267238106Sdes#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE) 268238106Sdes /* only libevent 1.2+ has it, but in 1.2 it is broken - 269238106Sdes assertion fails on signal handling ev that is not deleted 270238106Sdes in libevent 1.3c (event_base_once appears) this is fixed. */ 271238106Sdes event_base_free(b->eb->base); 272238106Sdes#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */ 273238106Sdes b->eb->base = NULL; 274238106Sdes free(b->eb); 275238106Sdes free(b); 276238106Sdes} 277238106Sdes 278238106Sdesvoid 279269257Sdescomm_base_delete_no_base(struct comm_base* b) 280238106Sdes{ 281269257Sdes if(!b) 282269257Sdes return; 283269257Sdes if(b->eb->slow_accept_enabled) { 284269257Sdes if(event_del(&b->eb->slow_accept) != 0) { 285269257Sdes log_err("could not event_del slow_accept"); 286269257Sdes } 287269257Sdes } 288269257Sdes b->eb->base = NULL; 289269257Sdes free(b->eb); 290269257Sdes free(b); 291269257Sdes} 292269257Sdes 293269257Sdesvoid 294269257Sdescomm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv) 295269257Sdes{ 296238106Sdes *tt = &b->eb->secs; 297238106Sdes *tv = &b->eb->now; 298238106Sdes} 299238106Sdes 300238106Sdesvoid 301238106Sdescomm_base_dispatch(struct comm_base* b) 302238106Sdes{ 303238106Sdes int retval; 304238106Sdes retval = event_base_dispatch(b->eb->base); 305238106Sdes if(retval != 0) { 306238106Sdes fatal_exit("event_dispatch returned error %d, " 307238106Sdes "errno is %s", retval, strerror(errno)); 308238106Sdes } 309238106Sdes} 310238106Sdes 311238106Sdesvoid comm_base_exit(struct comm_base* b) 312238106Sdes{ 313238106Sdes if(event_base_loopexit(b->eb->base, NULL) != 0) { 314238106Sdes log_err("Could not loopexit"); 315238106Sdes } 316238106Sdes} 317238106Sdes 318238106Sdesvoid comm_base_set_slow_accept_handlers(struct comm_base* b, 319238106Sdes void (*stop_acc)(void*), void (*start_acc)(void*), void* arg) 320238106Sdes{ 321238106Sdes b->stop_accept = stop_acc; 322238106Sdes b->start_accept = start_acc; 323238106Sdes b->cb_arg = arg; 324238106Sdes} 325238106Sdes 326238106Sdesstruct event_base* comm_base_internal(struct comm_base* b) 327238106Sdes{ 328238106Sdes return b->eb->base; 329238106Sdes} 330238106Sdes 331238106Sdes/** see if errno for udp has to be logged or not uses globals */ 332238106Sdesstatic int 333238106Sdesudp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 334238106Sdes{ 335238106Sdes /* do not log transient errors (unless high verbosity) */ 336238106Sdes#if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN) 337238106Sdes switch(errno) { 338238106Sdes# ifdef ENETUNREACH 339238106Sdes case ENETUNREACH: 340238106Sdes# endif 341238106Sdes# ifdef EHOSTDOWN 342238106Sdes case EHOSTDOWN: 343238106Sdes# endif 344238106Sdes# ifdef EHOSTUNREACH 345238106Sdes case EHOSTUNREACH: 346238106Sdes# endif 347238106Sdes# ifdef ENETDOWN 348238106Sdes case ENETDOWN: 349238106Sdes# endif 350238106Sdes if(verbosity < VERB_ALGO) 351238106Sdes return 0; 352238106Sdes default: 353238106Sdes break; 354238106Sdes } 355238106Sdes#endif 356269257Sdes /* permission denied is gotten for every send if the 357269257Sdes * network is disconnected (on some OS), squelch it */ 358269257Sdes if(errno == EPERM && verbosity < VERB_DETAIL) 359269257Sdes return 0; 360238106Sdes /* squelch errors where people deploy AAAA ::ffff:bla for 361238106Sdes * authority servers, which we try for intranets. */ 362238106Sdes if(errno == EINVAL && addr_is_ip4mapped( 363238106Sdes (struct sockaddr_storage*)addr, addrlen) && 364238106Sdes verbosity < VERB_DETAIL) 365238106Sdes return 0; 366238106Sdes /* SO_BROADCAST sockopt can give access to 255.255.255.255, 367238106Sdes * but a dns cache does not need it. */ 368238106Sdes if(errno == EACCES && addr_is_broadcast( 369238106Sdes (struct sockaddr_storage*)addr, addrlen) && 370238106Sdes verbosity < VERB_DETAIL) 371238106Sdes return 0; 372238106Sdes return 1; 373238106Sdes} 374238106Sdes 375238106Sdesint tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 376238106Sdes{ 377238106Sdes return udp_send_errno_needs_log(addr, addrlen); 378238106Sdes} 379238106Sdes 380238106Sdes/* send a UDP reply */ 381238106Sdesint 382269257Sdescomm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, 383238106Sdes struct sockaddr* addr, socklen_t addrlen) 384238106Sdes{ 385238106Sdes ssize_t sent; 386238106Sdes log_assert(c->fd != -1); 387238106Sdes#ifdef UNBOUND_DEBUG 388269257Sdes if(sldns_buffer_remaining(packet) == 0) 389238106Sdes log_err("error: send empty UDP packet"); 390238106Sdes#endif 391238106Sdes log_assert(addr && addrlen > 0); 392269257Sdes sent = sendto(c->fd, (void*)sldns_buffer_begin(packet), 393269257Sdes sldns_buffer_remaining(packet), 0, 394238106Sdes addr, addrlen); 395238106Sdes if(sent == -1) { 396238106Sdes if(!udp_send_errno_needs_log(addr, addrlen)) 397238106Sdes return 0; 398238106Sdes#ifndef USE_WINSOCK 399238106Sdes verbose(VERB_OPS, "sendto failed: %s", strerror(errno)); 400238106Sdes#else 401238106Sdes verbose(VERB_OPS, "sendto failed: %s", 402238106Sdes wsa_strerror(WSAGetLastError())); 403238106Sdes#endif 404238106Sdes log_addr(VERB_OPS, "remote address is", 405238106Sdes (struct sockaddr_storage*)addr, addrlen); 406238106Sdes return 0; 407269257Sdes } else if((size_t)sent != sldns_buffer_remaining(packet)) { 408238106Sdes log_err("sent %d in place of %d bytes", 409269257Sdes (int)sent, (int)sldns_buffer_remaining(packet)); 410238106Sdes return 0; 411238106Sdes } 412238106Sdes return 1; 413238106Sdes} 414238106Sdes 415238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG)) 416238106Sdes/** print debug ancillary info */ 417238106Sdesstatic void p_ancil(const char* str, struct comm_reply* r) 418238106Sdes{ 419238106Sdes if(r->srctype != 4 && r->srctype != 6) { 420238106Sdes log_info("%s: unknown srctype %d", str, r->srctype); 421238106Sdes return; 422238106Sdes } 423238106Sdes if(r->srctype == 6) { 424238106Sdes char buf[1024]; 425238106Sdes if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr, 426238106Sdes buf, (socklen_t)sizeof(buf)) == 0) { 427269257Sdes (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf)); 428238106Sdes } 429238106Sdes buf[sizeof(buf)-1]=0; 430238106Sdes log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex); 431238106Sdes } else if(r->srctype == 4) { 432238106Sdes#ifdef IP_PKTINFO 433238106Sdes char buf1[1024], buf2[1024]; 434238106Sdes if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr, 435238106Sdes buf1, (socklen_t)sizeof(buf1)) == 0) { 436269257Sdes (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 437238106Sdes } 438238106Sdes buf1[sizeof(buf1)-1]=0; 439238106Sdes#ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST 440238106Sdes if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst, 441238106Sdes buf2, (socklen_t)sizeof(buf2)) == 0) { 442269257Sdes (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2)); 443238106Sdes } 444238106Sdes buf2[sizeof(buf2)-1]=0; 445238106Sdes#else 446238106Sdes buf2[0]=0; 447238106Sdes#endif 448238106Sdes log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex, 449238106Sdes buf1, buf2); 450238106Sdes#elif defined(IP_RECVDSTADDR) 451238106Sdes char buf1[1024]; 452238106Sdes if(inet_ntop(AF_INET, &r->pktinfo.v4addr, 453238106Sdes buf1, (socklen_t)sizeof(buf1)) == 0) { 454269257Sdes (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 455238106Sdes } 456238106Sdes buf1[sizeof(buf1)-1]=0; 457238106Sdes log_info("%s: %s", str, buf1); 458238106Sdes#endif /* IP_PKTINFO or PI_RECVDSTDADDR */ 459238106Sdes } 460238106Sdes} 461238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */ 462238106Sdes 463238106Sdes/** send a UDP reply over specified interface*/ 464238106Sdesstatic int 465269257Sdescomm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet, 466238106Sdes struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r) 467238106Sdes{ 468238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG) 469238106Sdes ssize_t sent; 470238106Sdes struct msghdr msg; 471238106Sdes struct iovec iov[1]; 472238106Sdes char control[256]; 473238106Sdes#ifndef S_SPLINT_S 474238106Sdes struct cmsghdr *cmsg; 475238106Sdes#endif /* S_SPLINT_S */ 476238106Sdes 477238106Sdes log_assert(c->fd != -1); 478238106Sdes#ifdef UNBOUND_DEBUG 479269257Sdes if(sldns_buffer_remaining(packet) == 0) 480238106Sdes log_err("error: send empty UDP packet"); 481238106Sdes#endif 482238106Sdes log_assert(addr && addrlen > 0); 483238106Sdes 484238106Sdes msg.msg_name = addr; 485238106Sdes msg.msg_namelen = addrlen; 486269257Sdes iov[0].iov_base = sldns_buffer_begin(packet); 487269257Sdes iov[0].iov_len = sldns_buffer_remaining(packet); 488238106Sdes msg.msg_iov = iov; 489238106Sdes msg.msg_iovlen = 1; 490238106Sdes msg.msg_control = control; 491238106Sdes#ifndef S_SPLINT_S 492238106Sdes msg.msg_controllen = sizeof(control); 493238106Sdes#endif /* S_SPLINT_S */ 494238106Sdes msg.msg_flags = 0; 495238106Sdes 496238106Sdes#ifndef S_SPLINT_S 497238106Sdes cmsg = CMSG_FIRSTHDR(&msg); 498238106Sdes if(r->srctype == 4) { 499238106Sdes#ifdef IP_PKTINFO 500238106Sdes msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); 501238106Sdes log_assert(msg.msg_controllen <= sizeof(control)); 502238106Sdes cmsg->cmsg_level = IPPROTO_IP; 503238106Sdes cmsg->cmsg_type = IP_PKTINFO; 504238106Sdes memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info, 505238106Sdes sizeof(struct in_pktinfo)); 506238106Sdes cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 507238106Sdes#elif defined(IP_SENDSRCADDR) 508238106Sdes msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 509238106Sdes log_assert(msg.msg_controllen <= sizeof(control)); 510238106Sdes cmsg->cmsg_level = IPPROTO_IP; 511238106Sdes cmsg->cmsg_type = IP_SENDSRCADDR; 512238106Sdes memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr, 513238106Sdes sizeof(struct in_addr)); 514238106Sdes cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 515238106Sdes#else 516238106Sdes verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR"); 517238106Sdes msg.msg_control = NULL; 518238106Sdes#endif /* IP_PKTINFO or IP_SENDSRCADDR */ 519238106Sdes } else if(r->srctype == 6) { 520238106Sdes msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 521238106Sdes log_assert(msg.msg_controllen <= sizeof(control)); 522238106Sdes cmsg->cmsg_level = IPPROTO_IPV6; 523238106Sdes cmsg->cmsg_type = IPV6_PKTINFO; 524238106Sdes memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info, 525238106Sdes sizeof(struct in6_pktinfo)); 526238106Sdes cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 527238106Sdes } else { 528238106Sdes /* try to pass all 0 to use default route */ 529238106Sdes msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 530238106Sdes log_assert(msg.msg_controllen <= sizeof(control)); 531238106Sdes cmsg->cmsg_level = IPPROTO_IPV6; 532238106Sdes cmsg->cmsg_type = IPV6_PKTINFO; 533238106Sdes memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo)); 534238106Sdes cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 535238106Sdes } 536238106Sdes#endif /* S_SPLINT_S */ 537238106Sdes if(verbosity >= VERB_ALGO) 538238106Sdes p_ancil("send_udp over interface", r); 539238106Sdes sent = sendmsg(c->fd, &msg, 0); 540238106Sdes if(sent == -1) { 541238106Sdes if(!udp_send_errno_needs_log(addr, addrlen)) 542238106Sdes return 0; 543238106Sdes verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno)); 544238106Sdes log_addr(VERB_OPS, "remote address is", 545238106Sdes (struct sockaddr_storage*)addr, addrlen); 546238106Sdes return 0; 547269257Sdes } else if((size_t)sent != sldns_buffer_remaining(packet)) { 548238106Sdes log_err("sent %d in place of %d bytes", 549269257Sdes (int)sent, (int)sldns_buffer_remaining(packet)); 550238106Sdes return 0; 551238106Sdes } 552238106Sdes return 1; 553238106Sdes#else 554238106Sdes (void)c; 555238106Sdes (void)packet; 556238106Sdes (void)addr; 557238106Sdes (void)addrlen; 558238106Sdes (void)r; 559238106Sdes log_err("sendmsg: IPV6_PKTINFO not supported"); 560238106Sdes return 0; 561238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */ 562238106Sdes} 563238106Sdes 564238106Sdesvoid 565238106Sdescomm_point_udp_ancil_callback(int fd, short event, void* arg) 566238106Sdes{ 567238106Sdes#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) 568238106Sdes struct comm_reply rep; 569238106Sdes struct msghdr msg; 570238106Sdes struct iovec iov[1]; 571238106Sdes ssize_t rcv; 572238106Sdes char ancil[256]; 573238106Sdes int i; 574238106Sdes#ifndef S_SPLINT_S 575238106Sdes struct cmsghdr* cmsg; 576238106Sdes#endif /* S_SPLINT_S */ 577238106Sdes 578238106Sdes rep.c = (struct comm_point*)arg; 579238106Sdes log_assert(rep.c->type == comm_udp); 580238106Sdes 581238106Sdes if(!(event&EV_READ)) 582238106Sdes return; 583238106Sdes log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 584238106Sdes comm_base_now(rep.c->ev->base); 585238106Sdes for(i=0; i<NUM_UDP_PER_SELECT; i++) { 586269257Sdes sldns_buffer_clear(rep.c->buffer); 587238106Sdes rep.addrlen = (socklen_t)sizeof(rep.addr); 588238106Sdes log_assert(fd != -1); 589269257Sdes log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 590238106Sdes msg.msg_name = &rep.addr; 591238106Sdes msg.msg_namelen = (socklen_t)sizeof(rep.addr); 592269257Sdes iov[0].iov_base = sldns_buffer_begin(rep.c->buffer); 593269257Sdes iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer); 594238106Sdes msg.msg_iov = iov; 595238106Sdes msg.msg_iovlen = 1; 596238106Sdes msg.msg_control = ancil; 597238106Sdes#ifndef S_SPLINT_S 598238106Sdes msg.msg_controllen = sizeof(ancil); 599238106Sdes#endif /* S_SPLINT_S */ 600238106Sdes msg.msg_flags = 0; 601238106Sdes rcv = recvmsg(fd, &msg, 0); 602238106Sdes if(rcv == -1) { 603238106Sdes if(errno != EAGAIN && errno != EINTR) { 604238106Sdes log_err("recvmsg failed: %s", strerror(errno)); 605238106Sdes } 606238106Sdes return; 607238106Sdes } 608238106Sdes rep.addrlen = msg.msg_namelen; 609269257Sdes sldns_buffer_skip(rep.c->buffer, rcv); 610269257Sdes sldns_buffer_flip(rep.c->buffer); 611238106Sdes rep.srctype = 0; 612238106Sdes#ifndef S_SPLINT_S 613238106Sdes for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 614238106Sdes cmsg = CMSG_NXTHDR(&msg, cmsg)) { 615238106Sdes if( cmsg->cmsg_level == IPPROTO_IPV6 && 616238106Sdes cmsg->cmsg_type == IPV6_PKTINFO) { 617238106Sdes rep.srctype = 6; 618238106Sdes memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg), 619238106Sdes sizeof(struct in6_pktinfo)); 620238106Sdes break; 621238106Sdes#ifdef IP_PKTINFO 622238106Sdes } else if( cmsg->cmsg_level == IPPROTO_IP && 623238106Sdes cmsg->cmsg_type == IP_PKTINFO) { 624238106Sdes rep.srctype = 4; 625238106Sdes memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg), 626238106Sdes sizeof(struct in_pktinfo)); 627238106Sdes break; 628238106Sdes#elif defined(IP_RECVDSTADDR) 629238106Sdes } else if( cmsg->cmsg_level == IPPROTO_IP && 630238106Sdes cmsg->cmsg_type == IP_RECVDSTADDR) { 631238106Sdes rep.srctype = 4; 632238106Sdes memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg), 633238106Sdes sizeof(struct in_addr)); 634238106Sdes break; 635238106Sdes#endif /* IP_PKTINFO or IP_RECVDSTADDR */ 636238106Sdes } 637238106Sdes } 638238106Sdes if(verbosity >= VERB_ALGO) 639238106Sdes p_ancil("receive_udp on interface", &rep); 640238106Sdes#endif /* S_SPLINT_S */ 641238106Sdes fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 642238106Sdes if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 643238106Sdes /* send back immediate reply */ 644238106Sdes (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer, 645238106Sdes (struct sockaddr*)&rep.addr, rep.addrlen, &rep); 646238106Sdes } 647238106Sdes if(rep.c->fd == -1) /* commpoint closed */ 648238106Sdes break; 649238106Sdes } 650238106Sdes#else 651238106Sdes (void)fd; 652238106Sdes (void)event; 653238106Sdes (void)arg; 654238106Sdes fatal_exit("recvmsg: No support for IPV6_PKTINFO. " 655238106Sdes "Please disable interface-automatic"); 656238106Sdes#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ 657238106Sdes} 658238106Sdes 659238106Sdesvoid 660238106Sdescomm_point_udp_callback(int fd, short event, void* arg) 661238106Sdes{ 662238106Sdes struct comm_reply rep; 663238106Sdes ssize_t rcv; 664238106Sdes int i; 665238106Sdes 666238106Sdes rep.c = (struct comm_point*)arg; 667238106Sdes log_assert(rep.c->type == comm_udp); 668238106Sdes 669238106Sdes if(!(event&EV_READ)) 670238106Sdes return; 671238106Sdes log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 672238106Sdes comm_base_now(rep.c->ev->base); 673238106Sdes for(i=0; i<NUM_UDP_PER_SELECT; i++) { 674269257Sdes sldns_buffer_clear(rep.c->buffer); 675238106Sdes rep.addrlen = (socklen_t)sizeof(rep.addr); 676238106Sdes log_assert(fd != -1); 677269257Sdes log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 678269257Sdes rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer), 679269257Sdes sldns_buffer_remaining(rep.c->buffer), 0, 680238106Sdes (struct sockaddr*)&rep.addr, &rep.addrlen); 681238106Sdes if(rcv == -1) { 682238106Sdes#ifndef USE_WINSOCK 683238106Sdes if(errno != EAGAIN && errno != EINTR) 684238106Sdes log_err("recvfrom %d failed: %s", 685238106Sdes fd, strerror(errno)); 686238106Sdes#else 687238106Sdes if(WSAGetLastError() != WSAEINPROGRESS && 688238106Sdes WSAGetLastError() != WSAECONNRESET && 689238106Sdes WSAGetLastError()!= WSAEWOULDBLOCK) 690238106Sdes log_err("recvfrom failed: %s", 691238106Sdes wsa_strerror(WSAGetLastError())); 692238106Sdes#endif 693238106Sdes return; 694238106Sdes } 695269257Sdes sldns_buffer_skip(rep.c->buffer, rcv); 696269257Sdes sldns_buffer_flip(rep.c->buffer); 697238106Sdes rep.srctype = 0; 698238106Sdes fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 699238106Sdes if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 700238106Sdes /* send back immediate reply */ 701238106Sdes (void)comm_point_send_udp_msg(rep.c, rep.c->buffer, 702238106Sdes (struct sockaddr*)&rep.addr, rep.addrlen); 703238106Sdes } 704238106Sdes if(rep.c->fd != fd) /* commpoint closed to -1 or reused for 705238106Sdes another UDP port. Note rep.c cannot be reused with TCP fd. */ 706238106Sdes break; 707238106Sdes } 708238106Sdes} 709238106Sdes 710238106Sdes/** Use a new tcp handler for new query fd, set to read query */ 711238106Sdesstatic void 712238106Sdessetup_tcp_handler(struct comm_point* c, int fd) 713238106Sdes{ 714238106Sdes log_assert(c->type == comm_tcp); 715238106Sdes log_assert(c->fd == -1); 716269257Sdes sldns_buffer_clear(c->buffer); 717238106Sdes c->tcp_is_reading = 1; 718238106Sdes c->tcp_byte_count = 0; 719238106Sdes comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT); 720238106Sdes} 721238106Sdes 722238106Sdesvoid comm_base_handle_slow_accept(int ATTR_UNUSED(fd), 723238106Sdes short ATTR_UNUSED(event), void* arg) 724238106Sdes{ 725238106Sdes struct comm_base* b = (struct comm_base*)arg; 726238106Sdes /* timeout for the slow accept, re-enable accepts again */ 727238106Sdes if(b->start_accept) { 728238106Sdes verbose(VERB_ALGO, "wait is over, slow accept disabled"); 729238106Sdes fptr_ok(fptr_whitelist_start_accept(b->start_accept)); 730238106Sdes (*b->start_accept)(b->cb_arg); 731238106Sdes b->eb->slow_accept_enabled = 0; 732238106Sdes } 733238106Sdes} 734238106Sdes 735238106Sdesint comm_point_perform_accept(struct comm_point* c, 736238106Sdes struct sockaddr_storage* addr, socklen_t* addrlen) 737238106Sdes{ 738238106Sdes int new_fd; 739238106Sdes *addrlen = (socklen_t)sizeof(*addr); 740238106Sdes new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen); 741238106Sdes if(new_fd == -1) { 742238106Sdes#ifndef USE_WINSOCK 743238106Sdes /* EINTR is signal interrupt. others are closed connection. */ 744238106Sdes if( errno == EINTR || errno == EAGAIN 745238106Sdes#ifdef EWOULDBLOCK 746238106Sdes || errno == EWOULDBLOCK 747238106Sdes#endif 748238106Sdes#ifdef ECONNABORTED 749238106Sdes || errno == ECONNABORTED 750238106Sdes#endif 751238106Sdes#ifdef EPROTO 752238106Sdes || errno == EPROTO 753238106Sdes#endif /* EPROTO */ 754238106Sdes ) 755238106Sdes return -1; 756238106Sdes#if defined(ENFILE) && defined(EMFILE) 757238106Sdes if(errno == ENFILE || errno == EMFILE) { 758238106Sdes /* out of file descriptors, likely outside of our 759238106Sdes * control. stop accept() calls for some time */ 760238106Sdes if(c->ev->base->stop_accept) { 761238106Sdes struct comm_base* b = c->ev->base; 762238106Sdes struct timeval tv; 763238106Sdes verbose(VERB_ALGO, "out of file descriptors: " 764238106Sdes "slow accept"); 765238106Sdes b->eb->slow_accept_enabled = 1; 766238106Sdes fptr_ok(fptr_whitelist_stop_accept( 767238106Sdes b->stop_accept)); 768238106Sdes (*b->stop_accept)(b->cb_arg); 769238106Sdes /* set timeout, no mallocs */ 770238106Sdes tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; 771238106Sdes tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000; 772238106Sdes event_set(&b->eb->slow_accept, -1, EV_TIMEOUT, 773238106Sdes comm_base_handle_slow_accept, b); 774238106Sdes if(event_base_set(b->eb->base, 775238106Sdes &b->eb->slow_accept) != 0) { 776238106Sdes /* we do not want to log here, because 777238106Sdes * that would spam the logfiles. 778238106Sdes * error: "event_base_set failed." */ 779238106Sdes } 780238106Sdes if(event_add(&b->eb->slow_accept, &tv) != 0) { 781238106Sdes /* we do not want to log here, 782238106Sdes * error: "event_add failed." */ 783238106Sdes } 784238106Sdes } 785238106Sdes return -1; 786238106Sdes } 787238106Sdes#endif 788238106Sdes log_err("accept failed: %s", strerror(errno)); 789238106Sdes#else /* USE_WINSOCK */ 790238106Sdes if(WSAGetLastError() == WSAEINPROGRESS || 791238106Sdes WSAGetLastError() == WSAECONNRESET) 792238106Sdes return -1; 793238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) { 794238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 795238106Sdes return -1; 796238106Sdes } 797238106Sdes log_err("accept failed: %s", wsa_strerror(WSAGetLastError())); 798238106Sdes#endif 799238106Sdes log_addr(0, "remote address is", addr, *addrlen); 800238106Sdes return -1; 801238106Sdes } 802238106Sdes fd_set_nonblock(new_fd); 803238106Sdes return new_fd; 804238106Sdes} 805238106Sdes 806238106Sdes#ifdef USE_WINSOCK 807238106Sdesstatic long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp), 808238106Sdes int ATTR_UNUSED(argi), long argl, long retvalue) 809238106Sdes{ 810238106Sdes verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper, 811238106Sdes (oper&BIO_CB_RETURN)?"return":"before", 812238106Sdes (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"), 813238106Sdes WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":""); 814238106Sdes /* on windows, check if previous operation caused EWOULDBLOCK */ 815238106Sdes if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) || 816238106Sdes (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) { 817238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) 818238106Sdes winsock_tcp_wouldblock((struct event*) 819238106Sdes BIO_get_callback_arg(b), EV_READ); 820238106Sdes } 821238106Sdes if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) || 822238106Sdes (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) { 823238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) 824238106Sdes winsock_tcp_wouldblock((struct event*) 825238106Sdes BIO_get_callback_arg(b), EV_WRITE); 826238106Sdes } 827238106Sdes /* return original return value */ 828238106Sdes return retvalue; 829238106Sdes} 830238106Sdes 831238106Sdes/** set win bio callbacks for nonblocking operations */ 832238106Sdesvoid 833238106Sdescomm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl) 834238106Sdes{ 835238106Sdes SSL* ssl = (SSL*)thessl; 836238106Sdes /* set them both just in case, but usually they are the same BIO */ 837238106Sdes BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb); 838238106Sdes BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)&c->ev->ev); 839238106Sdes BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb); 840238106Sdes BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)&c->ev->ev); 841238106Sdes} 842238106Sdes#endif 843238106Sdes 844238106Sdesvoid 845238106Sdescomm_point_tcp_accept_callback(int fd, short event, void* arg) 846238106Sdes{ 847238106Sdes struct comm_point* c = (struct comm_point*)arg, *c_hdl; 848238106Sdes int new_fd; 849238106Sdes log_assert(c->type == comm_tcp_accept); 850238106Sdes if(!(event & EV_READ)) { 851238106Sdes log_info("ignoring tcp accept event %d", (int)event); 852238106Sdes return; 853238106Sdes } 854238106Sdes comm_base_now(c->ev->base); 855238106Sdes /* find free tcp handler. */ 856238106Sdes if(!c->tcp_free) { 857238106Sdes log_warn("accepted too many tcp, connections full"); 858238106Sdes return; 859238106Sdes } 860238106Sdes /* accept incoming connection. */ 861238106Sdes c_hdl = c->tcp_free; 862238106Sdes log_assert(fd != -1); 863238106Sdes new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr, 864238106Sdes &c_hdl->repinfo.addrlen); 865238106Sdes if(new_fd == -1) 866238106Sdes return; 867238106Sdes if(c->ssl) { 868238106Sdes c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd); 869238106Sdes if(!c_hdl->ssl) { 870238106Sdes c_hdl->fd = new_fd; 871238106Sdes comm_point_close(c_hdl); 872238106Sdes return; 873238106Sdes } 874238106Sdes c_hdl->ssl_shake_state = comm_ssl_shake_read; 875238106Sdes#ifdef USE_WINSOCK 876238106Sdes comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl); 877238106Sdes#endif 878238106Sdes } 879238106Sdes 880238106Sdes /* grab the tcp handler buffers */ 881238106Sdes c->tcp_free = c_hdl->tcp_free; 882238106Sdes if(!c->tcp_free) { 883238106Sdes /* stop accepting incoming queries for now. */ 884238106Sdes comm_point_stop_listening(c); 885238106Sdes } 886238106Sdes /* addr is dropped. Not needed for tcp reply. */ 887238106Sdes setup_tcp_handler(c_hdl, new_fd); 888238106Sdes} 889238106Sdes 890238106Sdes/** Make tcp handler free for next assignment */ 891238106Sdesstatic void 892238106Sdesreclaim_tcp_handler(struct comm_point* c) 893238106Sdes{ 894238106Sdes log_assert(c->type == comm_tcp); 895238106Sdes if(c->ssl) { 896249141Sdes#ifdef HAVE_SSL 897238106Sdes SSL_shutdown(c->ssl); 898238106Sdes SSL_free(c->ssl); 899238106Sdes c->ssl = NULL; 900249141Sdes#endif 901238106Sdes } 902238106Sdes comm_point_close(c); 903238106Sdes if(c->tcp_parent) { 904238106Sdes c->tcp_free = c->tcp_parent->tcp_free; 905238106Sdes c->tcp_parent->tcp_free = c; 906238106Sdes if(!c->tcp_free) { 907238106Sdes /* re-enable listening on accept socket */ 908238106Sdes comm_point_start_listening(c->tcp_parent, -1, -1); 909238106Sdes } 910238106Sdes } 911238106Sdes} 912238106Sdes 913238106Sdes/** do the callback when writing is done */ 914238106Sdesstatic void 915238106Sdestcp_callback_writer(struct comm_point* c) 916238106Sdes{ 917238106Sdes log_assert(c->type == comm_tcp); 918269257Sdes sldns_buffer_clear(c->buffer); 919238106Sdes if(c->tcp_do_toggle_rw) 920238106Sdes c->tcp_is_reading = 1; 921238106Sdes c->tcp_byte_count = 0; 922238106Sdes /* switch from listening(write) to listening(read) */ 923238106Sdes comm_point_stop_listening(c); 924238106Sdes comm_point_start_listening(c, -1, -1); 925238106Sdes} 926238106Sdes 927238106Sdes/** do the callback when reading is done */ 928238106Sdesstatic void 929238106Sdestcp_callback_reader(struct comm_point* c) 930238106Sdes{ 931238106Sdes log_assert(c->type == comm_tcp || c->type == comm_local); 932269257Sdes sldns_buffer_flip(c->buffer); 933238106Sdes if(c->tcp_do_toggle_rw) 934238106Sdes c->tcp_is_reading = 0; 935238106Sdes c->tcp_byte_count = 0; 936238106Sdes if(c->type == comm_tcp) 937238106Sdes comm_point_stop_listening(c); 938238106Sdes fptr_ok(fptr_whitelist_comm_point(c->callback)); 939238106Sdes if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) { 940238106Sdes comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT); 941238106Sdes } 942238106Sdes} 943238106Sdes 944238106Sdes/** continue ssl handshake */ 945249141Sdes#ifdef HAVE_SSL 946238106Sdesstatic int 947238106Sdesssl_handshake(struct comm_point* c) 948238106Sdes{ 949238106Sdes int r; 950238106Sdes if(c->ssl_shake_state == comm_ssl_shake_hs_read) { 951238106Sdes /* read condition satisfied back to writing */ 952238106Sdes comm_point_listen_for_rw(c, 1, 1); 953238106Sdes c->ssl_shake_state = comm_ssl_shake_none; 954238106Sdes return 1; 955238106Sdes } 956238106Sdes if(c->ssl_shake_state == comm_ssl_shake_hs_write) { 957238106Sdes /* write condition satisfied, back to reading */ 958238106Sdes comm_point_listen_for_rw(c, 1, 0); 959238106Sdes c->ssl_shake_state = comm_ssl_shake_none; 960238106Sdes return 1; 961238106Sdes } 962238106Sdes 963238106Sdes ERR_clear_error(); 964238106Sdes r = SSL_do_handshake(c->ssl); 965238106Sdes if(r != 1) { 966238106Sdes int want = SSL_get_error(c->ssl, r); 967238106Sdes if(want == SSL_ERROR_WANT_READ) { 968238106Sdes if(c->ssl_shake_state == comm_ssl_shake_read) 969238106Sdes return 1; 970238106Sdes c->ssl_shake_state = comm_ssl_shake_read; 971238106Sdes comm_point_listen_for_rw(c, 1, 0); 972238106Sdes return 1; 973238106Sdes } else if(want == SSL_ERROR_WANT_WRITE) { 974238106Sdes if(c->ssl_shake_state == comm_ssl_shake_write) 975238106Sdes return 1; 976238106Sdes c->ssl_shake_state = comm_ssl_shake_write; 977238106Sdes comm_point_listen_for_rw(c, 0, 1); 978238106Sdes return 1; 979238106Sdes } else if(r == 0) { 980238106Sdes return 0; /* closed */ 981238106Sdes } else if(want == SSL_ERROR_SYSCALL) { 982238106Sdes /* SYSCALL and errno==0 means closed uncleanly */ 983238106Sdes if(errno != 0) 984238106Sdes log_err("SSL_handshake syscall: %s", 985238106Sdes strerror(errno)); 986238106Sdes return 0; 987238106Sdes } else { 988238106Sdes log_crypto_err("ssl handshake failed"); 989238106Sdes log_addr(1, "ssl handshake failed", &c->repinfo.addr, 990238106Sdes c->repinfo.addrlen); 991238106Sdes return 0; 992238106Sdes } 993238106Sdes } 994238106Sdes /* this is where peer verification could take place */ 995238106Sdes log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr, 996238106Sdes c->repinfo.addrlen); 997238106Sdes 998238106Sdes /* setup listen rw correctly */ 999238106Sdes if(c->tcp_is_reading) { 1000238106Sdes if(c->ssl_shake_state != comm_ssl_shake_read) 1001238106Sdes comm_point_listen_for_rw(c, 1, 0); 1002238106Sdes } else { 1003238106Sdes comm_point_listen_for_rw(c, 1, 1); 1004238106Sdes } 1005238106Sdes c->ssl_shake_state = comm_ssl_shake_none; 1006238106Sdes return 1; 1007238106Sdes} 1008249141Sdes#endif /* HAVE_SSL */ 1009238106Sdes 1010238106Sdes/** ssl read callback on TCP */ 1011238106Sdesstatic int 1012238106Sdesssl_handle_read(struct comm_point* c) 1013238106Sdes{ 1014249141Sdes#ifdef HAVE_SSL 1015238106Sdes int r; 1016238106Sdes if(c->ssl_shake_state != comm_ssl_shake_none) { 1017238106Sdes if(!ssl_handshake(c)) 1018238106Sdes return 0; 1019238106Sdes if(c->ssl_shake_state != comm_ssl_shake_none) 1020238106Sdes return 1; 1021238106Sdes } 1022238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) { 1023238106Sdes /* read length bytes */ 1024238106Sdes ERR_clear_error(); 1025269257Sdes if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer, 1026238106Sdes c->tcp_byte_count), (int)(sizeof(uint16_t) - 1027238106Sdes c->tcp_byte_count))) <= 0) { 1028238106Sdes int want = SSL_get_error(c->ssl, r); 1029238106Sdes if(want == SSL_ERROR_ZERO_RETURN) { 1030238106Sdes return 0; /* shutdown, closed */ 1031238106Sdes } else if(want == SSL_ERROR_WANT_READ) { 1032238106Sdes return 1; /* read more later */ 1033238106Sdes } else if(want == SSL_ERROR_WANT_WRITE) { 1034238106Sdes c->ssl_shake_state = comm_ssl_shake_hs_write; 1035238106Sdes comm_point_listen_for_rw(c, 0, 1); 1036238106Sdes return 1; 1037238106Sdes } else if(want == SSL_ERROR_SYSCALL) { 1038238106Sdes if(errno != 0) 1039238106Sdes log_err("SSL_read syscall: %s", 1040238106Sdes strerror(errno)); 1041238106Sdes return 0; 1042238106Sdes } 1043238106Sdes log_crypto_err("could not SSL_read"); 1044238106Sdes return 0; 1045238106Sdes } 1046238106Sdes c->tcp_byte_count += r; 1047238106Sdes if(c->tcp_byte_count != sizeof(uint16_t)) 1048238106Sdes return 1; 1049269257Sdes if(sldns_buffer_read_u16_at(c->buffer, 0) > 1050269257Sdes sldns_buffer_capacity(c->buffer)) { 1051238106Sdes verbose(VERB_QUERY, "ssl: dropped larger than buffer"); 1052238106Sdes return 0; 1053238106Sdes } 1054269257Sdes sldns_buffer_set_limit(c->buffer, 1055269257Sdes sldns_buffer_read_u16_at(c->buffer, 0)); 1056269257Sdes if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1057238106Sdes verbose(VERB_QUERY, "ssl: dropped bogus too short."); 1058238106Sdes return 0; 1059238106Sdes } 1060238106Sdes verbose(VERB_ALGO, "Reading ssl tcp query of length %d", 1061269257Sdes (int)sldns_buffer_limit(c->buffer)); 1062238106Sdes } 1063269257Sdes log_assert(sldns_buffer_remaining(c->buffer) > 0); 1064238106Sdes ERR_clear_error(); 1065269257Sdes r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer), 1066269257Sdes (int)sldns_buffer_remaining(c->buffer)); 1067238106Sdes if(r <= 0) { 1068238106Sdes int want = SSL_get_error(c->ssl, r); 1069238106Sdes if(want == SSL_ERROR_ZERO_RETURN) { 1070238106Sdes return 0; /* shutdown, closed */ 1071238106Sdes } else if(want == SSL_ERROR_WANT_READ) { 1072238106Sdes return 1; /* read more later */ 1073238106Sdes } else if(want == SSL_ERROR_WANT_WRITE) { 1074238106Sdes c->ssl_shake_state = comm_ssl_shake_hs_write; 1075238106Sdes comm_point_listen_for_rw(c, 0, 1); 1076238106Sdes return 1; 1077238106Sdes } else if(want == SSL_ERROR_SYSCALL) { 1078238106Sdes if(errno != 0) 1079238106Sdes log_err("SSL_read syscall: %s", 1080238106Sdes strerror(errno)); 1081238106Sdes return 0; 1082238106Sdes } 1083238106Sdes log_crypto_err("could not SSL_read"); 1084238106Sdes return 0; 1085238106Sdes } 1086269257Sdes sldns_buffer_skip(c->buffer, (ssize_t)r); 1087269257Sdes if(sldns_buffer_remaining(c->buffer) <= 0) { 1088238106Sdes tcp_callback_reader(c); 1089238106Sdes } 1090238106Sdes return 1; 1091249141Sdes#else 1092249141Sdes (void)c; 1093249141Sdes return 0; 1094249141Sdes#endif /* HAVE_SSL */ 1095238106Sdes} 1096238106Sdes 1097238106Sdes/** ssl write callback on TCP */ 1098238106Sdesstatic int 1099238106Sdesssl_handle_write(struct comm_point* c) 1100238106Sdes{ 1101249141Sdes#ifdef HAVE_SSL 1102238106Sdes int r; 1103238106Sdes if(c->ssl_shake_state != comm_ssl_shake_none) { 1104238106Sdes if(!ssl_handshake(c)) 1105238106Sdes return 0; 1106238106Sdes if(c->ssl_shake_state != comm_ssl_shake_none) 1107238106Sdes return 1; 1108238106Sdes } 1109238106Sdes /* ignore return, if fails we may simply block */ 1110238106Sdes (void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); 1111238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) { 1112269257Sdes uint16_t len = htons(sldns_buffer_limit(c->buffer)); 1113238106Sdes ERR_clear_error(); 1114238106Sdes r = SSL_write(c->ssl, 1115238106Sdes (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1116238106Sdes (int)(sizeof(uint16_t)-c->tcp_byte_count)); 1117238106Sdes if(r <= 0) { 1118238106Sdes int want = SSL_get_error(c->ssl, r); 1119238106Sdes if(want == SSL_ERROR_ZERO_RETURN) { 1120238106Sdes return 0; /* closed */ 1121238106Sdes } else if(want == SSL_ERROR_WANT_READ) { 1122238106Sdes c->ssl_shake_state = comm_ssl_shake_read; 1123238106Sdes comm_point_listen_for_rw(c, 1, 0); 1124238106Sdes return 1; /* wait for read condition */ 1125238106Sdes } else if(want == SSL_ERROR_WANT_WRITE) { 1126238106Sdes return 1; /* write more later */ 1127238106Sdes } else if(want == SSL_ERROR_SYSCALL) { 1128238106Sdes if(errno != 0) 1129238106Sdes log_err("SSL_write syscall: %s", 1130238106Sdes strerror(errno)); 1131238106Sdes return 0; 1132238106Sdes } 1133238106Sdes log_crypto_err("could not SSL_write"); 1134238106Sdes return 0; 1135238106Sdes } 1136238106Sdes c->tcp_byte_count += r; 1137238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) 1138238106Sdes return 1; 1139269257Sdes sldns_buffer_set_position(c->buffer, c->tcp_byte_count - 1140238106Sdes sizeof(uint16_t)); 1141269257Sdes if(sldns_buffer_remaining(c->buffer) == 0) { 1142238106Sdes tcp_callback_writer(c); 1143238106Sdes return 1; 1144238106Sdes } 1145238106Sdes } 1146269257Sdes log_assert(sldns_buffer_remaining(c->buffer) > 0); 1147238106Sdes ERR_clear_error(); 1148269257Sdes r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer), 1149269257Sdes (int)sldns_buffer_remaining(c->buffer)); 1150238106Sdes if(r <= 0) { 1151238106Sdes int want = SSL_get_error(c->ssl, r); 1152238106Sdes if(want == SSL_ERROR_ZERO_RETURN) { 1153238106Sdes return 0; /* closed */ 1154238106Sdes } else if(want == SSL_ERROR_WANT_READ) { 1155238106Sdes c->ssl_shake_state = comm_ssl_shake_read; 1156238106Sdes comm_point_listen_for_rw(c, 1, 0); 1157238106Sdes return 1; /* wait for read condition */ 1158238106Sdes } else if(want == SSL_ERROR_WANT_WRITE) { 1159238106Sdes return 1; /* write more later */ 1160238106Sdes } else if(want == SSL_ERROR_SYSCALL) { 1161238106Sdes if(errno != 0) 1162238106Sdes log_err("SSL_write syscall: %s", 1163238106Sdes strerror(errno)); 1164238106Sdes return 0; 1165238106Sdes } 1166238106Sdes log_crypto_err("could not SSL_write"); 1167238106Sdes return 0; 1168238106Sdes } 1169269257Sdes sldns_buffer_skip(c->buffer, (ssize_t)r); 1170238106Sdes 1171269257Sdes if(sldns_buffer_remaining(c->buffer) == 0) { 1172238106Sdes tcp_callback_writer(c); 1173238106Sdes } 1174238106Sdes return 1; 1175249141Sdes#else 1176249141Sdes (void)c; 1177249141Sdes return 0; 1178249141Sdes#endif /* HAVE_SSL */ 1179238106Sdes} 1180238106Sdes 1181238106Sdes/** handle ssl tcp connection with dns contents */ 1182238106Sdesstatic int 1183238106Sdesssl_handle_it(struct comm_point* c) 1184238106Sdes{ 1185238106Sdes if(c->tcp_is_reading) 1186238106Sdes return ssl_handle_read(c); 1187238106Sdes return ssl_handle_write(c); 1188238106Sdes} 1189238106Sdes 1190238106Sdes/** Handle tcp reading callback. 1191238106Sdes * @param fd: file descriptor of socket. 1192238106Sdes * @param c: comm point to read from into buffer. 1193238106Sdes * @param short_ok: if true, very short packets are OK (for comm_local). 1194238106Sdes * @return: 0 on error 1195238106Sdes */ 1196238106Sdesstatic int 1197238106Sdescomm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) 1198238106Sdes{ 1199238106Sdes ssize_t r; 1200238106Sdes log_assert(c->type == comm_tcp || c->type == comm_local); 1201238106Sdes if(c->ssl) 1202238106Sdes return ssl_handle_it(c); 1203238106Sdes if(!c->tcp_is_reading) 1204238106Sdes return 0; 1205238106Sdes 1206238106Sdes log_assert(fd != -1); 1207238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) { 1208238106Sdes /* read length bytes */ 1209269257Sdes r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count), 1210238106Sdes sizeof(uint16_t)-c->tcp_byte_count, 0); 1211238106Sdes if(r == 0) 1212238106Sdes return 0; 1213238106Sdes else if(r == -1) { 1214238106Sdes#ifndef USE_WINSOCK 1215238106Sdes if(errno == EINTR || errno == EAGAIN) 1216238106Sdes return 1; 1217238106Sdes#ifdef ECONNRESET 1218238106Sdes if(errno == ECONNRESET && verbosity < 2) 1219238106Sdes return 0; /* silence reset by peer */ 1220238106Sdes#endif 1221238106Sdes log_err("read (in tcp s): %s", strerror(errno)); 1222238106Sdes#else /* USE_WINSOCK */ 1223238106Sdes if(WSAGetLastError() == WSAECONNRESET) 1224238106Sdes return 0; 1225238106Sdes if(WSAGetLastError() == WSAEINPROGRESS) 1226238106Sdes return 1; 1227238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) { 1228238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 1229238106Sdes return 1; 1230238106Sdes } 1231238106Sdes log_err("read (in tcp s): %s", 1232238106Sdes wsa_strerror(WSAGetLastError())); 1233238106Sdes#endif 1234238106Sdes log_addr(0, "remote address is", &c->repinfo.addr, 1235238106Sdes c->repinfo.addrlen); 1236238106Sdes return 0; 1237238106Sdes } 1238238106Sdes c->tcp_byte_count += r; 1239238106Sdes if(c->tcp_byte_count != sizeof(uint16_t)) 1240238106Sdes return 1; 1241269257Sdes if(sldns_buffer_read_u16_at(c->buffer, 0) > 1242269257Sdes sldns_buffer_capacity(c->buffer)) { 1243238106Sdes verbose(VERB_QUERY, "tcp: dropped larger than buffer"); 1244238106Sdes return 0; 1245238106Sdes } 1246269257Sdes sldns_buffer_set_limit(c->buffer, 1247269257Sdes sldns_buffer_read_u16_at(c->buffer, 0)); 1248238106Sdes if(!short_ok && 1249269257Sdes sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1250238106Sdes verbose(VERB_QUERY, "tcp: dropped bogus too short."); 1251238106Sdes return 0; 1252238106Sdes } 1253238106Sdes verbose(VERB_ALGO, "Reading tcp query of length %d", 1254269257Sdes (int)sldns_buffer_limit(c->buffer)); 1255238106Sdes } 1256238106Sdes 1257269257Sdes log_assert(sldns_buffer_remaining(c->buffer) > 0); 1258269257Sdes r = recv(fd, (void*)sldns_buffer_current(c->buffer), 1259269257Sdes sldns_buffer_remaining(c->buffer), 0); 1260238106Sdes if(r == 0) { 1261238106Sdes return 0; 1262238106Sdes } else if(r == -1) { 1263238106Sdes#ifndef USE_WINSOCK 1264238106Sdes if(errno == EINTR || errno == EAGAIN) 1265238106Sdes return 1; 1266238106Sdes log_err("read (in tcp r): %s", strerror(errno)); 1267238106Sdes#else /* USE_WINSOCK */ 1268238106Sdes if(WSAGetLastError() == WSAECONNRESET) 1269238106Sdes return 0; 1270238106Sdes if(WSAGetLastError() == WSAEINPROGRESS) 1271238106Sdes return 1; 1272238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) { 1273238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 1274238106Sdes return 1; 1275238106Sdes } 1276238106Sdes log_err("read (in tcp r): %s", 1277238106Sdes wsa_strerror(WSAGetLastError())); 1278238106Sdes#endif 1279238106Sdes log_addr(0, "remote address is", &c->repinfo.addr, 1280238106Sdes c->repinfo.addrlen); 1281238106Sdes return 0; 1282238106Sdes } 1283269257Sdes sldns_buffer_skip(c->buffer, r); 1284269257Sdes if(sldns_buffer_remaining(c->buffer) <= 0) { 1285238106Sdes tcp_callback_reader(c); 1286238106Sdes } 1287238106Sdes return 1; 1288238106Sdes} 1289238106Sdes 1290238106Sdes/** 1291238106Sdes * Handle tcp writing callback. 1292238106Sdes * @param fd: file descriptor of socket. 1293238106Sdes * @param c: comm point to write buffer out of. 1294238106Sdes * @return: 0 on error 1295238106Sdes */ 1296238106Sdesstatic int 1297238106Sdescomm_point_tcp_handle_write(int fd, struct comm_point* c) 1298238106Sdes{ 1299238106Sdes ssize_t r; 1300238106Sdes log_assert(c->type == comm_tcp); 1301238106Sdes if(c->tcp_is_reading && !c->ssl) 1302238106Sdes return 0; 1303238106Sdes log_assert(fd != -1); 1304238106Sdes if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) { 1305238106Sdes /* check for pending error from nonblocking connect */ 1306238106Sdes /* from Stevens, unix network programming, vol1, 3rd ed, p450*/ 1307238106Sdes int error = 0; 1308238106Sdes socklen_t len = (socklen_t)sizeof(error); 1309238106Sdes if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1310238106Sdes &len) < 0){ 1311238106Sdes#ifndef USE_WINSOCK 1312238106Sdes error = errno; /* on solaris errno is error */ 1313238106Sdes#else /* USE_WINSOCK */ 1314238106Sdes error = WSAGetLastError(); 1315238106Sdes#endif 1316238106Sdes } 1317238106Sdes#ifndef USE_WINSOCK 1318238106Sdes#if defined(EINPROGRESS) && defined(EWOULDBLOCK) 1319238106Sdes if(error == EINPROGRESS || error == EWOULDBLOCK) 1320238106Sdes return 1; /* try again later */ 1321238106Sdes else 1322238106Sdes#endif 1323238106Sdes if(error != 0 && verbosity < 2) 1324238106Sdes return 0; /* silence lots of chatter in the logs */ 1325238106Sdes else if(error != 0) { 1326238106Sdes log_err("tcp connect: %s", strerror(error)); 1327238106Sdes#else /* USE_WINSOCK */ 1328238106Sdes /* examine error */ 1329238106Sdes if(error == WSAEINPROGRESS) 1330238106Sdes return 1; 1331238106Sdes else if(error == WSAEWOULDBLOCK) { 1332238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1333238106Sdes return 1; 1334238106Sdes } else if(error != 0 && verbosity < 2) 1335238106Sdes return 0; 1336238106Sdes else if(error != 0) { 1337238106Sdes log_err("tcp connect: %s", wsa_strerror(error)); 1338238106Sdes#endif /* USE_WINSOCK */ 1339238106Sdes log_addr(0, "remote address is", &c->repinfo.addr, 1340238106Sdes c->repinfo.addrlen); 1341238106Sdes return 0; 1342238106Sdes } 1343238106Sdes } 1344238106Sdes if(c->ssl) 1345238106Sdes return ssl_handle_it(c); 1346238106Sdes 1347238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) { 1348269257Sdes uint16_t len = htons(sldns_buffer_limit(c->buffer)); 1349238106Sdes#ifdef HAVE_WRITEV 1350238106Sdes struct iovec iov[2]; 1351238106Sdes iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count; 1352238106Sdes iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count; 1353269257Sdes iov[1].iov_base = sldns_buffer_begin(c->buffer); 1354269257Sdes iov[1].iov_len = sldns_buffer_limit(c->buffer); 1355238106Sdes log_assert(iov[0].iov_len > 0); 1356238106Sdes log_assert(iov[1].iov_len > 0); 1357238106Sdes r = writev(fd, iov, 2); 1358238106Sdes#else /* HAVE_WRITEV */ 1359238106Sdes r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1360238106Sdes sizeof(uint16_t)-c->tcp_byte_count, 0); 1361238106Sdes#endif /* HAVE_WRITEV */ 1362238106Sdes if(r == -1) { 1363238106Sdes#ifndef USE_WINSOCK 1364238106Sdes#ifdef EPIPE 1365238106Sdes if(errno == EPIPE && verbosity < 2) 1366238106Sdes return 0; /* silence 'broken pipe' */ 1367238106Sdes#endif 1368238106Sdes if(errno == EINTR || errno == EAGAIN) 1369238106Sdes return 1; 1370238106Sdes log_err("tcp writev: %s", strerror(errno)); 1371238106Sdes#else 1372238106Sdes if(WSAGetLastError() == WSAENOTCONN) 1373238106Sdes return 1; 1374238106Sdes if(WSAGetLastError() == WSAEINPROGRESS) 1375238106Sdes return 1; 1376238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) { 1377238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1378238106Sdes return 1; 1379238106Sdes } 1380238106Sdes log_err("tcp send s: %s", 1381238106Sdes wsa_strerror(WSAGetLastError())); 1382238106Sdes#endif 1383238106Sdes log_addr(0, "remote address is", &c->repinfo.addr, 1384238106Sdes c->repinfo.addrlen); 1385238106Sdes return 0; 1386238106Sdes } 1387238106Sdes c->tcp_byte_count += r; 1388238106Sdes if(c->tcp_byte_count < sizeof(uint16_t)) 1389238106Sdes return 1; 1390269257Sdes sldns_buffer_set_position(c->buffer, c->tcp_byte_count - 1391238106Sdes sizeof(uint16_t)); 1392269257Sdes if(sldns_buffer_remaining(c->buffer) == 0) { 1393238106Sdes tcp_callback_writer(c); 1394238106Sdes return 1; 1395238106Sdes } 1396238106Sdes } 1397269257Sdes log_assert(sldns_buffer_remaining(c->buffer) > 0); 1398269257Sdes r = send(fd, (void*)sldns_buffer_current(c->buffer), 1399269257Sdes sldns_buffer_remaining(c->buffer), 0); 1400238106Sdes if(r == -1) { 1401238106Sdes#ifndef USE_WINSOCK 1402238106Sdes if(errno == EINTR || errno == EAGAIN) 1403238106Sdes return 1; 1404238106Sdes log_err("tcp send r: %s", strerror(errno)); 1405238106Sdes#else 1406238106Sdes if(WSAGetLastError() == WSAEINPROGRESS) 1407238106Sdes return 1; 1408238106Sdes if(WSAGetLastError() == WSAEWOULDBLOCK) { 1409238106Sdes winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1410238106Sdes return 1; 1411238106Sdes } 1412238106Sdes log_err("tcp send r: %s", 1413238106Sdes wsa_strerror(WSAGetLastError())); 1414238106Sdes#endif 1415238106Sdes log_addr(0, "remote address is", &c->repinfo.addr, 1416238106Sdes c->repinfo.addrlen); 1417238106Sdes return 0; 1418238106Sdes } 1419269257Sdes sldns_buffer_skip(c->buffer, r); 1420238106Sdes 1421269257Sdes if(sldns_buffer_remaining(c->buffer) == 0) { 1422238106Sdes tcp_callback_writer(c); 1423238106Sdes } 1424238106Sdes 1425238106Sdes return 1; 1426238106Sdes} 1427238106Sdes 1428238106Sdesvoid 1429238106Sdescomm_point_tcp_handle_callback(int fd, short event, void* arg) 1430238106Sdes{ 1431238106Sdes struct comm_point* c = (struct comm_point*)arg; 1432238106Sdes log_assert(c->type == comm_tcp); 1433238106Sdes comm_base_now(c->ev->base); 1434238106Sdes 1435238106Sdes if(event&EV_READ) { 1436238106Sdes if(!comm_point_tcp_handle_read(fd, c, 0)) { 1437238106Sdes reclaim_tcp_handler(c); 1438238106Sdes if(!c->tcp_do_close) { 1439238106Sdes fptr_ok(fptr_whitelist_comm_point( 1440238106Sdes c->callback)); 1441238106Sdes (void)(*c->callback)(c, c->cb_arg, 1442238106Sdes NETEVENT_CLOSED, NULL); 1443238106Sdes } 1444238106Sdes } 1445238106Sdes return; 1446238106Sdes } 1447238106Sdes if(event&EV_WRITE) { 1448238106Sdes if(!comm_point_tcp_handle_write(fd, c)) { 1449238106Sdes reclaim_tcp_handler(c); 1450238106Sdes if(!c->tcp_do_close) { 1451238106Sdes fptr_ok(fptr_whitelist_comm_point( 1452238106Sdes c->callback)); 1453238106Sdes (void)(*c->callback)(c, c->cb_arg, 1454238106Sdes NETEVENT_CLOSED, NULL); 1455238106Sdes } 1456238106Sdes } 1457238106Sdes return; 1458238106Sdes } 1459238106Sdes if(event&EV_TIMEOUT) { 1460238106Sdes verbose(VERB_QUERY, "tcp took too long, dropped"); 1461238106Sdes reclaim_tcp_handler(c); 1462238106Sdes if(!c->tcp_do_close) { 1463238106Sdes fptr_ok(fptr_whitelist_comm_point(c->callback)); 1464238106Sdes (void)(*c->callback)(c, c->cb_arg, 1465238106Sdes NETEVENT_TIMEOUT, NULL); 1466238106Sdes } 1467238106Sdes return; 1468238106Sdes } 1469238106Sdes log_err("Ignored event %d for tcphdl.", event); 1470238106Sdes} 1471238106Sdes 1472238106Sdesvoid comm_point_local_handle_callback(int fd, short event, void* arg) 1473238106Sdes{ 1474238106Sdes struct comm_point* c = (struct comm_point*)arg; 1475238106Sdes log_assert(c->type == comm_local); 1476238106Sdes comm_base_now(c->ev->base); 1477238106Sdes 1478238106Sdes if(event&EV_READ) { 1479238106Sdes if(!comm_point_tcp_handle_read(fd, c, 1)) { 1480238106Sdes fptr_ok(fptr_whitelist_comm_point(c->callback)); 1481238106Sdes (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED, 1482238106Sdes NULL); 1483238106Sdes } 1484238106Sdes return; 1485238106Sdes } 1486238106Sdes log_err("Ignored event %d for localhdl.", event); 1487238106Sdes} 1488238106Sdes 1489238106Sdesvoid comm_point_raw_handle_callback(int ATTR_UNUSED(fd), 1490238106Sdes short event, void* arg) 1491238106Sdes{ 1492238106Sdes struct comm_point* c = (struct comm_point*)arg; 1493238106Sdes int err = NETEVENT_NOERROR; 1494238106Sdes log_assert(c->type == comm_raw); 1495238106Sdes comm_base_now(c->ev->base); 1496238106Sdes 1497238106Sdes if(event&EV_TIMEOUT) 1498238106Sdes err = NETEVENT_TIMEOUT; 1499238106Sdes fptr_ok(fptr_whitelist_comm_point_raw(c->callback)); 1500238106Sdes (void)(*c->callback)(c, c->cb_arg, err, NULL); 1501238106Sdes} 1502238106Sdes 1503238106Sdesstruct comm_point* 1504269257Sdescomm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, 1505238106Sdes comm_point_callback_t* callback, void* callback_arg) 1506238106Sdes{ 1507238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1508238106Sdes sizeof(struct comm_point)); 1509238106Sdes short evbits; 1510238106Sdes if(!c) 1511238106Sdes return NULL; 1512238106Sdes c->ev = (struct internal_event*)calloc(1, 1513238106Sdes sizeof(struct internal_event)); 1514238106Sdes if(!c->ev) { 1515238106Sdes free(c); 1516238106Sdes return NULL; 1517238106Sdes } 1518238106Sdes c->ev->base = base; 1519238106Sdes c->fd = fd; 1520238106Sdes c->buffer = buffer; 1521238106Sdes c->timeout = NULL; 1522238106Sdes c->tcp_is_reading = 0; 1523238106Sdes c->tcp_byte_count = 0; 1524238106Sdes c->tcp_parent = NULL; 1525238106Sdes c->max_tcp_count = 0; 1526238106Sdes c->tcp_handlers = NULL; 1527238106Sdes c->tcp_free = NULL; 1528238106Sdes c->type = comm_udp; 1529238106Sdes c->tcp_do_close = 0; 1530238106Sdes c->do_not_close = 0; 1531238106Sdes c->tcp_do_toggle_rw = 0; 1532238106Sdes c->tcp_check_nb_connect = 0; 1533238106Sdes c->inuse = 0; 1534238106Sdes c->callback = callback; 1535238106Sdes c->cb_arg = callback_arg; 1536238106Sdes evbits = EV_READ | EV_PERSIST; 1537238106Sdes /* libevent stuff */ 1538238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c); 1539238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0) { 1540238106Sdes log_err("could not baseset udp event"); 1541238106Sdes comm_point_delete(c); 1542238106Sdes return NULL; 1543238106Sdes } 1544238106Sdes if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) { 1545238106Sdes log_err("could not add udp event"); 1546238106Sdes comm_point_delete(c); 1547238106Sdes return NULL; 1548238106Sdes } 1549238106Sdes return c; 1550238106Sdes} 1551238106Sdes 1552238106Sdesstruct comm_point* 1553238106Sdescomm_point_create_udp_ancil(struct comm_base *base, int fd, 1554269257Sdes sldns_buffer* buffer, 1555238106Sdes comm_point_callback_t* callback, void* callback_arg) 1556238106Sdes{ 1557238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1558238106Sdes sizeof(struct comm_point)); 1559238106Sdes short evbits; 1560238106Sdes if(!c) 1561238106Sdes return NULL; 1562238106Sdes c->ev = (struct internal_event*)calloc(1, 1563238106Sdes sizeof(struct internal_event)); 1564238106Sdes if(!c->ev) { 1565238106Sdes free(c); 1566238106Sdes return NULL; 1567238106Sdes } 1568238106Sdes c->ev->base = base; 1569238106Sdes c->fd = fd; 1570238106Sdes c->buffer = buffer; 1571238106Sdes c->timeout = NULL; 1572238106Sdes c->tcp_is_reading = 0; 1573238106Sdes c->tcp_byte_count = 0; 1574238106Sdes c->tcp_parent = NULL; 1575238106Sdes c->max_tcp_count = 0; 1576238106Sdes c->tcp_handlers = NULL; 1577238106Sdes c->tcp_free = NULL; 1578238106Sdes c->type = comm_udp; 1579238106Sdes c->tcp_do_close = 0; 1580238106Sdes c->do_not_close = 0; 1581238106Sdes c->inuse = 0; 1582238106Sdes c->tcp_do_toggle_rw = 0; 1583238106Sdes c->tcp_check_nb_connect = 0; 1584238106Sdes c->callback = callback; 1585238106Sdes c->cb_arg = callback_arg; 1586238106Sdes evbits = EV_READ | EV_PERSIST; 1587238106Sdes /* libevent stuff */ 1588238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_ancil_callback, c); 1589238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0) { 1590238106Sdes log_err("could not baseset udp event"); 1591238106Sdes comm_point_delete(c); 1592238106Sdes return NULL; 1593238106Sdes } 1594238106Sdes if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) { 1595238106Sdes log_err("could not add udp event"); 1596238106Sdes comm_point_delete(c); 1597238106Sdes return NULL; 1598238106Sdes } 1599238106Sdes return c; 1600238106Sdes} 1601238106Sdes 1602238106Sdesstatic struct comm_point* 1603238106Sdescomm_point_create_tcp_handler(struct comm_base *base, 1604238106Sdes struct comm_point* parent, size_t bufsize, 1605238106Sdes comm_point_callback_t* callback, void* callback_arg) 1606238106Sdes{ 1607238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1608238106Sdes sizeof(struct comm_point)); 1609238106Sdes short evbits; 1610238106Sdes if(!c) 1611238106Sdes return NULL; 1612238106Sdes c->ev = (struct internal_event*)calloc(1, 1613238106Sdes sizeof(struct internal_event)); 1614238106Sdes if(!c->ev) { 1615238106Sdes free(c); 1616238106Sdes return NULL; 1617238106Sdes } 1618238106Sdes c->ev->base = base; 1619238106Sdes c->fd = -1; 1620269257Sdes c->buffer = sldns_buffer_new(bufsize); 1621238106Sdes if(!c->buffer) { 1622238106Sdes free(c->ev); 1623238106Sdes free(c); 1624238106Sdes return NULL; 1625238106Sdes } 1626238106Sdes c->timeout = (struct timeval*)malloc(sizeof(struct timeval)); 1627238106Sdes if(!c->timeout) { 1628269257Sdes sldns_buffer_free(c->buffer); 1629238106Sdes free(c->ev); 1630238106Sdes free(c); 1631238106Sdes return NULL; 1632238106Sdes } 1633238106Sdes c->tcp_is_reading = 0; 1634238106Sdes c->tcp_byte_count = 0; 1635238106Sdes c->tcp_parent = parent; 1636238106Sdes c->max_tcp_count = 0; 1637238106Sdes c->tcp_handlers = NULL; 1638238106Sdes c->tcp_free = NULL; 1639238106Sdes c->type = comm_tcp; 1640238106Sdes c->tcp_do_close = 0; 1641238106Sdes c->do_not_close = 0; 1642238106Sdes c->tcp_do_toggle_rw = 1; 1643238106Sdes c->tcp_check_nb_connect = 0; 1644238106Sdes c->repinfo.c = c; 1645238106Sdes c->callback = callback; 1646238106Sdes c->cb_arg = callback_arg; 1647238106Sdes /* add to parent free list */ 1648238106Sdes c->tcp_free = parent->tcp_free; 1649238106Sdes parent->tcp_free = c; 1650238106Sdes /* libevent stuff */ 1651238106Sdes evbits = EV_PERSIST | EV_READ | EV_TIMEOUT; 1652238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c); 1653238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0) 1654238106Sdes { 1655238106Sdes log_err("could not basetset tcphdl event"); 1656238106Sdes parent->tcp_free = c->tcp_free; 1657238106Sdes free(c->ev); 1658238106Sdes free(c); 1659238106Sdes return NULL; 1660238106Sdes } 1661238106Sdes return c; 1662238106Sdes} 1663238106Sdes 1664238106Sdesstruct comm_point* 1665238106Sdescomm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, 1666238106Sdes comm_point_callback_t* callback, void* callback_arg) 1667238106Sdes{ 1668238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1669238106Sdes sizeof(struct comm_point)); 1670238106Sdes short evbits; 1671238106Sdes int i; 1672238106Sdes /* first allocate the TCP accept listener */ 1673238106Sdes if(!c) 1674238106Sdes return NULL; 1675238106Sdes c->ev = (struct internal_event*)calloc(1, 1676238106Sdes sizeof(struct internal_event)); 1677238106Sdes if(!c->ev) { 1678238106Sdes free(c); 1679238106Sdes return NULL; 1680238106Sdes } 1681238106Sdes c->ev->base = base; 1682238106Sdes c->fd = fd; 1683238106Sdes c->buffer = NULL; 1684238106Sdes c->timeout = NULL; 1685238106Sdes c->tcp_is_reading = 0; 1686238106Sdes c->tcp_byte_count = 0; 1687238106Sdes c->tcp_parent = NULL; 1688238106Sdes c->max_tcp_count = num; 1689238106Sdes c->tcp_handlers = (struct comm_point**)calloc((size_t)num, 1690238106Sdes sizeof(struct comm_point*)); 1691238106Sdes if(!c->tcp_handlers) { 1692238106Sdes free(c->ev); 1693238106Sdes free(c); 1694238106Sdes return NULL; 1695238106Sdes } 1696238106Sdes c->tcp_free = NULL; 1697238106Sdes c->type = comm_tcp_accept; 1698238106Sdes c->tcp_do_close = 0; 1699238106Sdes c->do_not_close = 0; 1700238106Sdes c->tcp_do_toggle_rw = 0; 1701238106Sdes c->tcp_check_nb_connect = 0; 1702238106Sdes c->callback = NULL; 1703238106Sdes c->cb_arg = NULL; 1704238106Sdes evbits = EV_READ | EV_PERSIST; 1705238106Sdes /* libevent stuff */ 1706238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c); 1707238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1708238106Sdes event_add(&c->ev->ev, c->timeout) != 0 ) 1709238106Sdes { 1710238106Sdes log_err("could not add tcpacc event"); 1711238106Sdes comm_point_delete(c); 1712238106Sdes return NULL; 1713238106Sdes } 1714238106Sdes 1715238106Sdes /* now prealloc the tcp handlers */ 1716238106Sdes for(i=0; i<num; i++) { 1717238106Sdes c->tcp_handlers[i] = comm_point_create_tcp_handler(base, 1718238106Sdes c, bufsize, callback, callback_arg); 1719238106Sdes if(!c->tcp_handlers[i]) { 1720238106Sdes comm_point_delete(c); 1721238106Sdes return NULL; 1722238106Sdes } 1723238106Sdes } 1724238106Sdes 1725238106Sdes return c; 1726238106Sdes} 1727238106Sdes 1728238106Sdesstruct comm_point* 1729238106Sdescomm_point_create_tcp_out(struct comm_base *base, size_t bufsize, 1730238106Sdes comm_point_callback_t* callback, void* callback_arg) 1731238106Sdes{ 1732238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1733238106Sdes sizeof(struct comm_point)); 1734238106Sdes short evbits; 1735238106Sdes if(!c) 1736238106Sdes return NULL; 1737238106Sdes c->ev = (struct internal_event*)calloc(1, 1738238106Sdes sizeof(struct internal_event)); 1739238106Sdes if(!c->ev) { 1740238106Sdes free(c); 1741238106Sdes return NULL; 1742238106Sdes } 1743238106Sdes c->ev->base = base; 1744238106Sdes c->fd = -1; 1745269257Sdes c->buffer = sldns_buffer_new(bufsize); 1746238106Sdes if(!c->buffer) { 1747238106Sdes free(c->ev); 1748238106Sdes free(c); 1749238106Sdes return NULL; 1750238106Sdes } 1751238106Sdes c->timeout = NULL; 1752238106Sdes c->tcp_is_reading = 0; 1753238106Sdes c->tcp_byte_count = 0; 1754238106Sdes c->tcp_parent = NULL; 1755238106Sdes c->max_tcp_count = 0; 1756238106Sdes c->tcp_handlers = NULL; 1757238106Sdes c->tcp_free = NULL; 1758238106Sdes c->type = comm_tcp; 1759238106Sdes c->tcp_do_close = 0; 1760238106Sdes c->do_not_close = 0; 1761238106Sdes c->tcp_do_toggle_rw = 1; 1762238106Sdes c->tcp_check_nb_connect = 1; 1763238106Sdes c->repinfo.c = c; 1764238106Sdes c->callback = callback; 1765238106Sdes c->cb_arg = callback_arg; 1766238106Sdes evbits = EV_PERSIST | EV_WRITE; 1767238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c); 1768238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0) 1769238106Sdes { 1770238106Sdes log_err("could not basetset tcpout event"); 1771269257Sdes sldns_buffer_free(c->buffer); 1772238106Sdes free(c->ev); 1773238106Sdes free(c); 1774238106Sdes return NULL; 1775238106Sdes } 1776238106Sdes 1777238106Sdes return c; 1778238106Sdes} 1779238106Sdes 1780238106Sdesstruct comm_point* 1781238106Sdescomm_point_create_local(struct comm_base *base, int fd, size_t bufsize, 1782238106Sdes comm_point_callback_t* callback, void* callback_arg) 1783238106Sdes{ 1784238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1785238106Sdes sizeof(struct comm_point)); 1786238106Sdes short evbits; 1787238106Sdes if(!c) 1788238106Sdes return NULL; 1789238106Sdes c->ev = (struct internal_event*)calloc(1, 1790238106Sdes sizeof(struct internal_event)); 1791238106Sdes if(!c->ev) { 1792238106Sdes free(c); 1793238106Sdes return NULL; 1794238106Sdes } 1795238106Sdes c->ev->base = base; 1796238106Sdes c->fd = fd; 1797269257Sdes c->buffer = sldns_buffer_new(bufsize); 1798238106Sdes if(!c->buffer) { 1799238106Sdes free(c->ev); 1800238106Sdes free(c); 1801238106Sdes return NULL; 1802238106Sdes } 1803238106Sdes c->timeout = NULL; 1804238106Sdes c->tcp_is_reading = 1; 1805238106Sdes c->tcp_byte_count = 0; 1806238106Sdes c->tcp_parent = NULL; 1807238106Sdes c->max_tcp_count = 0; 1808238106Sdes c->tcp_handlers = NULL; 1809238106Sdes c->tcp_free = NULL; 1810238106Sdes c->type = comm_local; 1811238106Sdes c->tcp_do_close = 0; 1812238106Sdes c->do_not_close = 1; 1813238106Sdes c->tcp_do_toggle_rw = 0; 1814238106Sdes c->tcp_check_nb_connect = 0; 1815238106Sdes c->callback = callback; 1816238106Sdes c->cb_arg = callback_arg; 1817238106Sdes /* libevent stuff */ 1818238106Sdes evbits = EV_PERSIST | EV_READ; 1819238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_local_handle_callback, 1820238106Sdes c); 1821238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1822238106Sdes event_add(&c->ev->ev, c->timeout) != 0 ) 1823238106Sdes { 1824238106Sdes log_err("could not add localhdl event"); 1825238106Sdes free(c->ev); 1826238106Sdes free(c); 1827238106Sdes return NULL; 1828238106Sdes } 1829238106Sdes return c; 1830238106Sdes} 1831238106Sdes 1832238106Sdesstruct comm_point* 1833238106Sdescomm_point_create_raw(struct comm_base* base, int fd, int writing, 1834238106Sdes comm_point_callback_t* callback, void* callback_arg) 1835238106Sdes{ 1836238106Sdes struct comm_point* c = (struct comm_point*)calloc(1, 1837238106Sdes sizeof(struct comm_point)); 1838238106Sdes short evbits; 1839238106Sdes if(!c) 1840238106Sdes return NULL; 1841238106Sdes c->ev = (struct internal_event*)calloc(1, 1842238106Sdes sizeof(struct internal_event)); 1843238106Sdes if(!c->ev) { 1844238106Sdes free(c); 1845238106Sdes return NULL; 1846238106Sdes } 1847238106Sdes c->ev->base = base; 1848238106Sdes c->fd = fd; 1849238106Sdes c->buffer = NULL; 1850238106Sdes c->timeout = NULL; 1851238106Sdes c->tcp_is_reading = 0; 1852238106Sdes c->tcp_byte_count = 0; 1853238106Sdes c->tcp_parent = NULL; 1854238106Sdes c->max_tcp_count = 0; 1855238106Sdes c->tcp_handlers = NULL; 1856238106Sdes c->tcp_free = NULL; 1857238106Sdes c->type = comm_raw; 1858238106Sdes c->tcp_do_close = 0; 1859238106Sdes c->do_not_close = 1; 1860238106Sdes c->tcp_do_toggle_rw = 0; 1861238106Sdes c->tcp_check_nb_connect = 0; 1862238106Sdes c->callback = callback; 1863238106Sdes c->cb_arg = callback_arg; 1864238106Sdes /* libevent stuff */ 1865238106Sdes if(writing) 1866238106Sdes evbits = EV_PERSIST | EV_WRITE; 1867238106Sdes else evbits = EV_PERSIST | EV_READ; 1868238106Sdes event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback, 1869238106Sdes c); 1870238106Sdes if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1871238106Sdes event_add(&c->ev->ev, c->timeout) != 0 ) 1872238106Sdes { 1873238106Sdes log_err("could not add rawhdl event"); 1874238106Sdes free(c->ev); 1875238106Sdes free(c); 1876238106Sdes return NULL; 1877238106Sdes } 1878238106Sdes return c; 1879238106Sdes} 1880238106Sdes 1881238106Sdesvoid 1882238106Sdescomm_point_close(struct comm_point* c) 1883238106Sdes{ 1884238106Sdes if(!c) 1885238106Sdes return; 1886238106Sdes if(c->fd != -1) 1887238106Sdes if(event_del(&c->ev->ev) != 0) { 1888238106Sdes log_err("could not event_del on close"); 1889238106Sdes } 1890238106Sdes /* close fd after removing from event lists, or epoll.. is messed up */ 1891238106Sdes if(c->fd != -1 && !c->do_not_close) { 1892238106Sdes verbose(VERB_ALGO, "close fd %d", c->fd); 1893238106Sdes#ifndef USE_WINSOCK 1894238106Sdes close(c->fd); 1895238106Sdes#else 1896238106Sdes closesocket(c->fd); 1897238106Sdes#endif 1898238106Sdes } 1899238106Sdes c->fd = -1; 1900238106Sdes} 1901238106Sdes 1902238106Sdesvoid 1903238106Sdescomm_point_delete(struct comm_point* c) 1904238106Sdes{ 1905238106Sdes if(!c) 1906238106Sdes return; 1907238106Sdes if(c->type == comm_tcp && c->ssl) { 1908249141Sdes#ifdef HAVE_SSL 1909238106Sdes SSL_shutdown(c->ssl); 1910238106Sdes SSL_free(c->ssl); 1911249141Sdes#endif 1912238106Sdes } 1913238106Sdes comm_point_close(c); 1914238106Sdes if(c->tcp_handlers) { 1915238106Sdes int i; 1916238106Sdes for(i=0; i<c->max_tcp_count; i++) 1917238106Sdes comm_point_delete(c->tcp_handlers[i]); 1918238106Sdes free(c->tcp_handlers); 1919238106Sdes } 1920238106Sdes free(c->timeout); 1921238106Sdes if(c->type == comm_tcp || c->type == comm_local) 1922269257Sdes sldns_buffer_free(c->buffer); 1923238106Sdes free(c->ev); 1924238106Sdes free(c); 1925238106Sdes} 1926238106Sdes 1927238106Sdesvoid 1928238106Sdescomm_point_send_reply(struct comm_reply *repinfo) 1929238106Sdes{ 1930238106Sdes log_assert(repinfo && repinfo->c); 1931238106Sdes if(repinfo->c->type == comm_udp) { 1932238106Sdes if(repinfo->srctype) 1933238106Sdes comm_point_send_udp_msg_if(repinfo->c, 1934238106Sdes repinfo->c->buffer, (struct sockaddr*)&repinfo->addr, 1935238106Sdes repinfo->addrlen, repinfo); 1936238106Sdes else 1937238106Sdes comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer, 1938238106Sdes (struct sockaddr*)&repinfo->addr, repinfo->addrlen); 1939238106Sdes } else { 1940238106Sdes comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT); 1941238106Sdes } 1942238106Sdes} 1943238106Sdes 1944238106Sdesvoid 1945238106Sdescomm_point_drop_reply(struct comm_reply* repinfo) 1946238106Sdes{ 1947238106Sdes if(!repinfo) 1948238106Sdes return; 1949238106Sdes log_assert(repinfo && repinfo->c); 1950238106Sdes log_assert(repinfo->c->type != comm_tcp_accept); 1951238106Sdes if(repinfo->c->type == comm_udp) 1952238106Sdes return; 1953238106Sdes reclaim_tcp_handler(repinfo->c); 1954238106Sdes} 1955238106Sdes 1956238106Sdesvoid 1957238106Sdescomm_point_stop_listening(struct comm_point* c) 1958238106Sdes{ 1959238106Sdes verbose(VERB_ALGO, "comm point stop listening %d", c->fd); 1960238106Sdes if(event_del(&c->ev->ev) != 0) { 1961238106Sdes log_err("event_del error to stoplisten"); 1962238106Sdes } 1963238106Sdes} 1964238106Sdes 1965238106Sdesvoid 1966238106Sdescomm_point_start_listening(struct comm_point* c, int newfd, int sec) 1967238106Sdes{ 1968238106Sdes verbose(VERB_ALGO, "comm point start listening %d", 1969238106Sdes c->fd==-1?newfd:c->fd); 1970238106Sdes if(c->type == comm_tcp_accept && !c->tcp_free) { 1971238106Sdes /* no use to start listening no free slots. */ 1972238106Sdes return; 1973238106Sdes } 1974238106Sdes if(sec != -1 && sec != 0) { 1975238106Sdes if(!c->timeout) { 1976238106Sdes c->timeout = (struct timeval*)malloc(sizeof( 1977238106Sdes struct timeval)); 1978238106Sdes if(!c->timeout) { 1979238106Sdes log_err("cpsl: malloc failed. No net read."); 1980238106Sdes return; 1981238106Sdes } 1982238106Sdes } 1983238106Sdes c->ev->ev.ev_events |= EV_TIMEOUT; 1984238106Sdes#ifndef S_SPLINT_S /* splint fails on struct timeval. */ 1985238106Sdes c->timeout->tv_sec = sec; 1986238106Sdes c->timeout->tv_usec = 0; 1987238106Sdes#endif /* S_SPLINT_S */ 1988238106Sdes } 1989238106Sdes if(c->type == comm_tcp) { 1990238106Sdes c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE); 1991238106Sdes if(c->tcp_is_reading) 1992238106Sdes c->ev->ev.ev_events |= EV_READ; 1993238106Sdes else c->ev->ev.ev_events |= EV_WRITE; 1994238106Sdes } 1995238106Sdes if(newfd != -1) { 1996238106Sdes if(c->fd != -1) { 1997238106Sdes#ifndef USE_WINSOCK 1998238106Sdes close(c->fd); 1999238106Sdes#else 2000238106Sdes closesocket(c->fd); 2001238106Sdes#endif 2002238106Sdes } 2003238106Sdes c->fd = newfd; 2004238106Sdes c->ev->ev.ev_fd = c->fd; 2005238106Sdes } 2006238106Sdes if(event_add(&c->ev->ev, sec==0?NULL:c->timeout) != 0) { 2007238106Sdes log_err("event_add failed. in cpsl."); 2008238106Sdes } 2009238106Sdes} 2010238106Sdes 2011238106Sdesvoid comm_point_listen_for_rw(struct comm_point* c, int rd, int wr) 2012238106Sdes{ 2013238106Sdes verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr); 2014238106Sdes if(event_del(&c->ev->ev) != 0) { 2015238106Sdes log_err("event_del error to cplf"); 2016238106Sdes } 2017238106Sdes c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE); 2018238106Sdes if(rd) c->ev->ev.ev_events |= EV_READ; 2019238106Sdes if(wr) c->ev->ev.ev_events |= EV_WRITE; 2020238106Sdes if(event_add(&c->ev->ev, c->timeout) != 0) { 2021238106Sdes log_err("event_add failed. in cplf."); 2022238106Sdes } 2023238106Sdes} 2024238106Sdes 2025238106Sdessize_t comm_point_get_mem(struct comm_point* c) 2026238106Sdes{ 2027238106Sdes size_t s; 2028238106Sdes if(!c) 2029238106Sdes return 0; 2030238106Sdes s = sizeof(*c) + sizeof(*c->ev); 2031238106Sdes if(c->timeout) 2032238106Sdes s += sizeof(*c->timeout); 2033238106Sdes if(c->type == comm_tcp || c->type == comm_local) 2034269257Sdes s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer); 2035238106Sdes if(c->type == comm_tcp_accept) { 2036238106Sdes int i; 2037238106Sdes for(i=0; i<c->max_tcp_count; i++) 2038238106Sdes s += comm_point_get_mem(c->tcp_handlers[i]); 2039238106Sdes } 2040238106Sdes return s; 2041238106Sdes} 2042238106Sdes 2043238106Sdesstruct comm_timer* 2044238106Sdescomm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg) 2045238106Sdes{ 2046238106Sdes struct comm_timer *tm = (struct comm_timer*)calloc(1, 2047238106Sdes sizeof(struct comm_timer)); 2048238106Sdes if(!tm) 2049238106Sdes return NULL; 2050238106Sdes tm->ev_timer = (struct internal_timer*)calloc(1, 2051238106Sdes sizeof(struct internal_timer)); 2052238106Sdes if(!tm->ev_timer) { 2053238106Sdes log_err("malloc failed"); 2054238106Sdes free(tm); 2055238106Sdes return NULL; 2056238106Sdes } 2057238106Sdes tm->ev_timer->base = base; 2058238106Sdes tm->callback = cb; 2059238106Sdes tm->cb_arg = cb_arg; 2060238106Sdes event_set(&tm->ev_timer->ev, -1, EV_TIMEOUT, 2061238106Sdes comm_timer_callback, tm); 2062238106Sdes if(event_base_set(base->eb->base, &tm->ev_timer->ev) != 0) { 2063238106Sdes log_err("timer_create: event_base_set failed."); 2064238106Sdes free(tm->ev_timer); 2065238106Sdes free(tm); 2066238106Sdes return NULL; 2067238106Sdes } 2068238106Sdes return tm; 2069238106Sdes} 2070238106Sdes 2071238106Sdesvoid 2072238106Sdescomm_timer_disable(struct comm_timer* timer) 2073238106Sdes{ 2074238106Sdes if(!timer) 2075238106Sdes return; 2076238106Sdes evtimer_del(&timer->ev_timer->ev); 2077238106Sdes timer->ev_timer->enabled = 0; 2078238106Sdes} 2079238106Sdes 2080238106Sdesvoid 2081238106Sdescomm_timer_set(struct comm_timer* timer, struct timeval* tv) 2082238106Sdes{ 2083238106Sdes log_assert(tv); 2084238106Sdes if(timer->ev_timer->enabled) 2085238106Sdes comm_timer_disable(timer); 2086238106Sdes event_set(&timer->ev_timer->ev, -1, EV_TIMEOUT, 2087238106Sdes comm_timer_callback, timer); 2088238106Sdes if(event_base_set(timer->ev_timer->base->eb->base, 2089238106Sdes &timer->ev_timer->ev) != 0) 2090238106Sdes log_err("comm_timer_set: set_base failed."); 2091238106Sdes if(evtimer_add(&timer->ev_timer->ev, tv) != 0) 2092238106Sdes log_err("comm_timer_set: evtimer_add failed."); 2093238106Sdes timer->ev_timer->enabled = 1; 2094238106Sdes} 2095238106Sdes 2096238106Sdesvoid 2097238106Sdescomm_timer_delete(struct comm_timer* timer) 2098238106Sdes{ 2099238106Sdes if(!timer) 2100238106Sdes return; 2101238106Sdes comm_timer_disable(timer); 2102238106Sdes free(timer->ev_timer); 2103238106Sdes free(timer); 2104238106Sdes} 2105238106Sdes 2106238106Sdesvoid 2107238106Sdescomm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg) 2108238106Sdes{ 2109238106Sdes struct comm_timer* tm = (struct comm_timer*)arg; 2110238106Sdes if(!(event&EV_TIMEOUT)) 2111238106Sdes return; 2112238106Sdes comm_base_now(tm->ev_timer->base); 2113238106Sdes tm->ev_timer->enabled = 0; 2114238106Sdes fptr_ok(fptr_whitelist_comm_timer(tm->callback)); 2115238106Sdes (*tm->callback)(tm->cb_arg); 2116238106Sdes} 2117238106Sdes 2118238106Sdesint 2119238106Sdescomm_timer_is_set(struct comm_timer* timer) 2120238106Sdes{ 2121238106Sdes return (int)timer->ev_timer->enabled; 2122238106Sdes} 2123238106Sdes 2124238106Sdessize_t 2125238106Sdescomm_timer_get_mem(struct comm_timer* timer) 2126238106Sdes{ 2127238106Sdes return sizeof(*timer) + sizeof(struct internal_timer); 2128238106Sdes} 2129238106Sdes 2130238106Sdesstruct comm_signal* 2131238106Sdescomm_signal_create(struct comm_base* base, 2132238106Sdes void (*callback)(int, void*), void* cb_arg) 2133238106Sdes{ 2134238106Sdes struct comm_signal* com = (struct comm_signal*)malloc( 2135238106Sdes sizeof(struct comm_signal)); 2136238106Sdes if(!com) { 2137238106Sdes log_err("malloc failed"); 2138238106Sdes return NULL; 2139238106Sdes } 2140238106Sdes com->base = base; 2141238106Sdes com->callback = callback; 2142238106Sdes com->cb_arg = cb_arg; 2143238106Sdes com->ev_signal = NULL; 2144238106Sdes return com; 2145238106Sdes} 2146238106Sdes 2147238106Sdesvoid 2148238106Sdescomm_signal_callback(int sig, short event, void* arg) 2149238106Sdes{ 2150238106Sdes struct comm_signal* comsig = (struct comm_signal*)arg; 2151238106Sdes if(!(event & EV_SIGNAL)) 2152238106Sdes return; 2153238106Sdes comm_base_now(comsig->base); 2154238106Sdes fptr_ok(fptr_whitelist_comm_signal(comsig->callback)); 2155238106Sdes (*comsig->callback)(sig, comsig->cb_arg); 2156238106Sdes} 2157238106Sdes 2158238106Sdesint 2159238106Sdescomm_signal_bind(struct comm_signal* comsig, int sig) 2160238106Sdes{ 2161238106Sdes struct internal_signal* entry = (struct internal_signal*)calloc(1, 2162238106Sdes sizeof(struct internal_signal)); 2163238106Sdes if(!entry) { 2164238106Sdes log_err("malloc failed"); 2165238106Sdes return 0; 2166238106Sdes } 2167238106Sdes log_assert(comsig); 2168238106Sdes /* add signal event */ 2169238106Sdes signal_set(&entry->ev, sig, comm_signal_callback, comsig); 2170238106Sdes if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) { 2171238106Sdes log_err("Could not set signal base"); 2172238106Sdes free(entry); 2173238106Sdes return 0; 2174238106Sdes } 2175238106Sdes if(signal_add(&entry->ev, NULL) != 0) { 2176238106Sdes log_err("Could not add signal handler"); 2177238106Sdes free(entry); 2178238106Sdes return 0; 2179238106Sdes } 2180238106Sdes /* link into list */ 2181238106Sdes entry->next = comsig->ev_signal; 2182238106Sdes comsig->ev_signal = entry; 2183238106Sdes return 1; 2184238106Sdes} 2185238106Sdes 2186238106Sdesvoid 2187238106Sdescomm_signal_delete(struct comm_signal* comsig) 2188238106Sdes{ 2189238106Sdes struct internal_signal* p, *np; 2190238106Sdes if(!comsig) 2191238106Sdes return; 2192238106Sdes p=comsig->ev_signal; 2193238106Sdes while(p) { 2194238106Sdes np = p->next; 2195238106Sdes signal_del(&p->ev); 2196238106Sdes free(p); 2197238106Sdes p = np; 2198238106Sdes } 2199238106Sdes free(comsig); 2200238106Sdes} 2201