1b7579f77SDag-Erling Smørgrav /* 2b7579f77SDag-Erling Smørgrav * util/netevent.c - event notification 3b7579f77SDag-Erling Smørgrav * 4b7579f77SDag-Erling Smørgrav * Copyright (c) 2007, NLnet Labs. All rights reserved. 5b7579f77SDag-Erling Smørgrav * 6b7579f77SDag-Erling Smørgrav * This software is open source. 7b7579f77SDag-Erling Smørgrav * 8b7579f77SDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 9b7579f77SDag-Erling Smørgrav * modification, are permitted provided that the following conditions 10b7579f77SDag-Erling Smørgrav * are met: 11b7579f77SDag-Erling Smørgrav * 12b7579f77SDag-Erling Smørgrav * Redistributions of source code must retain the above copyright notice, 13b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer. 14b7579f77SDag-Erling Smørgrav * 15b7579f77SDag-Erling Smørgrav * Redistributions in binary form must reproduce the above copyright notice, 16b7579f77SDag-Erling Smørgrav * this list of conditions and the following disclaimer in the documentation 17b7579f77SDag-Erling Smørgrav * and/or other materials provided with the distribution. 18b7579f77SDag-Erling Smørgrav * 19b7579f77SDag-Erling Smørgrav * Neither the name of the NLNET LABS nor the names of its contributors may 20b7579f77SDag-Erling Smørgrav * be used to endorse or promote products derived from this software without 21b7579f77SDag-Erling Smørgrav * specific prior written permission. 22b7579f77SDag-Erling Smørgrav * 23b7579f77SDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2417d15b25SDag-Erling Smørgrav * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2517d15b25SDag-Erling Smørgrav * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2617d15b25SDag-Erling Smørgrav * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2717d15b25SDag-Erling Smørgrav * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2817d15b25SDag-Erling Smørgrav * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 2917d15b25SDag-Erling Smørgrav * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 3017d15b25SDag-Erling Smørgrav * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 3117d15b25SDag-Erling Smørgrav * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 3217d15b25SDag-Erling Smørgrav * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 3317d15b25SDag-Erling Smørgrav * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34b7579f77SDag-Erling Smørgrav */ 35b7579f77SDag-Erling Smørgrav 36b7579f77SDag-Erling Smørgrav /** 37b7579f77SDag-Erling Smørgrav * \file 38b7579f77SDag-Erling Smørgrav * 39b7579f77SDag-Erling Smørgrav * This file contains event notification functions. 40b7579f77SDag-Erling Smørgrav */ 41b7579f77SDag-Erling Smørgrav #include "config.h" 42b7579f77SDag-Erling Smørgrav #include "util/netevent.h" 43e2d15004SDag-Erling Smørgrav #include "util/ub_event.h" 44b7579f77SDag-Erling Smørgrav #include "util/log.h" 45b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 46b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h" 4709a3aaf3SDag-Erling Smørgrav #include "sldns/pkthdr.h" 4809a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h" 49ff825849SDag-Erling Smørgrav #include "dnstap/dnstap.h" 5065b390aaSDag-Erling Smørgrav #include "dnscrypt/dnscrypt.h" 518ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H 52b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h> 538ed2b524SDag-Erling Smørgrav #endif 548ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H 55b7579f77SDag-Erling Smørgrav #include <openssl/err.h> 568ed2b524SDag-Erling Smørgrav #endif 57b7579f77SDag-Erling Smørgrav 58b7579f77SDag-Erling Smørgrav /* -------- Start of local definitions -------- */ 59b7579f77SDag-Erling Smørgrav /** if CMSG_ALIGN is not defined on this platform, a workaround */ 60b7579f77SDag-Erling Smørgrav #ifndef CMSG_ALIGN 61f61ef7f6SDag-Erling Smørgrav # ifdef __CMSG_ALIGN 62f61ef7f6SDag-Erling Smørgrav # define CMSG_ALIGN(n) __CMSG_ALIGN(n) 63f61ef7f6SDag-Erling Smørgrav # elif defined(CMSG_DATA_ALIGN) 64b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN _CMSG_DATA_ALIGN 65b7579f77SDag-Erling Smørgrav # else 66b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1)) 67b7579f77SDag-Erling Smørgrav # endif 68b7579f77SDag-Erling Smørgrav #endif 69b7579f77SDag-Erling Smørgrav 70b7579f77SDag-Erling Smørgrav /** if CMSG_LEN is not defined on this platform, a workaround */ 71b7579f77SDag-Erling Smørgrav #ifndef CMSG_LEN 72b7579f77SDag-Erling Smørgrav # define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len)) 73b7579f77SDag-Erling Smørgrav #endif 74b7579f77SDag-Erling Smørgrav 75b7579f77SDag-Erling Smørgrav /** if CMSG_SPACE is not defined on this platform, a workaround */ 76b7579f77SDag-Erling Smørgrav #ifndef CMSG_SPACE 77b7579f77SDag-Erling Smørgrav # ifdef _CMSG_HDR_ALIGN 78b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr))) 79b7579f77SDag-Erling Smørgrav # else 80b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr))) 81b7579f77SDag-Erling Smørgrav # endif 82b7579f77SDag-Erling Smørgrav #endif 83b7579f77SDag-Erling Smørgrav 84b5663de9SDag-Erling Smørgrav /** The TCP reading or writing query timeout in milliseconds */ 85b5663de9SDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT 120000 86b5663de9SDag-Erling Smørgrav /** The TCP timeout in msec for fast queries, above half are used */ 87b5663de9SDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT_FAST 200 88b7579f77SDag-Erling Smørgrav 89b7579f77SDag-Erling Smørgrav #ifndef NONBLOCKING_IS_BROKEN 90b7579f77SDag-Erling Smørgrav /** number of UDP reads to perform per read indication from select */ 91b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 100 92b7579f77SDag-Erling Smørgrav #else 93b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 1 94b7579f77SDag-Erling Smørgrav #endif 95b7579f77SDag-Erling Smørgrav 96b7579f77SDag-Erling Smørgrav /** 97e2d15004SDag-Erling Smørgrav * The internal event structure for keeping ub_event info for the event. 98b7579f77SDag-Erling Smørgrav * Possibly other structures (list, tree) this is part of. 99b7579f77SDag-Erling Smørgrav */ 100b7579f77SDag-Erling Smørgrav struct internal_event { 101b7579f77SDag-Erling Smørgrav /** the comm base */ 102b7579f77SDag-Erling Smørgrav struct comm_base* base; 103e2d15004SDag-Erling Smørgrav /** ub_event event type */ 104e2d15004SDag-Erling Smørgrav struct ub_event* ev; 105b7579f77SDag-Erling Smørgrav }; 106b7579f77SDag-Erling Smørgrav 107b7579f77SDag-Erling Smørgrav /** 108b7579f77SDag-Erling Smørgrav * Internal base structure, so that every thread has its own events. 109b7579f77SDag-Erling Smørgrav */ 110b7579f77SDag-Erling Smørgrav struct internal_base { 111e2d15004SDag-Erling Smørgrav /** ub_event event_base type. */ 112e2d15004SDag-Erling Smørgrav struct ub_event_base* base; 113b7579f77SDag-Erling Smørgrav /** seconds time pointer points here */ 11417d15b25SDag-Erling Smørgrav time_t secs; 115b7579f77SDag-Erling Smørgrav /** timeval with current time */ 116b7579f77SDag-Erling Smørgrav struct timeval now; 117b7579f77SDag-Erling Smørgrav /** the event used for slow_accept timeouts */ 118e2d15004SDag-Erling Smørgrav struct ub_event* slow_accept; 119b7579f77SDag-Erling Smørgrav /** true if slow_accept is enabled */ 120b7579f77SDag-Erling Smørgrav int slow_accept_enabled; 121b7579f77SDag-Erling Smørgrav }; 122b7579f77SDag-Erling Smørgrav 123b7579f77SDag-Erling Smørgrav /** 124b7579f77SDag-Erling Smørgrav * Internal timer structure, to store timer event in. 125b7579f77SDag-Erling Smørgrav */ 126b7579f77SDag-Erling Smørgrav struct internal_timer { 127e2d15004SDag-Erling Smørgrav /** the super struct from which derived */ 128e2d15004SDag-Erling Smørgrav struct comm_timer super; 129b7579f77SDag-Erling Smørgrav /** the comm base */ 130b7579f77SDag-Erling Smørgrav struct comm_base* base; 131e2d15004SDag-Erling Smørgrav /** ub_event event type */ 132e2d15004SDag-Erling Smørgrav struct ub_event* ev; 133b7579f77SDag-Erling Smørgrav /** is timer enabled */ 134b7579f77SDag-Erling Smørgrav uint8_t enabled; 135b7579f77SDag-Erling Smørgrav }; 136b7579f77SDag-Erling Smørgrav 137b7579f77SDag-Erling Smørgrav /** 138b7579f77SDag-Erling Smørgrav * Internal signal structure, to store signal event in. 139b7579f77SDag-Erling Smørgrav */ 140b7579f77SDag-Erling Smørgrav struct internal_signal { 141e2d15004SDag-Erling Smørgrav /** ub_event event type */ 142e2d15004SDag-Erling Smørgrav struct ub_event* ev; 143b7579f77SDag-Erling Smørgrav /** next in signal list */ 144b7579f77SDag-Erling Smørgrav struct internal_signal* next; 145b7579f77SDag-Erling Smørgrav }; 146b7579f77SDag-Erling Smørgrav 147b7579f77SDag-Erling Smørgrav /** create a tcp handler with a parent */ 148b7579f77SDag-Erling Smørgrav static struct comm_point* comm_point_create_tcp_handler( 149b7579f77SDag-Erling Smørgrav struct comm_base *base, struct comm_point* parent, size_t bufsize, 1503005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg); 151b7579f77SDag-Erling Smørgrav 152b7579f77SDag-Erling Smørgrav /* -------- End of local definitions -------- */ 153b7579f77SDag-Erling Smørgrav 154b7579f77SDag-Erling Smørgrav struct comm_base* 155b7579f77SDag-Erling Smørgrav comm_base_create(int sigs) 156b7579f77SDag-Erling Smørgrav { 157b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1, 158b7579f77SDag-Erling Smørgrav sizeof(struct comm_base)); 159e2d15004SDag-Erling Smørgrav const char *evnm="event", *evsys="", *evmethod=""; 160e2d15004SDag-Erling Smørgrav 161b7579f77SDag-Erling Smørgrav if(!b) 162b7579f77SDag-Erling Smørgrav return NULL; 163b7579f77SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 164b7579f77SDag-Erling Smørgrav if(!b->eb) { 165b7579f77SDag-Erling Smørgrav free(b); 166b7579f77SDag-Erling Smørgrav return NULL; 167b7579f77SDag-Erling Smørgrav } 168e2d15004SDag-Erling Smørgrav b->eb->base = ub_default_event_base(sigs, &b->eb->secs, &b->eb->now); 169b7579f77SDag-Erling Smørgrav if(!b->eb->base) { 170b7579f77SDag-Erling Smørgrav free(b->eb); 171b7579f77SDag-Erling Smørgrav free(b); 172b7579f77SDag-Erling Smørgrav return NULL; 173b7579f77SDag-Erling Smørgrav } 174e2d15004SDag-Erling Smørgrav ub_comm_base_now(b); 175e2d15004SDag-Erling Smørgrav ub_get_event_sys(b->eb->base, &evnm, &evsys, &evmethod); 176e2d15004SDag-Erling Smørgrav verbose(VERB_ALGO, "%s %s user %s method.", evnm, evsys, evmethod); 177b7579f77SDag-Erling Smørgrav return b; 178b7579f77SDag-Erling Smørgrav } 179b7579f77SDag-Erling Smørgrav 18017d15b25SDag-Erling Smørgrav struct comm_base* 181e2d15004SDag-Erling Smørgrav comm_base_create_event(struct ub_event_base* base) 18217d15b25SDag-Erling Smørgrav { 18317d15b25SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1, 18417d15b25SDag-Erling Smørgrav sizeof(struct comm_base)); 18517d15b25SDag-Erling Smørgrav if(!b) 18617d15b25SDag-Erling Smørgrav return NULL; 18717d15b25SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 18817d15b25SDag-Erling Smørgrav if(!b->eb) { 18917d15b25SDag-Erling Smørgrav free(b); 19017d15b25SDag-Erling Smørgrav return NULL; 19117d15b25SDag-Erling Smørgrav } 19217d15b25SDag-Erling Smørgrav b->eb->base = base; 193e2d15004SDag-Erling Smørgrav ub_comm_base_now(b); 19417d15b25SDag-Erling Smørgrav return b; 19517d15b25SDag-Erling Smørgrav } 19617d15b25SDag-Erling Smørgrav 197b7579f77SDag-Erling Smørgrav void 198b7579f77SDag-Erling Smørgrav comm_base_delete(struct comm_base* b) 199b7579f77SDag-Erling Smørgrav { 200b7579f77SDag-Erling Smørgrav if(!b) 201b7579f77SDag-Erling Smørgrav return; 202b7579f77SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) { 203e2d15004SDag-Erling Smørgrav if(ub_event_del(b->eb->slow_accept) != 0) { 204b7579f77SDag-Erling Smørgrav log_err("could not event_del slow_accept"); 205b7579f77SDag-Erling Smørgrav } 206e2d15004SDag-Erling Smørgrav ub_event_free(b->eb->slow_accept); 207b7579f77SDag-Erling Smørgrav } 208e2d15004SDag-Erling Smørgrav ub_event_base_free(b->eb->base); 209b7579f77SDag-Erling Smørgrav b->eb->base = NULL; 210b7579f77SDag-Erling Smørgrav free(b->eb); 211b7579f77SDag-Erling Smørgrav free(b); 212b7579f77SDag-Erling Smørgrav } 213b7579f77SDag-Erling Smørgrav 214b7579f77SDag-Erling Smørgrav void 21517d15b25SDag-Erling Smørgrav comm_base_delete_no_base(struct comm_base* b) 21617d15b25SDag-Erling Smørgrav { 21717d15b25SDag-Erling Smørgrav if(!b) 21817d15b25SDag-Erling Smørgrav return; 21917d15b25SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) { 220e2d15004SDag-Erling Smørgrav if(ub_event_del(b->eb->slow_accept) != 0) { 22117d15b25SDag-Erling Smørgrav log_err("could not event_del slow_accept"); 22217d15b25SDag-Erling Smørgrav } 223e2d15004SDag-Erling Smørgrav ub_event_free(b->eb->slow_accept); 22417d15b25SDag-Erling Smørgrav } 22517d15b25SDag-Erling Smørgrav b->eb->base = NULL; 22617d15b25SDag-Erling Smørgrav free(b->eb); 22717d15b25SDag-Erling Smørgrav free(b); 22817d15b25SDag-Erling Smørgrav } 22917d15b25SDag-Erling Smørgrav 23017d15b25SDag-Erling Smørgrav void 23117d15b25SDag-Erling Smørgrav comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv) 232b7579f77SDag-Erling Smørgrav { 233b7579f77SDag-Erling Smørgrav *tt = &b->eb->secs; 234b7579f77SDag-Erling Smørgrav *tv = &b->eb->now; 235b7579f77SDag-Erling Smørgrav } 236b7579f77SDag-Erling Smørgrav 237b7579f77SDag-Erling Smørgrav void 238b7579f77SDag-Erling Smørgrav comm_base_dispatch(struct comm_base* b) 239b7579f77SDag-Erling Smørgrav { 240b7579f77SDag-Erling Smørgrav int retval; 241e2d15004SDag-Erling Smørgrav retval = ub_event_base_dispatch(b->eb->base); 242e2d15004SDag-Erling Smørgrav if(retval < 0) { 243b7579f77SDag-Erling Smørgrav fatal_exit("event_dispatch returned error %d, " 244b7579f77SDag-Erling Smørgrav "errno is %s", retval, strerror(errno)); 245b7579f77SDag-Erling Smørgrav } 246b7579f77SDag-Erling Smørgrav } 247b7579f77SDag-Erling Smørgrav 248b7579f77SDag-Erling Smørgrav void comm_base_exit(struct comm_base* b) 249b7579f77SDag-Erling Smørgrav { 250e2d15004SDag-Erling Smørgrav if(ub_event_base_loopexit(b->eb->base) != 0) { 251b7579f77SDag-Erling Smørgrav log_err("Could not loopexit"); 252b7579f77SDag-Erling Smørgrav } 253b7579f77SDag-Erling Smørgrav } 254b7579f77SDag-Erling Smørgrav 255b7579f77SDag-Erling Smørgrav void comm_base_set_slow_accept_handlers(struct comm_base* b, 256b7579f77SDag-Erling Smørgrav void (*stop_acc)(void*), void (*start_acc)(void*), void* arg) 257b7579f77SDag-Erling Smørgrav { 258b7579f77SDag-Erling Smørgrav b->stop_accept = stop_acc; 259b7579f77SDag-Erling Smørgrav b->start_accept = start_acc; 260b7579f77SDag-Erling Smørgrav b->cb_arg = arg; 261b7579f77SDag-Erling Smørgrav } 262b7579f77SDag-Erling Smørgrav 263e2d15004SDag-Erling Smørgrav struct ub_event_base* comm_base_internal(struct comm_base* b) 264b7579f77SDag-Erling Smørgrav { 265b7579f77SDag-Erling Smørgrav return b->eb->base; 266b7579f77SDag-Erling Smørgrav } 267b7579f77SDag-Erling Smørgrav 268b7579f77SDag-Erling Smørgrav /** see if errno for udp has to be logged or not uses globals */ 269b7579f77SDag-Erling Smørgrav static int 270b7579f77SDag-Erling Smørgrav udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 271b7579f77SDag-Erling Smørgrav { 272b7579f77SDag-Erling Smørgrav /* do not log transient errors (unless high verbosity) */ 273b7579f77SDag-Erling Smørgrav #if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN) 274b7579f77SDag-Erling Smørgrav switch(errno) { 275b7579f77SDag-Erling Smørgrav # ifdef ENETUNREACH 276b7579f77SDag-Erling Smørgrav case ENETUNREACH: 277b7579f77SDag-Erling Smørgrav # endif 278b7579f77SDag-Erling Smørgrav # ifdef EHOSTDOWN 279b7579f77SDag-Erling Smørgrav case EHOSTDOWN: 280b7579f77SDag-Erling Smørgrav # endif 281b7579f77SDag-Erling Smørgrav # ifdef EHOSTUNREACH 282b7579f77SDag-Erling Smørgrav case EHOSTUNREACH: 283b7579f77SDag-Erling Smørgrav # endif 284b7579f77SDag-Erling Smørgrav # ifdef ENETDOWN 285b7579f77SDag-Erling Smørgrav case ENETDOWN: 286b7579f77SDag-Erling Smørgrav # endif 287b7579f77SDag-Erling Smørgrav if(verbosity < VERB_ALGO) 288b7579f77SDag-Erling Smørgrav return 0; 289b7579f77SDag-Erling Smørgrav default: 290b7579f77SDag-Erling Smørgrav break; 291b7579f77SDag-Erling Smørgrav } 292b7579f77SDag-Erling Smørgrav #endif 29317d15b25SDag-Erling Smørgrav /* permission denied is gotten for every send if the 29417d15b25SDag-Erling Smørgrav * network is disconnected (on some OS), squelch it */ 295f61ef7f6SDag-Erling Smørgrav if( ((errno == EPERM) 296f61ef7f6SDag-Erling Smørgrav # ifdef EADDRNOTAVAIL 297f61ef7f6SDag-Erling Smørgrav /* 'Cannot assign requested address' also when disconnected */ 298f61ef7f6SDag-Erling Smørgrav || (errno == EADDRNOTAVAIL) 299f61ef7f6SDag-Erling Smørgrav # endif 300f61ef7f6SDag-Erling Smørgrav ) && verbosity < VERB_DETAIL) 30117d15b25SDag-Erling Smørgrav return 0; 302b7579f77SDag-Erling Smørgrav /* squelch errors where people deploy AAAA ::ffff:bla for 303b7579f77SDag-Erling Smørgrav * authority servers, which we try for intranets. */ 304b7579f77SDag-Erling Smørgrav if(errno == EINVAL && addr_is_ip4mapped( 305b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) && 306b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL) 307b7579f77SDag-Erling Smørgrav return 0; 308b7579f77SDag-Erling Smørgrav /* SO_BROADCAST sockopt can give access to 255.255.255.255, 309b7579f77SDag-Erling Smørgrav * but a dns cache does not need it. */ 310b7579f77SDag-Erling Smørgrav if(errno == EACCES && addr_is_broadcast( 311b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) && 312b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL) 313b7579f77SDag-Erling Smørgrav return 0; 314b7579f77SDag-Erling Smørgrav return 1; 315b7579f77SDag-Erling Smørgrav } 316b7579f77SDag-Erling Smørgrav 317b7579f77SDag-Erling Smørgrav int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 318b7579f77SDag-Erling Smørgrav { 319b7579f77SDag-Erling Smørgrav return udp_send_errno_needs_log(addr, addrlen); 320b7579f77SDag-Erling Smørgrav } 321b7579f77SDag-Erling Smørgrav 322b7579f77SDag-Erling Smørgrav /* send a UDP reply */ 323b7579f77SDag-Erling Smørgrav int 32417d15b25SDag-Erling Smørgrav comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, 325b7579f77SDag-Erling Smørgrav struct sockaddr* addr, socklen_t addrlen) 326b7579f77SDag-Erling Smørgrav { 327b7579f77SDag-Erling Smørgrav ssize_t sent; 328b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1); 329b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG 33017d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0) 331b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet"); 332b7579f77SDag-Erling Smørgrav #endif 333b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0); 33417d15b25SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet), 33517d15b25SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0, 336b7579f77SDag-Erling Smørgrav addr, addrlen); 337b7579f77SDag-Erling Smørgrav if(sent == -1) { 338f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete, 339f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for 340f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */ 341f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK 342f61ef7f6SDag-Erling Smørgrav if(errno == EAGAIN || 343f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK 344f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK || 345f61ef7f6SDag-Erling Smørgrav # endif 346f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) { 347f61ef7f6SDag-Erling Smørgrav #else 348f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 349f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS || 350f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) { 351f61ef7f6SDag-Erling Smørgrav #endif 352f61ef7f6SDag-Erling Smørgrav int e; 353f61ef7f6SDag-Erling Smørgrav fd_set_block(c->fd); 354f61ef7f6SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet), 355f61ef7f6SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0, 356f61ef7f6SDag-Erling Smørgrav addr, addrlen); 357f61ef7f6SDag-Erling Smørgrav e = errno; 358f61ef7f6SDag-Erling Smørgrav fd_set_nonblock(c->fd); 359f61ef7f6SDag-Erling Smørgrav errno = e; 360f61ef7f6SDag-Erling Smørgrav } 361f61ef7f6SDag-Erling Smørgrav } 362f61ef7f6SDag-Erling Smørgrav if(sent == -1) { 363b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen)) 364b7579f77SDag-Erling Smørgrav return 0; 365b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 366b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendto failed: %s", strerror(errno)); 367b7579f77SDag-Erling Smørgrav #else 368b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendto failed: %s", 369b7579f77SDag-Erling Smørgrav wsa_strerror(WSAGetLastError())); 370b7579f77SDag-Erling Smørgrav #endif 371b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is", 372b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen); 373b7579f77SDag-Erling Smørgrav return 0; 37417d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) { 375b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes", 37617d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet)); 377b7579f77SDag-Erling Smørgrav return 0; 378b7579f77SDag-Erling Smørgrav } 379b7579f77SDag-Erling Smørgrav return 1; 380b7579f77SDag-Erling Smørgrav } 381b7579f77SDag-Erling Smørgrav 382b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG)) 383b7579f77SDag-Erling Smørgrav /** print debug ancillary info */ 384b7579f77SDag-Erling Smørgrav static void p_ancil(const char* str, struct comm_reply* r) 385b7579f77SDag-Erling Smørgrav { 386b7579f77SDag-Erling Smørgrav if(r->srctype != 4 && r->srctype != 6) { 387b7579f77SDag-Erling Smørgrav log_info("%s: unknown srctype %d", str, r->srctype); 388b7579f77SDag-Erling Smørgrav return; 389b7579f77SDag-Erling Smørgrav } 390b7579f77SDag-Erling Smørgrav if(r->srctype == 6) { 391b7579f77SDag-Erling Smørgrav char buf[1024]; 392b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr, 393b7579f77SDag-Erling Smørgrav buf, (socklen_t)sizeof(buf)) == 0) { 39417d15b25SDag-Erling Smørgrav (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf)); 395b7579f77SDag-Erling Smørgrav } 396b7579f77SDag-Erling Smørgrav buf[sizeof(buf)-1]=0; 397b7579f77SDag-Erling Smørgrav log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex); 398b7579f77SDag-Erling Smørgrav } else if(r->srctype == 4) { 399b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 400b7579f77SDag-Erling Smørgrav char buf1[1024], buf2[1024]; 401b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr, 402b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) { 40317d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 404b7579f77SDag-Erling Smørgrav } 405b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0; 406b7579f77SDag-Erling Smørgrav #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST 407b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst, 408b7579f77SDag-Erling Smørgrav buf2, (socklen_t)sizeof(buf2)) == 0) { 40917d15b25SDag-Erling Smørgrav (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2)); 410b7579f77SDag-Erling Smørgrav } 411b7579f77SDag-Erling Smørgrav buf2[sizeof(buf2)-1]=0; 412b7579f77SDag-Erling Smørgrav #else 413b7579f77SDag-Erling Smørgrav buf2[0]=0; 414b7579f77SDag-Erling Smørgrav #endif 415b7579f77SDag-Erling Smørgrav log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex, 416b7579f77SDag-Erling Smørgrav buf1, buf2); 417b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR) 418b7579f77SDag-Erling Smørgrav char buf1[1024]; 419b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4addr, 420b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) { 42117d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 422b7579f77SDag-Erling Smørgrav } 423b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0; 424b7579f77SDag-Erling Smørgrav log_info("%s: %s", str, buf1); 425b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or PI_RECVDSTDADDR */ 426b7579f77SDag-Erling Smørgrav } 427b7579f77SDag-Erling Smørgrav } 428b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */ 429b7579f77SDag-Erling Smørgrav 430b7579f77SDag-Erling Smørgrav /** send a UDP reply over specified interface*/ 431b7579f77SDag-Erling Smørgrav static int 43217d15b25SDag-Erling Smørgrav comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet, 433b7579f77SDag-Erling Smørgrav struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r) 434b7579f77SDag-Erling Smørgrav { 435b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG) 436b7579f77SDag-Erling Smørgrav ssize_t sent; 437b7579f77SDag-Erling Smørgrav struct msghdr msg; 438b7579f77SDag-Erling Smørgrav struct iovec iov[1]; 439b7579f77SDag-Erling Smørgrav char control[256]; 440b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 441b7579f77SDag-Erling Smørgrav struct cmsghdr *cmsg; 442b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 443b7579f77SDag-Erling Smørgrav 444b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1); 445b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG 44617d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0) 447b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet"); 448b7579f77SDag-Erling Smørgrav #endif 449b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0); 450b7579f77SDag-Erling Smørgrav 451b7579f77SDag-Erling Smørgrav msg.msg_name = addr; 452b7579f77SDag-Erling Smørgrav msg.msg_namelen = addrlen; 45317d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(packet); 45417d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(packet); 455b7579f77SDag-Erling Smørgrav msg.msg_iov = iov; 456b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1; 457b7579f77SDag-Erling Smørgrav msg.msg_control = control; 458b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 459b7579f77SDag-Erling Smørgrav msg.msg_controllen = sizeof(control); 460b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 461b7579f77SDag-Erling Smørgrav msg.msg_flags = 0; 462b7579f77SDag-Erling Smørgrav 463b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 464b7579f77SDag-Erling Smørgrav cmsg = CMSG_FIRSTHDR(&msg); 465b7579f77SDag-Erling Smørgrav if(r->srctype == 4) { 466b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 46709a3aaf3SDag-Erling Smørgrav void* cmsg_data; 468b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); 469b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 470b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP; 471b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_PKTINFO; 472b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info, 473b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo)); 47409a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */ 47509a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg); 47609a3aaf3SDag-Erling Smørgrav ((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0; 477b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 478b7579f77SDag-Erling Smørgrav #elif defined(IP_SENDSRCADDR) 479b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 480b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 481b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP; 482b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_SENDSRCADDR; 483b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr, 484b7579f77SDag-Erling Smørgrav sizeof(struct in_addr)); 485b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 486b7579f77SDag-Erling Smørgrav #else 487b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR"); 488b7579f77SDag-Erling Smørgrav msg.msg_control = NULL; 489b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_SENDSRCADDR */ 490b7579f77SDag-Erling Smørgrav } else if(r->srctype == 6) { 49109a3aaf3SDag-Erling Smørgrav void* cmsg_data; 492b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 493b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 494b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6; 495b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO; 496b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info, 497b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo)); 49809a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */ 49909a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg); 50009a3aaf3SDag-Erling Smørgrav ((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0; 501b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 502b7579f77SDag-Erling Smørgrav } else { 503b7579f77SDag-Erling Smørgrav /* try to pass all 0 to use default route */ 504b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 505b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 506b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6; 507b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO; 508b7579f77SDag-Erling Smørgrav memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo)); 509b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 510b7579f77SDag-Erling Smørgrav } 511b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 512b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_ALGO) 513b7579f77SDag-Erling Smørgrav p_ancil("send_udp over interface", r); 514b7579f77SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0); 515b7579f77SDag-Erling Smørgrav if(sent == -1) { 516f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete, 517f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for 518f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */ 519f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK 520f61ef7f6SDag-Erling Smørgrav if(errno == EAGAIN || 521f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK 522f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK || 523f61ef7f6SDag-Erling Smørgrav # endif 524f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) { 525f61ef7f6SDag-Erling Smørgrav #else 526f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 527f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS || 528f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) { 529f61ef7f6SDag-Erling Smørgrav #endif 530f61ef7f6SDag-Erling Smørgrav int e; 531f61ef7f6SDag-Erling Smørgrav fd_set_block(c->fd); 532f61ef7f6SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0); 533f61ef7f6SDag-Erling Smørgrav e = errno; 534f61ef7f6SDag-Erling Smørgrav fd_set_nonblock(c->fd); 535f61ef7f6SDag-Erling Smørgrav errno = e; 536f61ef7f6SDag-Erling Smørgrav } 537f61ef7f6SDag-Erling Smørgrav } 538f61ef7f6SDag-Erling Smørgrav if(sent == -1) { 539b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen)) 540b7579f77SDag-Erling Smørgrav return 0; 541b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno)); 542b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is", 543b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen); 544f61ef7f6SDag-Erling Smørgrav #ifdef __NetBSD__ 545f61ef7f6SDag-Erling Smørgrav /* netbsd 7 has IP_PKTINFO for recv but not send */ 546f61ef7f6SDag-Erling Smørgrav if(errno == EINVAL && r->srctype == 4) 547f61ef7f6SDag-Erling Smørgrav log_err("sendmsg: No support for sendmsg(IP_PKTINFO). " 548f61ef7f6SDag-Erling Smørgrav "Please disable interface-automatic"); 549f61ef7f6SDag-Erling Smørgrav #endif 550b7579f77SDag-Erling Smørgrav return 0; 55117d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) { 552b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes", 55317d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet)); 554b7579f77SDag-Erling Smørgrav return 0; 555b7579f77SDag-Erling Smørgrav } 556b7579f77SDag-Erling Smørgrav return 1; 557b7579f77SDag-Erling Smørgrav #else 558b7579f77SDag-Erling Smørgrav (void)c; 559b7579f77SDag-Erling Smørgrav (void)packet; 560b7579f77SDag-Erling Smørgrav (void)addr; 561b7579f77SDag-Erling Smørgrav (void)addrlen; 562b7579f77SDag-Erling Smørgrav (void)r; 563b7579f77SDag-Erling Smørgrav log_err("sendmsg: IPV6_PKTINFO not supported"); 564b7579f77SDag-Erling Smørgrav return 0; 565b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */ 566b7579f77SDag-Erling Smørgrav } 567b7579f77SDag-Erling Smørgrav 568b7579f77SDag-Erling Smørgrav void 569b7579f77SDag-Erling Smørgrav comm_point_udp_ancil_callback(int fd, short event, void* arg) 570b7579f77SDag-Erling Smørgrav { 571b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) 572b7579f77SDag-Erling Smørgrav struct comm_reply rep; 573b7579f77SDag-Erling Smørgrav struct msghdr msg; 574b7579f77SDag-Erling Smørgrav struct iovec iov[1]; 575b7579f77SDag-Erling Smørgrav ssize_t rcv; 576b7579f77SDag-Erling Smørgrav char ancil[256]; 577b7579f77SDag-Erling Smørgrav int i; 578b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 579b7579f77SDag-Erling Smørgrav struct cmsghdr* cmsg; 580b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 581b7579f77SDag-Erling Smørgrav 582b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg; 583b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp); 584b7579f77SDag-Erling Smørgrav 585e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_READ)) 586b7579f77SDag-Erling Smørgrav return; 587b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 588e2d15004SDag-Erling Smørgrav ub_comm_base_now(rep.c->ev->base); 589b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) { 59017d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer); 591b7579f77SDag-Erling Smørgrav rep.addrlen = (socklen_t)sizeof(rep.addr); 592b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 59317d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 594b7579f77SDag-Erling Smørgrav msg.msg_name = &rep.addr; 595b7579f77SDag-Erling Smørgrav msg.msg_namelen = (socklen_t)sizeof(rep.addr); 59617d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(rep.c->buffer); 59717d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer); 598b7579f77SDag-Erling Smørgrav msg.msg_iov = iov; 599b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1; 600b7579f77SDag-Erling Smørgrav msg.msg_control = ancil; 601b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 602b7579f77SDag-Erling Smørgrav msg.msg_controllen = sizeof(ancil); 603b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 604b7579f77SDag-Erling Smørgrav msg.msg_flags = 0; 605b7579f77SDag-Erling Smørgrav rcv = recvmsg(fd, &msg, 0); 606b7579f77SDag-Erling Smørgrav if(rcv == -1) { 607b7579f77SDag-Erling Smørgrav if(errno != EAGAIN && errno != EINTR) { 608b7579f77SDag-Erling Smørgrav log_err("recvmsg failed: %s", strerror(errno)); 609b7579f77SDag-Erling Smørgrav } 610b7579f77SDag-Erling Smørgrav return; 611b7579f77SDag-Erling Smørgrav } 612b7579f77SDag-Erling Smørgrav rep.addrlen = msg.msg_namelen; 61317d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv); 61417d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer); 615b7579f77SDag-Erling Smørgrav rep.srctype = 0; 616b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 617b7579f77SDag-Erling Smørgrav for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 618b7579f77SDag-Erling Smørgrav cmsg = CMSG_NXTHDR(&msg, cmsg)) { 619b7579f77SDag-Erling Smørgrav if( cmsg->cmsg_level == IPPROTO_IPV6 && 620b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IPV6_PKTINFO) { 621b7579f77SDag-Erling Smørgrav rep.srctype = 6; 622b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg), 623b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo)); 624b7579f77SDag-Erling Smørgrav break; 625b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 626b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP && 627b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_PKTINFO) { 628b7579f77SDag-Erling Smørgrav rep.srctype = 4; 629b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg), 630b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo)); 631b7579f77SDag-Erling Smørgrav break; 632b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR) 633b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP && 634b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_RECVDSTADDR) { 635b7579f77SDag-Erling Smørgrav rep.srctype = 4; 636b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg), 637b7579f77SDag-Erling Smørgrav sizeof(struct in_addr)); 638b7579f77SDag-Erling Smørgrav break; 639b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_RECVDSTADDR */ 640b7579f77SDag-Erling Smørgrav } 641b7579f77SDag-Erling Smørgrav } 642b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_ALGO) 643b7579f77SDag-Erling Smørgrav p_ancil("receive_udp on interface", &rep); 644b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 645b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 646b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 647b7579f77SDag-Erling Smørgrav /* send back immediate reply */ 648b7579f77SDag-Erling Smørgrav (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer, 649b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, rep.addrlen, &rep); 650b7579f77SDag-Erling Smørgrav } 651b7579f77SDag-Erling Smørgrav if(rep.c->fd == -1) /* commpoint closed */ 652b7579f77SDag-Erling Smørgrav break; 653b7579f77SDag-Erling Smørgrav } 654b7579f77SDag-Erling Smørgrav #else 655b7579f77SDag-Erling Smørgrav (void)fd; 656b7579f77SDag-Erling Smørgrav (void)event; 657b7579f77SDag-Erling Smørgrav (void)arg; 6583005e0a3SDag-Erling Smørgrav fatal_exit("recvmsg: No support for IPV6_PKTINFO; IP_PKTINFO or IP_RECVDSTADDR. " 659b7579f77SDag-Erling Smørgrav "Please disable interface-automatic"); 660b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ 661b7579f77SDag-Erling Smørgrav } 662b7579f77SDag-Erling Smørgrav 663b7579f77SDag-Erling Smørgrav void 664b7579f77SDag-Erling Smørgrav comm_point_udp_callback(int fd, short event, void* arg) 665b7579f77SDag-Erling Smørgrav { 666b7579f77SDag-Erling Smørgrav struct comm_reply rep; 667b7579f77SDag-Erling Smørgrav ssize_t rcv; 668b7579f77SDag-Erling Smørgrav int i; 66965b390aaSDag-Erling Smørgrav struct sldns_buffer *buffer; 670b7579f77SDag-Erling Smørgrav 671b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg; 672b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp); 673b7579f77SDag-Erling Smørgrav 674e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_READ)) 675b7579f77SDag-Erling Smørgrav return; 676b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 677e2d15004SDag-Erling Smørgrav ub_comm_base_now(rep.c->ev->base); 678b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) { 67917d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer); 680b7579f77SDag-Erling Smørgrav rep.addrlen = (socklen_t)sizeof(rep.addr); 681b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 68217d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 68317d15b25SDag-Erling Smørgrav rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer), 68417d15b25SDag-Erling Smørgrav sldns_buffer_remaining(rep.c->buffer), 0, 685b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, &rep.addrlen); 686b7579f77SDag-Erling Smørgrav if(rcv == -1) { 687b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 688b7579f77SDag-Erling Smørgrav if(errno != EAGAIN && errno != EINTR) 689b7579f77SDag-Erling Smørgrav log_err("recvfrom %d failed: %s", 690b7579f77SDag-Erling Smørgrav fd, strerror(errno)); 691b7579f77SDag-Erling Smørgrav #else 692b7579f77SDag-Erling Smørgrav if(WSAGetLastError() != WSAEINPROGRESS && 693b7579f77SDag-Erling Smørgrav WSAGetLastError() != WSAECONNRESET && 694b7579f77SDag-Erling Smørgrav WSAGetLastError()!= WSAEWOULDBLOCK) 695b7579f77SDag-Erling Smørgrav log_err("recvfrom failed: %s", 696b7579f77SDag-Erling Smørgrav wsa_strerror(WSAGetLastError())); 697b7579f77SDag-Erling Smørgrav #endif 698b7579f77SDag-Erling Smørgrav return; 699b7579f77SDag-Erling Smørgrav } 70017d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv); 70117d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer); 702b7579f77SDag-Erling Smørgrav rep.srctype = 0; 703b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 704b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 705b7579f77SDag-Erling Smørgrav /* send back immediate reply */ 70665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 70765b390aaSDag-Erling Smørgrav buffer = rep.c->dnscrypt_buffer; 70865b390aaSDag-Erling Smørgrav #else 70965b390aaSDag-Erling Smørgrav buffer = rep.c->buffer; 71065b390aaSDag-Erling Smørgrav #endif 71165b390aaSDag-Erling Smørgrav (void)comm_point_send_udp_msg(rep.c, buffer, 712b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, rep.addrlen); 713b7579f77SDag-Erling Smørgrav } 714b7579f77SDag-Erling Smørgrav if(rep.c->fd != fd) /* commpoint closed to -1 or reused for 715b7579f77SDag-Erling Smørgrav another UDP port. Note rep.c cannot be reused with TCP fd. */ 716b7579f77SDag-Erling Smørgrav break; 717b7579f77SDag-Erling Smørgrav } 718b7579f77SDag-Erling Smørgrav } 719b7579f77SDag-Erling Smørgrav 720b7579f77SDag-Erling Smørgrav /** Use a new tcp handler for new query fd, set to read query */ 721b7579f77SDag-Erling Smørgrav static void 722b5663de9SDag-Erling Smørgrav setup_tcp_handler(struct comm_point* c, int fd, int cur, int max) 723b7579f77SDag-Erling Smørgrav { 724b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 725b7579f77SDag-Erling Smørgrav log_assert(c->fd == -1); 72617d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer); 72765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 72865b390aaSDag-Erling Smørgrav if (c->dnscrypt) 72965b390aaSDag-Erling Smørgrav sldns_buffer_clear(c->dnscrypt_buffer); 73065b390aaSDag-Erling Smørgrav #endif 731b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 732b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 733b5663de9SDag-Erling Smørgrav c->tcp_timeout_msec = TCP_QUERY_TIMEOUT; 734b5663de9SDag-Erling Smørgrav /* if more than half the tcp handlers are in use, use a shorter 735b5663de9SDag-Erling Smørgrav * timeout for this TCP connection, we need to make space for 736b5663de9SDag-Erling Smørgrav * other connections to be able to get attention */ 737b5663de9SDag-Erling Smørgrav if(cur > max/2) 738b5663de9SDag-Erling Smørgrav c->tcp_timeout_msec = TCP_QUERY_TIMEOUT_FAST; 739b5663de9SDag-Erling Smørgrav comm_point_start_listening(c, fd, c->tcp_timeout_msec); 740b7579f77SDag-Erling Smørgrav } 741b7579f77SDag-Erling Smørgrav 742b7579f77SDag-Erling Smørgrav void comm_base_handle_slow_accept(int ATTR_UNUSED(fd), 743b7579f77SDag-Erling Smørgrav short ATTR_UNUSED(event), void* arg) 744b7579f77SDag-Erling Smørgrav { 745b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)arg; 746b7579f77SDag-Erling Smørgrav /* timeout for the slow accept, re-enable accepts again */ 747b7579f77SDag-Erling Smørgrav if(b->start_accept) { 748b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "wait is over, slow accept disabled"); 749b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_start_accept(b->start_accept)); 750b7579f77SDag-Erling Smørgrav (*b->start_accept)(b->cb_arg); 751b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 0; 752b7579f77SDag-Erling Smørgrav } 753b7579f77SDag-Erling Smørgrav } 754b7579f77SDag-Erling Smørgrav 755b7579f77SDag-Erling Smørgrav int comm_point_perform_accept(struct comm_point* c, 756b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t* addrlen) 757b7579f77SDag-Erling Smørgrav { 758b7579f77SDag-Erling Smørgrav int new_fd; 759b7579f77SDag-Erling Smørgrav *addrlen = (socklen_t)sizeof(*addr); 760b7579f77SDag-Erling Smørgrav new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen); 761b7579f77SDag-Erling Smørgrav if(new_fd == -1) { 762b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 763b7579f77SDag-Erling Smørgrav /* EINTR is signal interrupt. others are closed connection. */ 764b7579f77SDag-Erling Smørgrav if( errno == EINTR || errno == EAGAIN 765b7579f77SDag-Erling Smørgrav #ifdef EWOULDBLOCK 766b7579f77SDag-Erling Smørgrav || errno == EWOULDBLOCK 767b7579f77SDag-Erling Smørgrav #endif 768b7579f77SDag-Erling Smørgrav #ifdef ECONNABORTED 769b7579f77SDag-Erling Smørgrav || errno == ECONNABORTED 770b7579f77SDag-Erling Smørgrav #endif 771b7579f77SDag-Erling Smørgrav #ifdef EPROTO 772b7579f77SDag-Erling Smørgrav || errno == EPROTO 773b7579f77SDag-Erling Smørgrav #endif /* EPROTO */ 774b7579f77SDag-Erling Smørgrav ) 775b7579f77SDag-Erling Smørgrav return -1; 776b7579f77SDag-Erling Smørgrav #if defined(ENFILE) && defined(EMFILE) 777b7579f77SDag-Erling Smørgrav if(errno == ENFILE || errno == EMFILE) { 778b7579f77SDag-Erling Smørgrav /* out of file descriptors, likely outside of our 779b7579f77SDag-Erling Smørgrav * control. stop accept() calls for some time */ 780b7579f77SDag-Erling Smørgrav if(c->ev->base->stop_accept) { 781b7579f77SDag-Erling Smørgrav struct comm_base* b = c->ev->base; 782b7579f77SDag-Erling Smørgrav struct timeval tv; 783b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "out of file descriptors: " 784b7579f77SDag-Erling Smørgrav "slow accept"); 785b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 1; 786b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_stop_accept( 787b7579f77SDag-Erling Smørgrav b->stop_accept)); 788b7579f77SDag-Erling Smørgrav (*b->stop_accept)(b->cb_arg); 789b7579f77SDag-Erling Smørgrav /* set timeout, no mallocs */ 790b7579f77SDag-Erling Smørgrav tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; 791b5663de9SDag-Erling Smørgrav tv.tv_usec = (NETEVENT_SLOW_ACCEPT_TIME%1000)*1000; 792e2d15004SDag-Erling Smørgrav b->eb->slow_accept = ub_event_new(b->eb->base, 793e2d15004SDag-Erling Smørgrav -1, UB_EV_TIMEOUT, 794b7579f77SDag-Erling Smørgrav comm_base_handle_slow_accept, b); 795e2d15004SDag-Erling Smørgrav if(b->eb->slow_accept == NULL) { 796b7579f77SDag-Erling Smørgrav /* we do not want to log here, because 797b7579f77SDag-Erling Smørgrav * that would spam the logfiles. 798b7579f77SDag-Erling Smørgrav * error: "event_base_set failed." */ 799b7579f77SDag-Erling Smørgrav } 800e2d15004SDag-Erling Smørgrav else if(ub_event_add(b->eb->slow_accept, &tv) 801e2d15004SDag-Erling Smørgrav != 0) { 802b7579f77SDag-Erling Smørgrav /* we do not want to log here, 803b7579f77SDag-Erling Smørgrav * error: "event_add failed." */ 804b7579f77SDag-Erling Smørgrav } 805b7579f77SDag-Erling Smørgrav } 806b7579f77SDag-Erling Smørgrav return -1; 807b7579f77SDag-Erling Smørgrav } 808b7579f77SDag-Erling Smørgrav #endif 809ff825849SDag-Erling Smørgrav log_err_addr("accept failed", strerror(errno), addr, *addrlen); 810b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 811b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 812b7579f77SDag-Erling Smørgrav WSAGetLastError() == WSAECONNRESET) 813b7579f77SDag-Erling Smørgrav return -1; 814b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 815e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ); 816b7579f77SDag-Erling Smørgrav return -1; 817b7579f77SDag-Erling Smørgrav } 818ff825849SDag-Erling Smørgrav log_err_addr("accept failed", wsa_strerror(WSAGetLastError()), 819ff825849SDag-Erling Smørgrav addr, *addrlen); 820b7579f77SDag-Erling Smørgrav #endif 821b7579f77SDag-Erling Smørgrav return -1; 822b7579f77SDag-Erling Smørgrav } 823b7579f77SDag-Erling Smørgrav fd_set_nonblock(new_fd); 824b7579f77SDag-Erling Smørgrav return new_fd; 825b7579f77SDag-Erling Smørgrav } 826b7579f77SDag-Erling Smørgrav 827b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 828b7579f77SDag-Erling Smørgrav static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp), 829b7579f77SDag-Erling Smørgrav int ATTR_UNUSED(argi), long argl, long retvalue) 830b7579f77SDag-Erling Smørgrav { 831b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper, 832b7579f77SDag-Erling Smørgrav (oper&BIO_CB_RETURN)?"return":"before", 833b7579f77SDag-Erling Smørgrav (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"), 834b7579f77SDag-Erling Smørgrav WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":""); 835b7579f77SDag-Erling Smørgrav /* on windows, check if previous operation caused EWOULDBLOCK */ 836b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) || 837b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) { 838b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) 839e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock((struct ub_event*) 840e2d15004SDag-Erling Smørgrav BIO_get_callback_arg(b), UB_EV_READ); 841b7579f77SDag-Erling Smørgrav } 842b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) || 843b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) { 844b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) 845e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock((struct ub_event*) 846e2d15004SDag-Erling Smørgrav BIO_get_callback_arg(b), UB_EV_WRITE); 847b7579f77SDag-Erling Smørgrav } 848b7579f77SDag-Erling Smørgrav /* return original return value */ 849b7579f77SDag-Erling Smørgrav return retvalue; 850b7579f77SDag-Erling Smørgrav } 851b7579f77SDag-Erling Smørgrav 852b7579f77SDag-Erling Smørgrav /** set win bio callbacks for nonblocking operations */ 853b7579f77SDag-Erling Smørgrav void 854b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl) 855b7579f77SDag-Erling Smørgrav { 856b7579f77SDag-Erling Smørgrav SSL* ssl = (SSL*)thessl; 857b7579f77SDag-Erling Smørgrav /* set them both just in case, but usually they are the same BIO */ 858b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb); 859e2d15004SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)c->ev->ev); 860b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb); 861e2d15004SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)c->ev->ev); 862b7579f77SDag-Erling Smørgrav } 863b7579f77SDag-Erling Smørgrav #endif 864b7579f77SDag-Erling Smørgrav 865b7579f77SDag-Erling Smørgrav void 866b7579f77SDag-Erling Smørgrav comm_point_tcp_accept_callback(int fd, short event, void* arg) 867b7579f77SDag-Erling Smørgrav { 868b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg, *c_hdl; 869b7579f77SDag-Erling Smørgrav int new_fd; 870b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp_accept); 871e2d15004SDag-Erling Smørgrav if(!(event & UB_EV_READ)) { 872b7579f77SDag-Erling Smørgrav log_info("ignoring tcp accept event %d", (int)event); 873b7579f77SDag-Erling Smørgrav return; 874b7579f77SDag-Erling Smørgrav } 875e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base); 876b7579f77SDag-Erling Smørgrav /* find free tcp handler. */ 877b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 878b7579f77SDag-Erling Smørgrav log_warn("accepted too many tcp, connections full"); 879b7579f77SDag-Erling Smørgrav return; 880b7579f77SDag-Erling Smørgrav } 881b7579f77SDag-Erling Smørgrav /* accept incoming connection. */ 882b7579f77SDag-Erling Smørgrav c_hdl = c->tcp_free; 883b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 884b5663de9SDag-Erling Smørgrav (void)fd; 885b7579f77SDag-Erling Smørgrav new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr, 886b7579f77SDag-Erling Smørgrav &c_hdl->repinfo.addrlen); 887b7579f77SDag-Erling Smørgrav if(new_fd == -1) 888b7579f77SDag-Erling Smørgrav return; 889b7579f77SDag-Erling Smørgrav if(c->ssl) { 890b7579f77SDag-Erling Smørgrav c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd); 891b7579f77SDag-Erling Smørgrav if(!c_hdl->ssl) { 892b7579f77SDag-Erling Smørgrav c_hdl->fd = new_fd; 893b7579f77SDag-Erling Smørgrav comm_point_close(c_hdl); 894b7579f77SDag-Erling Smørgrav return; 895b7579f77SDag-Erling Smørgrav } 896b7579f77SDag-Erling Smørgrav c_hdl->ssl_shake_state = comm_ssl_shake_read; 897b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 898b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl); 899b7579f77SDag-Erling Smørgrav #endif 900b7579f77SDag-Erling Smørgrav } 901b7579f77SDag-Erling Smørgrav 902b7579f77SDag-Erling Smørgrav /* grab the tcp handler buffers */ 90309a3aaf3SDag-Erling Smørgrav c->cur_tcp_count++; 904b7579f77SDag-Erling Smørgrav c->tcp_free = c_hdl->tcp_free; 905b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 906b7579f77SDag-Erling Smørgrav /* stop accepting incoming queries for now. */ 907b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 908b7579f77SDag-Erling Smørgrav } 909b5663de9SDag-Erling Smørgrav setup_tcp_handler(c_hdl, new_fd, c->cur_tcp_count, c->max_tcp_count); 910b7579f77SDag-Erling Smørgrav } 911b7579f77SDag-Erling Smørgrav 912b7579f77SDag-Erling Smørgrav /** Make tcp handler free for next assignment */ 913b7579f77SDag-Erling Smørgrav static void 914b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(struct comm_point* c) 915b7579f77SDag-Erling Smørgrav { 916b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 917b7579f77SDag-Erling Smørgrav if(c->ssl) { 9188ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 919b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl); 920b7579f77SDag-Erling Smørgrav SSL_free(c->ssl); 921b7579f77SDag-Erling Smørgrav c->ssl = NULL; 9228ed2b524SDag-Erling Smørgrav #endif 923b7579f77SDag-Erling Smørgrav } 924b7579f77SDag-Erling Smørgrav comm_point_close(c); 925b7579f77SDag-Erling Smørgrav if(c->tcp_parent) { 92609a3aaf3SDag-Erling Smørgrav c->tcp_parent->cur_tcp_count--; 927b7579f77SDag-Erling Smørgrav c->tcp_free = c->tcp_parent->tcp_free; 928b7579f77SDag-Erling Smørgrav c->tcp_parent->tcp_free = c; 929b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 930b7579f77SDag-Erling Smørgrav /* re-enable listening on accept socket */ 931b7579f77SDag-Erling Smørgrav comm_point_start_listening(c->tcp_parent, -1, -1); 932b7579f77SDag-Erling Smørgrav } 933b7579f77SDag-Erling Smørgrav } 934b7579f77SDag-Erling Smørgrav } 935b7579f77SDag-Erling Smørgrav 936b7579f77SDag-Erling Smørgrav /** do the callback when writing is done */ 937b7579f77SDag-Erling Smørgrav static void 938b7579f77SDag-Erling Smørgrav tcp_callback_writer(struct comm_point* c) 939b7579f77SDag-Erling Smørgrav { 940b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 94117d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer); 942b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw) 943b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 944b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 945b7579f77SDag-Erling Smørgrav /* switch from listening(write) to listening(read) */ 946b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 947b7579f77SDag-Erling Smørgrav comm_point_start_listening(c, -1, -1); 948b7579f77SDag-Erling Smørgrav } 949b7579f77SDag-Erling Smørgrav 950b7579f77SDag-Erling Smørgrav /** do the callback when reading is done */ 951b7579f77SDag-Erling Smørgrav static void 952b7579f77SDag-Erling Smørgrav tcp_callback_reader(struct comm_point* c) 953b7579f77SDag-Erling Smørgrav { 954b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local); 95517d15b25SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 956b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw) 957b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 958b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 959b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp) 960b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 961b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 962b7579f77SDag-Erling Smørgrav if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) { 963b5663de9SDag-Erling Smørgrav comm_point_start_listening(c, -1, c->tcp_timeout_msec); 964b7579f77SDag-Erling Smørgrav } 965b7579f77SDag-Erling Smørgrav } 966b7579f77SDag-Erling Smørgrav 967b7579f77SDag-Erling Smørgrav /** continue ssl handshake */ 9688ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 969b7579f77SDag-Erling Smørgrav static int 970b7579f77SDag-Erling Smørgrav ssl_handshake(struct comm_point* c) 971b7579f77SDag-Erling Smørgrav { 972b7579f77SDag-Erling Smørgrav int r; 973b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_read) { 974b7579f77SDag-Erling Smørgrav /* read condition satisfied back to writing */ 975b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 1); 976b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 977b7579f77SDag-Erling Smørgrav return 1; 978b7579f77SDag-Erling Smørgrav } 979b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_write) { 980b7579f77SDag-Erling Smørgrav /* write condition satisfied, back to reading */ 981b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 982b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 983b7579f77SDag-Erling Smørgrav return 1; 984b7579f77SDag-Erling Smørgrav } 985b7579f77SDag-Erling Smørgrav 986b7579f77SDag-Erling Smørgrav ERR_clear_error(); 987b7579f77SDag-Erling Smørgrav r = SSL_do_handshake(c->ssl); 988b7579f77SDag-Erling Smørgrav if(r != 1) { 989b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 990b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_WANT_READ) { 991b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_read) 992b7579f77SDag-Erling Smørgrav return 1; 993b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 994b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 995b7579f77SDag-Erling Smørgrav return 1; 996b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 997b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_write) 998b7579f77SDag-Erling Smørgrav return 1; 999b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_write; 1000b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1001b7579f77SDag-Erling Smørgrav return 1; 1002b7579f77SDag-Erling Smørgrav } else if(r == 0) { 1003b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1004b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1005b7579f77SDag-Erling Smørgrav /* SYSCALL and errno==0 means closed uncleanly */ 1006b7579f77SDag-Erling Smørgrav if(errno != 0) 1007b7579f77SDag-Erling Smørgrav log_err("SSL_handshake syscall: %s", 1008b7579f77SDag-Erling Smørgrav strerror(errno)); 1009b7579f77SDag-Erling Smørgrav return 0; 1010b7579f77SDag-Erling Smørgrav } else { 1011b7579f77SDag-Erling Smørgrav log_crypto_err("ssl handshake failed"); 1012b7579f77SDag-Erling Smørgrav log_addr(1, "ssl handshake failed", &c->repinfo.addr, 1013b7579f77SDag-Erling Smørgrav c->repinfo.addrlen); 1014b7579f77SDag-Erling Smørgrav return 0; 1015b7579f77SDag-Erling Smørgrav } 1016b7579f77SDag-Erling Smørgrav } 1017b7579f77SDag-Erling Smørgrav /* this is where peer verification could take place */ 1018b7579f77SDag-Erling Smørgrav log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr, 1019b7579f77SDag-Erling Smørgrav c->repinfo.addrlen); 1020b7579f77SDag-Erling Smørgrav 1021b7579f77SDag-Erling Smørgrav /* setup listen rw correctly */ 1022b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) { 1023b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_read) 1024b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1025b7579f77SDag-Erling Smørgrav } else { 1026b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 1); 1027b7579f77SDag-Erling Smørgrav } 1028b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 1029b7579f77SDag-Erling Smørgrav return 1; 1030b7579f77SDag-Erling Smørgrav } 10318ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1032b7579f77SDag-Erling Smørgrav 1033b7579f77SDag-Erling Smørgrav /** ssl read callback on TCP */ 1034b7579f77SDag-Erling Smørgrav static int 1035b7579f77SDag-Erling Smørgrav ssl_handle_read(struct comm_point* c) 1036b7579f77SDag-Erling Smørgrav { 10378ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1038b7579f77SDag-Erling Smørgrav int r; 1039b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) { 1040b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c)) 1041b7579f77SDag-Erling Smørgrav return 0; 1042b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) 1043b7579f77SDag-Erling Smørgrav return 1; 1044b7579f77SDag-Erling Smørgrav } 1045b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 1046b7579f77SDag-Erling Smørgrav /* read length bytes */ 1047b7579f77SDag-Erling Smørgrav ERR_clear_error(); 104817d15b25SDag-Erling Smørgrav if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer, 1049b7579f77SDag-Erling Smørgrav c->tcp_byte_count), (int)(sizeof(uint16_t) - 1050b7579f77SDag-Erling Smørgrav c->tcp_byte_count))) <= 0) { 1051b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1052b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1053b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */ 1054b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1055b7579f77SDag-Erling Smørgrav return 1; /* read more later */ 1056b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1057b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write; 1058b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1059b7579f77SDag-Erling Smørgrav return 1; 1060b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1061b7579f77SDag-Erling Smørgrav if(errno != 0) 1062b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s", 1063b7579f77SDag-Erling Smørgrav strerror(errno)); 1064b7579f77SDag-Erling Smørgrav return 0; 1065b7579f77SDag-Erling Smørgrav } 1066b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_read"); 1067b7579f77SDag-Erling Smørgrav return 0; 1068b7579f77SDag-Erling Smørgrav } 1069b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1070b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count != sizeof(uint16_t)) 1071b7579f77SDag-Erling Smørgrav return 1; 107217d15b25SDag-Erling Smørgrav if(sldns_buffer_read_u16_at(c->buffer, 0) > 107317d15b25SDag-Erling Smørgrav sldns_buffer_capacity(c->buffer)) { 1074b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped larger than buffer"); 1075b7579f77SDag-Erling Smørgrav return 0; 1076b7579f77SDag-Erling Smørgrav } 107717d15b25SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, 107817d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 0)); 107917d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1080b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped bogus too short."); 1081b7579f77SDag-Erling Smørgrav return 0; 1082b7579f77SDag-Erling Smørgrav } 1083b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Reading ssl tcp query of length %d", 108417d15b25SDag-Erling Smørgrav (int)sldns_buffer_limit(c->buffer)); 1085b7579f77SDag-Erling Smørgrav } 108617d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 1087b7579f77SDag-Erling Smørgrav ERR_clear_error(); 108817d15b25SDag-Erling Smørgrav r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer), 108917d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer)); 1090b7579f77SDag-Erling Smørgrav if(r <= 0) { 1091b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1092b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1093b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */ 1094b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1095b7579f77SDag-Erling Smørgrav return 1; /* read more later */ 1096b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1097b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write; 1098b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1099b7579f77SDag-Erling Smørgrav return 1; 1100b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1101b7579f77SDag-Erling Smørgrav if(errno != 0) 1102b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s", 1103b7579f77SDag-Erling Smørgrav strerror(errno)); 1104b7579f77SDag-Erling Smørgrav return 0; 1105b7579f77SDag-Erling Smørgrav } 1106b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_read"); 1107b7579f77SDag-Erling Smørgrav return 0; 1108b7579f77SDag-Erling Smørgrav } 110917d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r); 111017d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) <= 0) { 1111b7579f77SDag-Erling Smørgrav tcp_callback_reader(c); 1112b7579f77SDag-Erling Smørgrav } 1113b7579f77SDag-Erling Smørgrav return 1; 11148ed2b524SDag-Erling Smørgrav #else 11158ed2b524SDag-Erling Smørgrav (void)c; 11168ed2b524SDag-Erling Smørgrav return 0; 11178ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1118b7579f77SDag-Erling Smørgrav } 1119b7579f77SDag-Erling Smørgrav 1120b7579f77SDag-Erling Smørgrav /** ssl write callback on TCP */ 1121b7579f77SDag-Erling Smørgrav static int 1122b7579f77SDag-Erling Smørgrav ssl_handle_write(struct comm_point* c) 1123b7579f77SDag-Erling Smørgrav { 11248ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1125b7579f77SDag-Erling Smørgrav int r; 1126b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) { 1127b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c)) 1128b7579f77SDag-Erling Smørgrav return 0; 1129b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) 1130b7579f77SDag-Erling Smørgrav return 1; 1131b7579f77SDag-Erling Smørgrav } 1132b7579f77SDag-Erling Smørgrav /* ignore return, if fails we may simply block */ 1133b7579f77SDag-Erling Smørgrav (void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); 1134b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 113517d15b25SDag-Erling Smørgrav uint16_t len = htons(sldns_buffer_limit(c->buffer)); 1136b7579f77SDag-Erling Smørgrav ERR_clear_error(); 1137b7579f77SDag-Erling Smørgrav r = SSL_write(c->ssl, 1138b7579f77SDag-Erling Smørgrav (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1139b7579f77SDag-Erling Smørgrav (int)(sizeof(uint16_t)-c->tcp_byte_count)); 1140b7579f77SDag-Erling Smørgrav if(r <= 0) { 1141b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1142b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1143b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1144b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1145b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 1146b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1147b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */ 1148b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1149b7579f77SDag-Erling Smørgrav return 1; /* write more later */ 1150b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1151b7579f77SDag-Erling Smørgrav if(errno != 0) 1152b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s", 1153b7579f77SDag-Erling Smørgrav strerror(errno)); 1154b7579f77SDag-Erling Smørgrav return 0; 1155b7579f77SDag-Erling Smørgrav } 1156b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_write"); 1157b7579f77SDag-Erling Smørgrav return 0; 1158b7579f77SDag-Erling Smørgrav } 1159b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1160b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) 1161b7579f77SDag-Erling Smørgrav return 1; 116217d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, c->tcp_byte_count - 1163b7579f77SDag-Erling Smørgrav sizeof(uint16_t)); 116417d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1165b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1166b7579f77SDag-Erling Smørgrav return 1; 1167b7579f77SDag-Erling Smørgrav } 1168b7579f77SDag-Erling Smørgrav } 116917d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 1170b7579f77SDag-Erling Smørgrav ERR_clear_error(); 117117d15b25SDag-Erling Smørgrav r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer), 117217d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer)); 1173b7579f77SDag-Erling Smørgrav if(r <= 0) { 1174b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1175b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1176b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1177b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1178b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 1179b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1180b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */ 1181b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1182b7579f77SDag-Erling Smørgrav return 1; /* write more later */ 1183b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1184b7579f77SDag-Erling Smørgrav if(errno != 0) 1185b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s", 1186b7579f77SDag-Erling Smørgrav strerror(errno)); 1187b7579f77SDag-Erling Smørgrav return 0; 1188b7579f77SDag-Erling Smørgrav } 1189b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_write"); 1190b7579f77SDag-Erling Smørgrav return 0; 1191b7579f77SDag-Erling Smørgrav } 119217d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r); 1193b7579f77SDag-Erling Smørgrav 119417d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1195b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1196b7579f77SDag-Erling Smørgrav } 1197b7579f77SDag-Erling Smørgrav return 1; 11988ed2b524SDag-Erling Smørgrav #else 11998ed2b524SDag-Erling Smørgrav (void)c; 12008ed2b524SDag-Erling Smørgrav return 0; 12018ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1202b7579f77SDag-Erling Smørgrav } 1203b7579f77SDag-Erling Smørgrav 1204b7579f77SDag-Erling Smørgrav /** handle ssl tcp connection with dns contents */ 1205b7579f77SDag-Erling Smørgrav static int 1206b7579f77SDag-Erling Smørgrav ssl_handle_it(struct comm_point* c) 1207b7579f77SDag-Erling Smørgrav { 1208b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) 1209b7579f77SDag-Erling Smørgrav return ssl_handle_read(c); 1210b7579f77SDag-Erling Smørgrav return ssl_handle_write(c); 1211b7579f77SDag-Erling Smørgrav } 1212b7579f77SDag-Erling Smørgrav 1213b7579f77SDag-Erling Smørgrav /** Handle tcp reading callback. 1214b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket. 1215b7579f77SDag-Erling Smørgrav * @param c: comm point to read from into buffer. 1216b7579f77SDag-Erling Smørgrav * @param short_ok: if true, very short packets are OK (for comm_local). 1217b7579f77SDag-Erling Smørgrav * @return: 0 on error 1218b7579f77SDag-Erling Smørgrav */ 1219b7579f77SDag-Erling Smørgrav static int 1220b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) 1221b7579f77SDag-Erling Smørgrav { 1222b7579f77SDag-Erling Smørgrav ssize_t r; 1223b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local); 1224b7579f77SDag-Erling Smørgrav if(c->ssl) 1225b7579f77SDag-Erling Smørgrav return ssl_handle_it(c); 1226b7579f77SDag-Erling Smørgrav if(!c->tcp_is_reading) 1227b7579f77SDag-Erling Smørgrav return 0; 1228b7579f77SDag-Erling Smørgrav 1229b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 1230b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 1231b7579f77SDag-Erling Smørgrav /* read length bytes */ 123217d15b25SDag-Erling Smørgrav r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count), 1233b7579f77SDag-Erling Smørgrav sizeof(uint16_t)-c->tcp_byte_count, 0); 1234b7579f77SDag-Erling Smørgrav if(r == 0) 1235b7579f77SDag-Erling Smørgrav return 0; 1236b7579f77SDag-Erling Smørgrav else if(r == -1) { 1237b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1238b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1239b7579f77SDag-Erling Smørgrav return 1; 1240b7579f77SDag-Erling Smørgrav #ifdef ECONNRESET 1241b7579f77SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2) 1242b7579f77SDag-Erling Smørgrav return 0; /* silence reset by peer */ 1243b7579f77SDag-Erling Smørgrav #endif 1244ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp s)", strerror(errno), 1245ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1246b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1247b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET) 1248b7579f77SDag-Erling Smørgrav return 0; 1249b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1250b7579f77SDag-Erling Smørgrav return 1; 1251b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1252e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, 1253e2d15004SDag-Erling Smørgrav UB_EV_READ); 1254b7579f77SDag-Erling Smørgrav return 1; 1255b7579f77SDag-Erling Smørgrav } 1256ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp s)", 1257ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1258ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1259b7579f77SDag-Erling Smørgrav #endif 1260b7579f77SDag-Erling Smørgrav return 0; 1261b7579f77SDag-Erling Smørgrav } 1262b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1263b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count != sizeof(uint16_t)) 1264b7579f77SDag-Erling Smørgrav return 1; 126517d15b25SDag-Erling Smørgrav if(sldns_buffer_read_u16_at(c->buffer, 0) > 126617d15b25SDag-Erling Smørgrav sldns_buffer_capacity(c->buffer)) { 1267b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp: dropped larger than buffer"); 1268b7579f77SDag-Erling Smørgrav return 0; 1269b7579f77SDag-Erling Smørgrav } 127017d15b25SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, 127117d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 0)); 1272b7579f77SDag-Erling Smørgrav if(!short_ok && 127317d15b25SDag-Erling Smørgrav sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1274b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp: dropped bogus too short."); 1275b7579f77SDag-Erling Smørgrav return 0; 1276b7579f77SDag-Erling Smørgrav } 1277b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Reading tcp query of length %d", 127817d15b25SDag-Erling Smørgrav (int)sldns_buffer_limit(c->buffer)); 1279b7579f77SDag-Erling Smørgrav } 1280b7579f77SDag-Erling Smørgrav 128117d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 128217d15b25SDag-Erling Smørgrav r = recv(fd, (void*)sldns_buffer_current(c->buffer), 128317d15b25SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer), 0); 1284b7579f77SDag-Erling Smørgrav if(r == 0) { 1285b7579f77SDag-Erling Smørgrav return 0; 1286b7579f77SDag-Erling Smørgrav } else if(r == -1) { 1287b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1288b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1289b7579f77SDag-Erling Smørgrav return 1; 1290ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp r)", strerror(errno), 1291ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1292b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1293b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET) 1294b7579f77SDag-Erling Smørgrav return 0; 1295b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1296b7579f77SDag-Erling Smørgrav return 1; 1297b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1298e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_READ); 1299b7579f77SDag-Erling Smørgrav return 1; 1300b7579f77SDag-Erling Smørgrav } 1301ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp r)", 1302ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1303ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1304b7579f77SDag-Erling Smørgrav #endif 1305b7579f77SDag-Erling Smørgrav return 0; 1306b7579f77SDag-Erling Smørgrav } 130717d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, r); 130817d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) <= 0) { 1309b7579f77SDag-Erling Smørgrav tcp_callback_reader(c); 1310b7579f77SDag-Erling Smørgrav } 1311b7579f77SDag-Erling Smørgrav return 1; 1312b7579f77SDag-Erling Smørgrav } 1313b7579f77SDag-Erling Smørgrav 1314b7579f77SDag-Erling Smørgrav /** 1315b7579f77SDag-Erling Smørgrav * Handle tcp writing callback. 1316b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket. 1317b7579f77SDag-Erling Smørgrav * @param c: comm point to write buffer out of. 1318b7579f77SDag-Erling Smørgrav * @return: 0 on error 1319b7579f77SDag-Erling Smørgrav */ 1320b7579f77SDag-Erling Smørgrav static int 1321b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_write(int fd, struct comm_point* c) 1322b7579f77SDag-Erling Smørgrav { 1323b7579f77SDag-Erling Smørgrav ssize_t r; 132465b390aaSDag-Erling Smørgrav struct sldns_buffer *buffer; 1325b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 132665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 132765b390aaSDag-Erling Smørgrav buffer = c->dnscrypt_buffer; 132865b390aaSDag-Erling Smørgrav #else 132965b390aaSDag-Erling Smørgrav buffer = c->buffer; 133065b390aaSDag-Erling Smørgrav #endif 1331b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading && !c->ssl) 1332b7579f77SDag-Erling Smørgrav return 0; 1333b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 1334b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) { 1335b7579f77SDag-Erling Smørgrav /* check for pending error from nonblocking connect */ 1336b7579f77SDag-Erling Smørgrav /* from Stevens, unix network programming, vol1, 3rd ed, p450*/ 1337b7579f77SDag-Erling Smørgrav int error = 0; 1338b7579f77SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(error); 1339b7579f77SDag-Erling Smørgrav if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1340b7579f77SDag-Erling Smørgrav &len) < 0){ 1341b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1342b7579f77SDag-Erling Smørgrav error = errno; /* on solaris errno is error */ 1343b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1344b7579f77SDag-Erling Smørgrav error = WSAGetLastError(); 1345b7579f77SDag-Erling Smørgrav #endif 1346b7579f77SDag-Erling Smørgrav } 1347b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1348b7579f77SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK) 1349b7579f77SDag-Erling Smørgrav if(error == EINPROGRESS || error == EWOULDBLOCK) 1350b7579f77SDag-Erling Smørgrav return 1; /* try again later */ 1351b7579f77SDag-Erling Smørgrav else 1352b7579f77SDag-Erling Smørgrav #endif 1353b7579f77SDag-Erling Smørgrav if(error != 0 && verbosity < 2) 1354b7579f77SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */ 1355b7579f77SDag-Erling Smørgrav else if(error != 0) { 1356ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", strerror(error), 1357ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1358b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1359b7579f77SDag-Erling Smørgrav /* examine error */ 1360b7579f77SDag-Erling Smørgrav if(error == WSAEINPROGRESS) 1361b7579f77SDag-Erling Smørgrav return 1; 1362b7579f77SDag-Erling Smørgrav else if(error == WSAEWOULDBLOCK) { 1363e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE); 1364b7579f77SDag-Erling Smørgrav return 1; 1365b7579f77SDag-Erling Smørgrav } else if(error != 0 && verbosity < 2) 1366b7579f77SDag-Erling Smørgrav return 0; 1367b7579f77SDag-Erling Smørgrav else if(error != 0) { 1368ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", wsa_strerror(error), 1369ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1370b7579f77SDag-Erling Smørgrav #endif /* USE_WINSOCK */ 1371b7579f77SDag-Erling Smørgrav return 0; 1372b7579f77SDag-Erling Smørgrav } 1373b7579f77SDag-Erling Smørgrav } 1374b7579f77SDag-Erling Smørgrav if(c->ssl) 1375b7579f77SDag-Erling Smørgrav return ssl_handle_it(c); 1376b7579f77SDag-Erling Smørgrav 1377b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1378b5663de9SDag-Erling Smørgrav /* Only try this on first use of a connection that uses tfo, 1379b5663de9SDag-Erling Smørgrav otherwise fall through to normal write */ 1380b5663de9SDag-Erling Smørgrav /* Also, TFO support on WINDOWS not implemented at the moment */ 1381b5663de9SDag-Erling Smørgrav if(c->tcp_do_fastopen == 1) { 1382b5663de9SDag-Erling Smørgrav /* this form of sendmsg() does both a connect() and send() so need to 1383b5663de9SDag-Erling Smørgrav look for various flavours of error*/ 138465b390aaSDag-Erling Smørgrav uint16_t len = htons(sldns_buffer_limit(buffer)); 1385b5663de9SDag-Erling Smørgrav struct msghdr msg; 1386b5663de9SDag-Erling Smørgrav struct iovec iov[2]; 1387b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1388b5663de9SDag-Erling Smørgrav memset(&msg, 0, sizeof(msg)); 1389b5663de9SDag-Erling Smørgrav iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count; 1390b5663de9SDag-Erling Smørgrav iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count; 139165b390aaSDag-Erling Smørgrav iov[1].iov_base = sldns_buffer_begin(buffer); 139265b390aaSDag-Erling Smørgrav iov[1].iov_len = sldns_buffer_limit(buffer); 1393b5663de9SDag-Erling Smørgrav log_assert(iov[0].iov_len > 0); 1394b5663de9SDag-Erling Smørgrav log_assert(iov[1].iov_len > 0); 1395b5663de9SDag-Erling Smørgrav msg.msg_name = &c->repinfo.addr; 1396b5663de9SDag-Erling Smørgrav msg.msg_namelen = c->repinfo.addrlen; 1397b5663de9SDag-Erling Smørgrav msg.msg_iov = iov; 1398b5663de9SDag-Erling Smørgrav msg.msg_iovlen = 2; 1399b5663de9SDag-Erling Smørgrav r = sendmsg(fd, &msg, MSG_FASTOPEN); 1400b5663de9SDag-Erling Smørgrav if (r == -1) { 1401b5663de9SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK) 1402b5663de9SDag-Erling Smørgrav /* Handshake is underway, maybe because no TFO cookie available. 1403*8a384985SDag-Erling Smørgrav Come back to write the message*/ 1404b5663de9SDag-Erling Smørgrav if(errno == EINPROGRESS || errno == EWOULDBLOCK) 1405b5663de9SDag-Erling Smørgrav return 1; 1406b5663de9SDag-Erling Smørgrav #endif 1407b5663de9SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1408b5663de9SDag-Erling Smørgrav return 1; 1409b5663de9SDag-Erling Smørgrav /* Not handling EISCONN here as shouldn't ever hit that case.*/ 1410c7f4d7adSDag-Erling Smørgrav if(errno != EPIPE && errno != 0 && verbosity < 2) 1411b5663de9SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */ 1412c7f4d7adSDag-Erling Smørgrav if(errno != EPIPE && errno != 0) { 1413b5663de9SDag-Erling Smørgrav log_err_addr("tcp sendmsg", strerror(errno), 1414b5663de9SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1415b5663de9SDag-Erling Smørgrav return 0; 1416c7f4d7adSDag-Erling Smørgrav } 1417c7f4d7adSDag-Erling Smørgrav /* fallthrough to nonFASTOPEN 1418c7f4d7adSDag-Erling Smørgrav * (MSG_FASTOPEN on Linux 3 produces EPIPE) 1419c7f4d7adSDag-Erling Smørgrav * we need to perform connect() */ 1420c7f4d7adSDag-Erling Smørgrav if(connect(fd, (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen) == -1) { 1421c7f4d7adSDag-Erling Smørgrav #ifdef EINPROGRESS 1422c7f4d7adSDag-Erling Smørgrav if(errno == EINPROGRESS) 1423c7f4d7adSDag-Erling Smørgrav return 1; /* wait until connect done*/ 1424c7f4d7adSDag-Erling Smørgrav #endif 1425c7f4d7adSDag-Erling Smørgrav #ifdef USE_WINSOCK 1426c7f4d7adSDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 1427c7f4d7adSDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) 1428c7f4d7adSDag-Erling Smørgrav return 1; /* wait until connect done*/ 1429c7f4d7adSDag-Erling Smørgrav #endif 1430c7f4d7adSDag-Erling Smørgrav if(tcp_connect_errno_needs_log( 1431c7f4d7adSDag-Erling Smørgrav (struct sockaddr *)&c->repinfo.addr, c->repinfo.addrlen)) { 1432c7f4d7adSDag-Erling Smørgrav log_err_addr("outgoing tcp: connect after EPIPE for fastopen", 1433c7f4d7adSDag-Erling Smørgrav strerror(errno), &c->repinfo.addr, c->repinfo.addrlen); 1434c7f4d7adSDag-Erling Smørgrav } 1435c7f4d7adSDag-Erling Smørgrav return 0; 1436c7f4d7adSDag-Erling Smørgrav } 1437c7f4d7adSDag-Erling Smørgrav 1438b5663de9SDag-Erling Smørgrav } else { 1439b5663de9SDag-Erling Smørgrav c->tcp_byte_count += r; 1440b5663de9SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) 1441b5663de9SDag-Erling Smørgrav return 1; 144265b390aaSDag-Erling Smørgrav sldns_buffer_set_position(buffer, c->tcp_byte_count - 1443b5663de9SDag-Erling Smørgrav sizeof(uint16_t)); 144465b390aaSDag-Erling Smørgrav if(sldns_buffer_remaining(buffer) == 0) { 1445b5663de9SDag-Erling Smørgrav tcp_callback_writer(c); 1446b5663de9SDag-Erling Smørgrav return 1; 1447b5663de9SDag-Erling Smørgrav } 1448b5663de9SDag-Erling Smørgrav } 1449b5663de9SDag-Erling Smørgrav } 1450b5663de9SDag-Erling Smørgrav #endif /* USE_MSG_FASTOPEN */ 1451b5663de9SDag-Erling Smørgrav 1452b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 145365b390aaSDag-Erling Smørgrav uint16_t len = htons(sldns_buffer_limit(buffer)); 1454b7579f77SDag-Erling Smørgrav #ifdef HAVE_WRITEV 1455b7579f77SDag-Erling Smørgrav struct iovec iov[2]; 1456b7579f77SDag-Erling Smørgrav iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count; 1457b7579f77SDag-Erling Smørgrav iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count; 145865b390aaSDag-Erling Smørgrav iov[1].iov_base = sldns_buffer_begin(buffer); 145965b390aaSDag-Erling Smørgrav iov[1].iov_len = sldns_buffer_limit(buffer); 1460b7579f77SDag-Erling Smørgrav log_assert(iov[0].iov_len > 0); 1461b7579f77SDag-Erling Smørgrav log_assert(iov[1].iov_len > 0); 1462b7579f77SDag-Erling Smørgrav r = writev(fd, iov, 2); 1463b7579f77SDag-Erling Smørgrav #else /* HAVE_WRITEV */ 1464b7579f77SDag-Erling Smørgrav r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1465b7579f77SDag-Erling Smørgrav sizeof(uint16_t)-c->tcp_byte_count, 0); 1466b7579f77SDag-Erling Smørgrav #endif /* HAVE_WRITEV */ 1467b7579f77SDag-Erling Smørgrav if(r == -1) { 1468b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1469b7579f77SDag-Erling Smørgrav # ifdef EPIPE 1470b7579f77SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2) 1471b7579f77SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */ 1472b7579f77SDag-Erling Smørgrav #endif 1473b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1474b7579f77SDag-Erling Smørgrav return 1; 1475ff825849SDag-Erling Smørgrav # ifdef HAVE_WRITEV 1476ff825849SDag-Erling Smørgrav log_err_addr("tcp writev", strerror(errno), 1477ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1478ff825849SDag-Erling Smørgrav # else /* HAVE_WRITEV */ 1479ff825849SDag-Erling Smørgrav log_err_addr("tcp send s", strerror(errno), 1480ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1481ff825849SDag-Erling Smørgrav # endif /* HAVE_WRITEV */ 1482b7579f77SDag-Erling Smørgrav #else 1483b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAENOTCONN) 1484b7579f77SDag-Erling Smørgrav return 1; 1485b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1486b7579f77SDag-Erling Smørgrav return 1; 1487b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1488e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, 1489e2d15004SDag-Erling Smørgrav UB_EV_WRITE); 1490b7579f77SDag-Erling Smørgrav return 1; 1491b7579f77SDag-Erling Smørgrav } 1492ff825849SDag-Erling Smørgrav log_err_addr("tcp send s", 1493ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1494ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1495b7579f77SDag-Erling Smørgrav #endif 1496b7579f77SDag-Erling Smørgrav return 0; 1497b7579f77SDag-Erling Smørgrav } 1498b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1499b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) 1500b7579f77SDag-Erling Smørgrav return 1; 150165b390aaSDag-Erling Smørgrav sldns_buffer_set_position(buffer, c->tcp_byte_count - 1502b7579f77SDag-Erling Smørgrav sizeof(uint16_t)); 150365b390aaSDag-Erling Smørgrav if(sldns_buffer_remaining(buffer) == 0) { 1504b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1505b7579f77SDag-Erling Smørgrav return 1; 1506b7579f77SDag-Erling Smørgrav } 1507b7579f77SDag-Erling Smørgrav } 150865b390aaSDag-Erling Smørgrav log_assert(sldns_buffer_remaining(buffer) > 0); 150965b390aaSDag-Erling Smørgrav r = send(fd, (void*)sldns_buffer_current(buffer), 151065b390aaSDag-Erling Smørgrav sldns_buffer_remaining(buffer), 0); 1511b7579f77SDag-Erling Smørgrav if(r == -1) { 1512b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1513b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1514b7579f77SDag-Erling Smørgrav return 1; 1515ff825849SDag-Erling Smørgrav log_err_addr("tcp send r", strerror(errno), 1516ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1517b7579f77SDag-Erling Smørgrav #else 1518b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1519b7579f77SDag-Erling Smørgrav return 1; 1520b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1521e2d15004SDag-Erling Smørgrav ub_winsock_tcp_wouldblock(c->ev->ev, UB_EV_WRITE); 1522b7579f77SDag-Erling Smørgrav return 1; 1523b7579f77SDag-Erling Smørgrav } 1524ff825849SDag-Erling Smørgrav log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()), 1525ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1526b7579f77SDag-Erling Smørgrav #endif 1527b7579f77SDag-Erling Smørgrav return 0; 1528b7579f77SDag-Erling Smørgrav } 152965b390aaSDag-Erling Smørgrav sldns_buffer_skip(buffer, r); 1530b7579f77SDag-Erling Smørgrav 153165b390aaSDag-Erling Smørgrav if(sldns_buffer_remaining(buffer) == 0) { 1532b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1533b7579f77SDag-Erling Smørgrav } 1534b7579f77SDag-Erling Smørgrav 1535b7579f77SDag-Erling Smørgrav return 1; 1536b7579f77SDag-Erling Smørgrav } 1537b7579f77SDag-Erling Smørgrav 1538b7579f77SDag-Erling Smørgrav void 1539b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_callback(int fd, short event, void* arg) 1540b7579f77SDag-Erling Smørgrav { 1541b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1542b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 1543e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base); 1544b7579f77SDag-Erling Smørgrav 154565b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 154665b390aaSDag-Erling Smørgrav /* Initialize if this is a dnscrypt socket */ 154765b390aaSDag-Erling Smørgrav if(c->tcp_parent) { 154865b390aaSDag-Erling Smørgrav c->dnscrypt = c->tcp_parent->dnscrypt; 154965b390aaSDag-Erling Smørgrav } 155065b390aaSDag-Erling Smørgrav if(c->dnscrypt && c->dnscrypt_buffer == c->buffer) { 155165b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = sldns_buffer_new(sldns_buffer_capacity(c->buffer)); 155265b390aaSDag-Erling Smørgrav if(!c->dnscrypt_buffer) { 155365b390aaSDag-Erling Smørgrav log_err("Could not allocate dnscrypt buffer"); 1554971980c3SDag-Erling Smørgrav reclaim_tcp_handler(c); 1555971980c3SDag-Erling Smørgrav if(!c->tcp_do_close) { 1556971980c3SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point( 1557971980c3SDag-Erling Smørgrav c->callback)); 1558971980c3SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1559971980c3SDag-Erling Smørgrav NETEVENT_CLOSED, NULL); 1560971980c3SDag-Erling Smørgrav } 156165b390aaSDag-Erling Smørgrav return; 156265b390aaSDag-Erling Smørgrav } 156365b390aaSDag-Erling Smørgrav } 156465b390aaSDag-Erling Smørgrav #endif 156565b390aaSDag-Erling Smørgrav 1566e2d15004SDag-Erling Smørgrav if(event&UB_EV_READ) { 1567b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 0)) { 1568b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1569b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1570b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point( 1571b7579f77SDag-Erling Smørgrav c->callback)); 1572b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1573b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL); 1574b7579f77SDag-Erling Smørgrav } 1575b7579f77SDag-Erling Smørgrav } 1576b7579f77SDag-Erling Smørgrav return; 1577b7579f77SDag-Erling Smørgrav } 1578e2d15004SDag-Erling Smørgrav if(event&UB_EV_WRITE) { 1579b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_write(fd, c)) { 1580b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1581b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1582b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point( 1583b7579f77SDag-Erling Smørgrav c->callback)); 1584b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1585b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL); 1586b7579f77SDag-Erling Smørgrav } 1587b7579f77SDag-Erling Smørgrav } 1588b7579f77SDag-Erling Smørgrav return; 1589b7579f77SDag-Erling Smørgrav } 1590e2d15004SDag-Erling Smørgrav if(event&UB_EV_TIMEOUT) { 1591b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp took too long, dropped"); 1592b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1593b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1594b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 1595b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1596b7579f77SDag-Erling Smørgrav NETEVENT_TIMEOUT, NULL); 1597b7579f77SDag-Erling Smørgrav } 1598b7579f77SDag-Erling Smørgrav return; 1599b7579f77SDag-Erling Smørgrav } 1600b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for tcphdl.", event); 1601b7579f77SDag-Erling Smørgrav } 1602b7579f77SDag-Erling Smørgrav 1603b7579f77SDag-Erling Smørgrav void comm_point_local_handle_callback(int fd, short event, void* arg) 1604b7579f77SDag-Erling Smørgrav { 1605b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1606b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_local); 1607e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base); 1608b7579f77SDag-Erling Smørgrav 1609e2d15004SDag-Erling Smørgrav if(event&UB_EV_READ) { 1610b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 1)) { 1611b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 1612b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED, 1613b7579f77SDag-Erling Smørgrav NULL); 1614b7579f77SDag-Erling Smørgrav } 1615b7579f77SDag-Erling Smørgrav return; 1616b7579f77SDag-Erling Smørgrav } 1617b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for localhdl.", event); 1618b7579f77SDag-Erling Smørgrav } 1619b7579f77SDag-Erling Smørgrav 1620b7579f77SDag-Erling Smørgrav void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), 1621b7579f77SDag-Erling Smørgrav short event, void* arg) 1622b7579f77SDag-Erling Smørgrav { 1623b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1624b7579f77SDag-Erling Smørgrav int err = NETEVENT_NOERROR; 1625b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_raw); 1626e2d15004SDag-Erling Smørgrav ub_comm_base_now(c->ev->base); 1627b7579f77SDag-Erling Smørgrav 1628e2d15004SDag-Erling Smørgrav if(event&UB_EV_TIMEOUT) 1629b7579f77SDag-Erling Smørgrav err = NETEVENT_TIMEOUT; 1630b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point_raw(c->callback)); 1631b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, err, NULL); 1632b7579f77SDag-Erling Smørgrav } 1633b7579f77SDag-Erling Smørgrav 1634b7579f77SDag-Erling Smørgrav struct comm_point* 163517d15b25SDag-Erling Smørgrav comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, 16363005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1637b7579f77SDag-Erling Smørgrav { 1638b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1639b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1640b7579f77SDag-Erling Smørgrav short evbits; 1641b7579f77SDag-Erling Smørgrav if(!c) 1642b7579f77SDag-Erling Smørgrav return NULL; 1643b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1644b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1645b7579f77SDag-Erling Smørgrav if(!c->ev) { 1646b7579f77SDag-Erling Smørgrav free(c); 1647b7579f77SDag-Erling Smørgrav return NULL; 1648b7579f77SDag-Erling Smørgrav } 1649b7579f77SDag-Erling Smørgrav c->ev->base = base; 1650b7579f77SDag-Erling Smørgrav c->fd = fd; 1651b7579f77SDag-Erling Smørgrav c->buffer = buffer; 1652b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1653b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1654b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1655b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1656b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 165709a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1658b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1659b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1660b7579f77SDag-Erling Smørgrav c->type = comm_udp; 1661b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1662b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1663b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1664b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1665b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1666b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1667b5663de9SDag-Erling Smørgrav #endif 166865b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 166965b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 167065b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = buffer; 167165b390aaSDag-Erling Smørgrav #endif 1672b7579f77SDag-Erling Smørgrav c->inuse = 0; 1673b7579f77SDag-Erling Smørgrav c->callback = callback; 1674b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1675e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST; 1676e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 1677e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 1678e2d15004SDag-Erling Smørgrav comm_point_udp_callback, c); 1679e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) { 1680b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event"); 1681b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1682b7579f77SDag-Erling Smørgrav return NULL; 1683b7579f77SDag-Erling Smørgrav } 1684e2d15004SDag-Erling Smørgrav if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) { 1685b7579f77SDag-Erling Smørgrav log_err("could not add udp event"); 1686b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1687b7579f77SDag-Erling Smørgrav return NULL; 1688b7579f77SDag-Erling Smørgrav } 1689b7579f77SDag-Erling Smørgrav return c; 1690b7579f77SDag-Erling Smørgrav } 1691b7579f77SDag-Erling Smørgrav 1692b7579f77SDag-Erling Smørgrav struct comm_point* 1693b7579f77SDag-Erling Smørgrav comm_point_create_udp_ancil(struct comm_base *base, int fd, 169417d15b25SDag-Erling Smørgrav sldns_buffer* buffer, 16953005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1696b7579f77SDag-Erling Smørgrav { 1697b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1698b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1699b7579f77SDag-Erling Smørgrav short evbits; 1700b7579f77SDag-Erling Smørgrav if(!c) 1701b7579f77SDag-Erling Smørgrav return NULL; 1702b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1703b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1704b7579f77SDag-Erling Smørgrav if(!c->ev) { 1705b7579f77SDag-Erling Smørgrav free(c); 1706b7579f77SDag-Erling Smørgrav return NULL; 1707b7579f77SDag-Erling Smørgrav } 1708b7579f77SDag-Erling Smørgrav c->ev->base = base; 1709b7579f77SDag-Erling Smørgrav c->fd = fd; 1710b7579f77SDag-Erling Smørgrav c->buffer = buffer; 1711b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1712b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1713b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1714b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1715b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 171609a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1717b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1718b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1719b7579f77SDag-Erling Smørgrav c->type = comm_udp; 1720b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1721b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 172265b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 172365b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 172465b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = buffer; 172565b390aaSDag-Erling Smørgrav #endif 1726b7579f77SDag-Erling Smørgrav c->inuse = 0; 1727b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1728b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1729b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1730b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1731b5663de9SDag-Erling Smørgrav #endif 1732b7579f77SDag-Erling Smørgrav c->callback = callback; 1733b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1734e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST; 1735e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 1736e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 1737e2d15004SDag-Erling Smørgrav comm_point_udp_ancil_callback, c); 1738e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) { 1739b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event"); 1740b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1741b7579f77SDag-Erling Smørgrav return NULL; 1742b7579f77SDag-Erling Smørgrav } 1743e2d15004SDag-Erling Smørgrav if(fd!=-1 && ub_event_add(c->ev->ev, c->timeout) != 0 ) { 1744b7579f77SDag-Erling Smørgrav log_err("could not add udp event"); 1745b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1746b7579f77SDag-Erling Smørgrav return NULL; 1747b7579f77SDag-Erling Smørgrav } 1748b7579f77SDag-Erling Smørgrav return c; 1749b7579f77SDag-Erling Smørgrav } 1750b7579f77SDag-Erling Smørgrav 1751b7579f77SDag-Erling Smørgrav static struct comm_point* 1752b7579f77SDag-Erling Smørgrav comm_point_create_tcp_handler(struct comm_base *base, 1753b7579f77SDag-Erling Smørgrav struct comm_point* parent, size_t bufsize, 17543005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1755b7579f77SDag-Erling Smørgrav { 1756b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1757b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1758b7579f77SDag-Erling Smørgrav short evbits; 1759b7579f77SDag-Erling Smørgrav if(!c) 1760b7579f77SDag-Erling Smørgrav return NULL; 1761b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1762b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1763b7579f77SDag-Erling Smørgrav if(!c->ev) { 1764b7579f77SDag-Erling Smørgrav free(c); 1765b7579f77SDag-Erling Smørgrav return NULL; 1766b7579f77SDag-Erling Smørgrav } 1767b7579f77SDag-Erling Smørgrav c->ev->base = base; 1768b7579f77SDag-Erling Smørgrav c->fd = -1; 176917d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1770b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1771b7579f77SDag-Erling Smørgrav free(c->ev); 1772b7579f77SDag-Erling Smørgrav free(c); 1773b7579f77SDag-Erling Smørgrav return NULL; 1774b7579f77SDag-Erling Smørgrav } 1775b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof(struct timeval)); 1776b7579f77SDag-Erling Smørgrav if(!c->timeout) { 177717d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 1778b7579f77SDag-Erling Smørgrav free(c->ev); 1779b7579f77SDag-Erling Smørgrav free(c); 1780b7579f77SDag-Erling Smørgrav return NULL; 1781b7579f77SDag-Erling Smørgrav } 1782b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1783b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1784b7579f77SDag-Erling Smørgrav c->tcp_parent = parent; 1785b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 178609a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1787b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1788b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1789b7579f77SDag-Erling Smørgrav c->type = comm_tcp; 1790b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1791b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1792b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1; 1793b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1794b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1795b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1796b5663de9SDag-Erling Smørgrav #endif 179765b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 179865b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 1799c7f4d7adSDag-Erling Smørgrav /* We don't know just yet if this is a dnscrypt channel. Allocation 1800c7f4d7adSDag-Erling Smørgrav * will be done when handling the callback. */ 180165b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer; 180265b390aaSDag-Erling Smørgrav #endif 1803b7579f77SDag-Erling Smørgrav c->repinfo.c = c; 1804b7579f77SDag-Erling Smørgrav c->callback = callback; 1805b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1806b7579f77SDag-Erling Smørgrav /* add to parent free list */ 1807b7579f77SDag-Erling Smørgrav c->tcp_free = parent->tcp_free; 1808b7579f77SDag-Erling Smørgrav parent->tcp_free = c; 1809e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 1810e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_READ | UB_EV_TIMEOUT; 1811e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 1812e2d15004SDag-Erling Smørgrav comm_point_tcp_handle_callback, c); 1813e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) 1814b7579f77SDag-Erling Smørgrav { 1815b7579f77SDag-Erling Smørgrav log_err("could not basetset tcphdl event"); 1816b7579f77SDag-Erling Smørgrav parent->tcp_free = c->tcp_free; 1817b7579f77SDag-Erling Smørgrav free(c->ev); 1818b7579f77SDag-Erling Smørgrav free(c); 1819b7579f77SDag-Erling Smørgrav return NULL; 1820b7579f77SDag-Erling Smørgrav } 1821b7579f77SDag-Erling Smørgrav return c; 1822b7579f77SDag-Erling Smørgrav } 1823b7579f77SDag-Erling Smørgrav 1824b7579f77SDag-Erling Smørgrav struct comm_point* 1825b7579f77SDag-Erling Smørgrav comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, 18263005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1827b7579f77SDag-Erling Smørgrav { 1828b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1829b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1830b7579f77SDag-Erling Smørgrav short evbits; 1831b7579f77SDag-Erling Smørgrav int i; 1832b7579f77SDag-Erling Smørgrav /* first allocate the TCP accept listener */ 1833b7579f77SDag-Erling Smørgrav if(!c) 1834b7579f77SDag-Erling Smørgrav return NULL; 1835b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1836b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1837b7579f77SDag-Erling Smørgrav if(!c->ev) { 1838b7579f77SDag-Erling Smørgrav free(c); 1839b7579f77SDag-Erling Smørgrav return NULL; 1840b7579f77SDag-Erling Smørgrav } 1841b7579f77SDag-Erling Smørgrav c->ev->base = base; 1842b7579f77SDag-Erling Smørgrav c->fd = fd; 1843b7579f77SDag-Erling Smørgrav c->buffer = NULL; 1844b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1845b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1846b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1847b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1848b7579f77SDag-Erling Smørgrav c->max_tcp_count = num; 184909a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1850b7579f77SDag-Erling Smørgrav c->tcp_handlers = (struct comm_point**)calloc((size_t)num, 1851b7579f77SDag-Erling Smørgrav sizeof(struct comm_point*)); 1852b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers) { 1853b7579f77SDag-Erling Smørgrav free(c->ev); 1854b7579f77SDag-Erling Smørgrav free(c); 1855b7579f77SDag-Erling Smørgrav return NULL; 1856b7579f77SDag-Erling Smørgrav } 1857b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1858b7579f77SDag-Erling Smørgrav c->type = comm_tcp_accept; 1859b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1860b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1861b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1862b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1863b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1864b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1865b5663de9SDag-Erling Smørgrav #endif 186665b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 186765b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 186865b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = NULL; 186965b390aaSDag-Erling Smørgrav #endif 1870b7579f77SDag-Erling Smørgrav c->callback = NULL; 1871b7579f77SDag-Erling Smørgrav c->cb_arg = NULL; 1872e2d15004SDag-Erling Smørgrav evbits = UB_EV_READ | UB_EV_PERSIST; 1873e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 1874e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 1875e2d15004SDag-Erling Smørgrav comm_point_tcp_accept_callback, c); 1876e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) { 1877e2d15004SDag-Erling Smørgrav log_err("could not baseset tcpacc event"); 1878e2d15004SDag-Erling Smørgrav comm_point_delete(c); 1879e2d15004SDag-Erling Smørgrav return NULL; 1880e2d15004SDag-Erling Smørgrav } 1881e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) { 1882b7579f77SDag-Erling Smørgrav log_err("could not add tcpacc event"); 1883b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1884b7579f77SDag-Erling Smørgrav return NULL; 1885b7579f77SDag-Erling Smørgrav } 1886b7579f77SDag-Erling Smørgrav /* now prealloc the tcp handlers */ 1887b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) { 1888b7579f77SDag-Erling Smørgrav c->tcp_handlers[i] = comm_point_create_tcp_handler(base, 1889b7579f77SDag-Erling Smørgrav c, bufsize, callback, callback_arg); 1890b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers[i]) { 1891b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1892b7579f77SDag-Erling Smørgrav return NULL; 1893b7579f77SDag-Erling Smørgrav } 1894b7579f77SDag-Erling Smørgrav } 1895b7579f77SDag-Erling Smørgrav 1896b7579f77SDag-Erling Smørgrav return c; 1897b7579f77SDag-Erling Smørgrav } 1898b7579f77SDag-Erling Smørgrav 1899b7579f77SDag-Erling Smørgrav struct comm_point* 1900b7579f77SDag-Erling Smørgrav comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, 19013005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1902b7579f77SDag-Erling Smørgrav { 1903b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1904b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1905b7579f77SDag-Erling Smørgrav short evbits; 1906b7579f77SDag-Erling Smørgrav if(!c) 1907b7579f77SDag-Erling Smørgrav return NULL; 1908b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1909b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1910b7579f77SDag-Erling Smørgrav if(!c->ev) { 1911b7579f77SDag-Erling Smørgrav free(c); 1912b7579f77SDag-Erling Smørgrav return NULL; 1913b7579f77SDag-Erling Smørgrav } 1914b7579f77SDag-Erling Smørgrav c->ev->base = base; 1915b7579f77SDag-Erling Smørgrav c->fd = -1; 191617d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1917b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1918b7579f77SDag-Erling Smørgrav free(c->ev); 1919b7579f77SDag-Erling Smørgrav free(c); 1920b7579f77SDag-Erling Smørgrav return NULL; 1921b7579f77SDag-Erling Smørgrav } 1922b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1923b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1924b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1925b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1926b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 192709a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1928b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1929b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1930b7579f77SDag-Erling Smørgrav c->type = comm_tcp; 1931b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1932b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1933b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1; 1934b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 1; 1935b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1936b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 1; 1937b5663de9SDag-Erling Smørgrav #endif 193865b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 193965b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 194065b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer; 194165b390aaSDag-Erling Smørgrav #endif 1942b7579f77SDag-Erling Smørgrav c->repinfo.c = c; 1943b7579f77SDag-Erling Smørgrav c->callback = callback; 1944b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1945e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_WRITE; 1946e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 1947e2d15004SDag-Erling Smørgrav comm_point_tcp_handle_callback, c); 1948e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) 1949b7579f77SDag-Erling Smørgrav { 1950e2d15004SDag-Erling Smørgrav log_err("could not baseset tcpout event"); 195117d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 1952b7579f77SDag-Erling Smørgrav free(c->ev); 1953b7579f77SDag-Erling Smørgrav free(c); 1954b7579f77SDag-Erling Smørgrav return NULL; 1955b7579f77SDag-Erling Smørgrav } 1956b7579f77SDag-Erling Smørgrav 1957b7579f77SDag-Erling Smørgrav return c; 1958b7579f77SDag-Erling Smørgrav } 1959b7579f77SDag-Erling Smørgrav 1960b7579f77SDag-Erling Smørgrav struct comm_point* 1961b7579f77SDag-Erling Smørgrav comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, 19623005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 1963b7579f77SDag-Erling Smørgrav { 1964b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1965b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1966b7579f77SDag-Erling Smørgrav short evbits; 1967b7579f77SDag-Erling Smørgrav if(!c) 1968b7579f77SDag-Erling Smørgrav return NULL; 1969b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1970b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1971b7579f77SDag-Erling Smørgrav if(!c->ev) { 1972b7579f77SDag-Erling Smørgrav free(c); 1973b7579f77SDag-Erling Smørgrav return NULL; 1974b7579f77SDag-Erling Smørgrav } 1975b7579f77SDag-Erling Smørgrav c->ev->base = base; 1976b7579f77SDag-Erling Smørgrav c->fd = fd; 197717d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1978b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1979b7579f77SDag-Erling Smørgrav free(c->ev); 1980b7579f77SDag-Erling Smørgrav free(c); 1981b7579f77SDag-Erling Smørgrav return NULL; 1982b7579f77SDag-Erling Smørgrav } 1983b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1984b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 1985b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1986b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1987b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 198809a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1989b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1990b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1991b7579f77SDag-Erling Smørgrav c->type = comm_local; 1992b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1993b7579f77SDag-Erling Smørgrav c->do_not_close = 1; 1994b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1995b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1996b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 1997b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 1998b5663de9SDag-Erling Smørgrav #endif 199965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 200065b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 200165b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer; 200265b390aaSDag-Erling Smørgrav #endif 2003b7579f77SDag-Erling Smørgrav c->callback = callback; 2004b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 2005e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 2006e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_READ; 2007e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 2008e2d15004SDag-Erling Smørgrav comm_point_local_handle_callback, c); 2009e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) { 2010e2d15004SDag-Erling Smørgrav log_err("could not baseset localhdl event"); 2011e2d15004SDag-Erling Smørgrav free(c->ev); 2012e2d15004SDag-Erling Smørgrav free(c); 2013e2d15004SDag-Erling Smørgrav return NULL; 2014e2d15004SDag-Erling Smørgrav } 2015e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) { 2016b7579f77SDag-Erling Smørgrav log_err("could not add localhdl event"); 2017e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev); 2018b7579f77SDag-Erling Smørgrav free(c->ev); 2019b7579f77SDag-Erling Smørgrav free(c); 2020b7579f77SDag-Erling Smørgrav return NULL; 2021b7579f77SDag-Erling Smørgrav } 2022b7579f77SDag-Erling Smørgrav return c; 2023b7579f77SDag-Erling Smørgrav } 2024b7579f77SDag-Erling Smørgrav 2025b7579f77SDag-Erling Smørgrav struct comm_point* 2026b7579f77SDag-Erling Smørgrav comm_point_create_raw(struct comm_base* base, int fd, int writing, 20273005e0a3SDag-Erling Smørgrav comm_point_callback_type* callback, void* callback_arg) 2028b7579f77SDag-Erling Smørgrav { 2029b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 2030b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 2031b7579f77SDag-Erling Smørgrav short evbits; 2032b7579f77SDag-Erling Smørgrav if(!c) 2033b7579f77SDag-Erling Smørgrav return NULL; 2034b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 2035b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 2036b7579f77SDag-Erling Smørgrav if(!c->ev) { 2037b7579f77SDag-Erling Smørgrav free(c); 2038b7579f77SDag-Erling Smørgrav return NULL; 2039b7579f77SDag-Erling Smørgrav } 2040b7579f77SDag-Erling Smørgrav c->ev->base = base; 2041b7579f77SDag-Erling Smørgrav c->fd = fd; 2042b7579f77SDag-Erling Smørgrav c->buffer = NULL; 2043b7579f77SDag-Erling Smørgrav c->timeout = NULL; 2044b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 2045b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 2046b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 2047b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 204809a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 2049b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 2050b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 2051b7579f77SDag-Erling Smørgrav c->type = comm_raw; 2052b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 2053b7579f77SDag-Erling Smørgrav c->do_not_close = 1; 2054b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 2055b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 2056b5663de9SDag-Erling Smørgrav #ifdef USE_MSG_FASTOPEN 2057b5663de9SDag-Erling Smørgrav c->tcp_do_fastopen = 0; 2058b5663de9SDag-Erling Smørgrav #endif 205965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 206065b390aaSDag-Erling Smørgrav c->dnscrypt = 0; 206165b390aaSDag-Erling Smørgrav c->dnscrypt_buffer = c->buffer; 206265b390aaSDag-Erling Smørgrav #endif 2063b7579f77SDag-Erling Smørgrav c->callback = callback; 2064b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 2065e2d15004SDag-Erling Smørgrav /* ub_event stuff */ 2066b7579f77SDag-Erling Smørgrav if(writing) 2067e2d15004SDag-Erling Smørgrav evbits = UB_EV_PERSIST | UB_EV_WRITE; 2068e2d15004SDag-Erling Smørgrav else evbits = UB_EV_PERSIST | UB_EV_READ; 2069e2d15004SDag-Erling Smørgrav c->ev->ev = ub_event_new(base->eb->base, c->fd, evbits, 2070e2d15004SDag-Erling Smørgrav comm_point_raw_handle_callback, c); 2071e2d15004SDag-Erling Smørgrav if(c->ev->ev == NULL) { 2072e2d15004SDag-Erling Smørgrav log_err("could not baseset rawhdl event"); 2073e2d15004SDag-Erling Smørgrav free(c->ev); 2074e2d15004SDag-Erling Smørgrav free(c); 2075e2d15004SDag-Erling Smørgrav return NULL; 2076e2d15004SDag-Erling Smørgrav } 2077e2d15004SDag-Erling Smørgrav if (ub_event_add(c->ev->ev, c->timeout) != 0) { 2078b7579f77SDag-Erling Smørgrav log_err("could not add rawhdl event"); 2079e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev); 2080b7579f77SDag-Erling Smørgrav free(c->ev); 2081b7579f77SDag-Erling Smørgrav free(c); 2082b7579f77SDag-Erling Smørgrav return NULL; 2083b7579f77SDag-Erling Smørgrav } 2084b7579f77SDag-Erling Smørgrav return c; 2085b7579f77SDag-Erling Smørgrav } 2086b7579f77SDag-Erling Smørgrav 2087b7579f77SDag-Erling Smørgrav void 2088b7579f77SDag-Erling Smørgrav comm_point_close(struct comm_point* c) 2089b7579f77SDag-Erling Smørgrav { 2090b7579f77SDag-Erling Smørgrav if(!c) 2091b7579f77SDag-Erling Smørgrav return; 2092b7579f77SDag-Erling Smørgrav if(c->fd != -1) 2093e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) { 2094b7579f77SDag-Erling Smørgrav log_err("could not event_del on close"); 2095b7579f77SDag-Erling Smørgrav } 2096b7579f77SDag-Erling Smørgrav /* close fd after removing from event lists, or epoll.. is messed up */ 2097b7579f77SDag-Erling Smørgrav if(c->fd != -1 && !c->do_not_close) { 2098b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "close fd %d", c->fd); 2099b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 2100b7579f77SDag-Erling Smørgrav close(c->fd); 2101b7579f77SDag-Erling Smørgrav #else 2102b7579f77SDag-Erling Smørgrav closesocket(c->fd); 2103b7579f77SDag-Erling Smørgrav #endif 2104b7579f77SDag-Erling Smørgrav } 2105b7579f77SDag-Erling Smørgrav c->fd = -1; 2106b7579f77SDag-Erling Smørgrav } 2107b7579f77SDag-Erling Smørgrav 2108b7579f77SDag-Erling Smørgrav void 2109b7579f77SDag-Erling Smørgrav comm_point_delete(struct comm_point* c) 2110b7579f77SDag-Erling Smørgrav { 2111b7579f77SDag-Erling Smørgrav if(!c) 2112b7579f77SDag-Erling Smørgrav return; 2113b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp && c->ssl) { 21148ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 2115b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl); 2116b7579f77SDag-Erling Smørgrav SSL_free(c->ssl); 21178ed2b524SDag-Erling Smørgrav #endif 2118b7579f77SDag-Erling Smørgrav } 2119b7579f77SDag-Erling Smørgrav comm_point_close(c); 2120b7579f77SDag-Erling Smørgrav if(c->tcp_handlers) { 2121b7579f77SDag-Erling Smørgrav int i; 2122b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++) 2123b7579f77SDag-Erling Smørgrav comm_point_delete(c->tcp_handlers[i]); 2124b7579f77SDag-Erling Smørgrav free(c->tcp_handlers); 2125b7579f77SDag-Erling Smørgrav } 2126b7579f77SDag-Erling Smørgrav free(c->timeout); 212765b390aaSDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local) { 212817d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 212965b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 213065b390aaSDag-Erling Smørgrav if(c->dnscrypt && c->dnscrypt_buffer != c->buffer) { 213165b390aaSDag-Erling Smørgrav sldns_buffer_free(c->dnscrypt_buffer); 213265b390aaSDag-Erling Smørgrav } 213365b390aaSDag-Erling Smørgrav #endif 213465b390aaSDag-Erling Smørgrav } 2135e2d15004SDag-Erling Smørgrav ub_event_free(c->ev->ev); 2136b7579f77SDag-Erling Smørgrav free(c->ev); 2137b7579f77SDag-Erling Smørgrav free(c); 2138b7579f77SDag-Erling Smørgrav } 2139b7579f77SDag-Erling Smørgrav 2140b7579f77SDag-Erling Smørgrav void 2141b7579f77SDag-Erling Smørgrav comm_point_send_reply(struct comm_reply *repinfo) 2142b7579f77SDag-Erling Smørgrav { 214365b390aaSDag-Erling Smørgrav struct sldns_buffer* buffer; 2144b7579f77SDag-Erling Smørgrav log_assert(repinfo && repinfo->c); 214565b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 214665b390aaSDag-Erling Smørgrav buffer = repinfo->c->dnscrypt_buffer; 214765b390aaSDag-Erling Smørgrav if(!dnsc_handle_uncurved_request(repinfo)) { 214865b390aaSDag-Erling Smørgrav return; 214965b390aaSDag-Erling Smørgrav } 215065b390aaSDag-Erling Smørgrav #else 215165b390aaSDag-Erling Smørgrav buffer = repinfo->c->buffer; 215265b390aaSDag-Erling Smørgrav #endif 2153b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp) { 2154b7579f77SDag-Erling Smørgrav if(repinfo->srctype) 2155b7579f77SDag-Erling Smørgrav comm_point_send_udp_msg_if(repinfo->c, 215665b390aaSDag-Erling Smørgrav buffer, (struct sockaddr*)&repinfo->addr, 2157b7579f77SDag-Erling Smørgrav repinfo->addrlen, repinfo); 2158b7579f77SDag-Erling Smørgrav else 215965b390aaSDag-Erling Smørgrav comm_point_send_udp_msg(repinfo->c, buffer, 2160b7579f77SDag-Erling Smørgrav (struct sockaddr*)&repinfo->addr, repinfo->addrlen); 2161ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2162ff825849SDag-Erling Smørgrav if(repinfo->c->dtenv != NULL && 2163ff825849SDag-Erling Smørgrav repinfo->c->dtenv->log_client_response_messages) 2164ff825849SDag-Erling Smørgrav dt_msg_send_client_response(repinfo->c->dtenv, 2165ff825849SDag-Erling Smørgrav &repinfo->addr, repinfo->c->type, repinfo->c->buffer); 2166ff825849SDag-Erling Smørgrav #endif 2167b7579f77SDag-Erling Smørgrav } else { 2168ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2169ff825849SDag-Erling Smørgrav if(repinfo->c->tcp_parent->dtenv != NULL && 2170ff825849SDag-Erling Smørgrav repinfo->c->tcp_parent->dtenv->log_client_response_messages) 2171ff825849SDag-Erling Smørgrav dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, 2172ff825849SDag-Erling Smørgrav &repinfo->addr, repinfo->c->type, repinfo->c->buffer); 2173ff825849SDag-Erling Smørgrav #endif 2174b5663de9SDag-Erling Smørgrav comm_point_start_listening(repinfo->c, -1, 2175b5663de9SDag-Erling Smørgrav repinfo->c->tcp_timeout_msec); 2176b7579f77SDag-Erling Smørgrav } 2177b7579f77SDag-Erling Smørgrav } 2178b7579f77SDag-Erling Smørgrav 2179b7579f77SDag-Erling Smørgrav void 2180b7579f77SDag-Erling Smørgrav comm_point_drop_reply(struct comm_reply* repinfo) 2181b7579f77SDag-Erling Smørgrav { 2182b7579f77SDag-Erling Smørgrav if(!repinfo) 2183b7579f77SDag-Erling Smørgrav return; 2184b7579f77SDag-Erling Smørgrav log_assert(repinfo && repinfo->c); 2185b7579f77SDag-Erling Smørgrav log_assert(repinfo->c->type != comm_tcp_accept); 2186b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp) 2187b7579f77SDag-Erling Smørgrav return; 2188b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(repinfo->c); 2189b7579f77SDag-Erling Smørgrav } 2190b7579f77SDag-Erling Smørgrav 2191b7579f77SDag-Erling Smørgrav void 2192b7579f77SDag-Erling Smørgrav comm_point_stop_listening(struct comm_point* c) 2193b7579f77SDag-Erling Smørgrav { 2194b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point stop listening %d", c->fd); 2195e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) { 2196b7579f77SDag-Erling Smørgrav log_err("event_del error to stoplisten"); 2197b7579f77SDag-Erling Smørgrav } 2198b7579f77SDag-Erling Smørgrav } 2199b7579f77SDag-Erling Smørgrav 2200b7579f77SDag-Erling Smørgrav void 2201b5663de9SDag-Erling Smørgrav comm_point_start_listening(struct comm_point* c, int newfd, int msec) 2202b7579f77SDag-Erling Smørgrav { 2203b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point start listening %d", 2204b7579f77SDag-Erling Smørgrav c->fd==-1?newfd:c->fd); 2205b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept && !c->tcp_free) { 2206b7579f77SDag-Erling Smørgrav /* no use to start listening no free slots. */ 2207b7579f77SDag-Erling Smørgrav return; 2208b7579f77SDag-Erling Smørgrav } 2209b5663de9SDag-Erling Smørgrav if(msec != -1 && msec != 0) { 2210b7579f77SDag-Erling Smørgrav if(!c->timeout) { 2211b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof( 2212b7579f77SDag-Erling Smørgrav struct timeval)); 2213b7579f77SDag-Erling Smørgrav if(!c->timeout) { 2214b7579f77SDag-Erling Smørgrav log_err("cpsl: malloc failed. No net read."); 2215b7579f77SDag-Erling Smørgrav return; 2216b7579f77SDag-Erling Smørgrav } 2217b7579f77SDag-Erling Smørgrav } 2218e2d15004SDag-Erling Smørgrav ub_event_add_bits(c->ev->ev, UB_EV_TIMEOUT); 2219b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S /* splint fails on struct timeval. */ 2220b5663de9SDag-Erling Smørgrav c->timeout->tv_sec = msec/1000; 2221b5663de9SDag-Erling Smørgrav c->timeout->tv_usec = (msec%1000)*1000; 2222b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 2223b7579f77SDag-Erling Smørgrav } 2224b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp) { 2225e2d15004SDag-Erling Smørgrav ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE); 2226b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) 2227e2d15004SDag-Erling Smørgrav ub_event_add_bits(c->ev->ev, UB_EV_READ); 2228e2d15004SDag-Erling Smørgrav else ub_event_add_bits(c->ev->ev, UB_EV_WRITE); 2229b7579f77SDag-Erling Smørgrav } 2230b7579f77SDag-Erling Smørgrav if(newfd != -1) { 2231b7579f77SDag-Erling Smørgrav if(c->fd != -1) { 2232b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 2233b7579f77SDag-Erling Smørgrav close(c->fd); 2234b7579f77SDag-Erling Smørgrav #else 2235b7579f77SDag-Erling Smørgrav closesocket(c->fd); 2236b7579f77SDag-Erling Smørgrav #endif 2237b7579f77SDag-Erling Smørgrav } 2238b7579f77SDag-Erling Smørgrav c->fd = newfd; 2239e2d15004SDag-Erling Smørgrav ub_event_set_fd(c->ev->ev, c->fd); 2240b7579f77SDag-Erling Smørgrav } 2241b5663de9SDag-Erling Smørgrav if(ub_event_add(c->ev->ev, msec==0?NULL:c->timeout) != 0) { 2242b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cpsl."); 2243b7579f77SDag-Erling Smørgrav } 2244b7579f77SDag-Erling Smørgrav } 2245b7579f77SDag-Erling Smørgrav 2246b7579f77SDag-Erling Smørgrav void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr) 2247b7579f77SDag-Erling Smørgrav { 2248b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr); 2249e2d15004SDag-Erling Smørgrav if(ub_event_del(c->ev->ev) != 0) { 2250b7579f77SDag-Erling Smørgrav log_err("event_del error to cplf"); 2251b7579f77SDag-Erling Smørgrav } 2252e2d15004SDag-Erling Smørgrav ub_event_del_bits(c->ev->ev, UB_EV_READ|UB_EV_WRITE); 2253e2d15004SDag-Erling Smørgrav if(rd) ub_event_add_bits(c->ev->ev, UB_EV_READ); 2254e2d15004SDag-Erling Smørgrav if(wr) ub_event_add_bits(c->ev->ev, UB_EV_WRITE); 2255e2d15004SDag-Erling Smørgrav if(ub_event_add(c->ev->ev, c->timeout) != 0) { 2256b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cplf."); 2257b7579f77SDag-Erling Smørgrav } 2258b7579f77SDag-Erling Smørgrav } 2259b7579f77SDag-Erling Smørgrav 2260b7579f77SDag-Erling Smørgrav size_t comm_point_get_mem(struct comm_point* c) 2261b7579f77SDag-Erling Smørgrav { 2262b7579f77SDag-Erling Smørgrav size_t s; 2263b7579f77SDag-Erling Smørgrav if(!c) 2264b7579f77SDag-Erling Smørgrav return 0; 2265b7579f77SDag-Erling Smørgrav s = sizeof(*c) + sizeof(*c->ev); 2266b7579f77SDag-Erling Smørgrav if(c->timeout) 2267b7579f77SDag-Erling Smørgrav s += sizeof(*c->timeout); 226865b390aaSDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local) { 226917d15b25SDag-Erling Smørgrav s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer); 227065b390aaSDag-Erling Smørgrav #ifdef USE_DNSCRYPT 227165b390aaSDag-Erling Smørgrav s += sizeof(*c->dnscrypt_buffer); 227265b390aaSDag-Erling Smørgrav if(c->buffer != c->dnscrypt_buffer) { 227365b390aaSDag-Erling Smørgrav s += sldns_buffer_capacity(c->dnscrypt_buffer); 227465b390aaSDag-Erling Smørgrav } 227565b390aaSDag-Erling Smørgrav #endif 227665b390aaSDag-Erling Smørgrav } 2277b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept) { 2278b7579f77SDag-Erling Smørgrav int i; 2279b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++) 2280b7579f77SDag-Erling Smørgrav s += comm_point_get_mem(c->tcp_handlers[i]); 2281b7579f77SDag-Erling Smørgrav } 2282b7579f77SDag-Erling Smørgrav return s; 2283b7579f77SDag-Erling Smørgrav } 2284b7579f77SDag-Erling Smørgrav 2285b7579f77SDag-Erling Smørgrav struct comm_timer* 2286b7579f77SDag-Erling Smørgrav comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg) 2287b7579f77SDag-Erling Smørgrav { 2288e2d15004SDag-Erling Smørgrav struct internal_timer *tm = (struct internal_timer*)calloc(1, 2289b7579f77SDag-Erling Smørgrav sizeof(struct internal_timer)); 2290e2d15004SDag-Erling Smørgrav if(!tm) { 2291b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2292b7579f77SDag-Erling Smørgrav return NULL; 2293b7579f77SDag-Erling Smørgrav } 2294e2d15004SDag-Erling Smørgrav tm->super.ev_timer = tm; 2295e2d15004SDag-Erling Smørgrav tm->base = base; 2296e2d15004SDag-Erling Smørgrav tm->super.callback = cb; 2297e2d15004SDag-Erling Smørgrav tm->super.cb_arg = cb_arg; 2298e2d15004SDag-Erling Smørgrav tm->ev = ub_event_new(base->eb->base, -1, UB_EV_TIMEOUT, 2299e2d15004SDag-Erling Smørgrav comm_timer_callback, &tm->super); 2300e2d15004SDag-Erling Smørgrav if(tm->ev == NULL) { 2301b7579f77SDag-Erling Smørgrav log_err("timer_create: event_base_set failed."); 2302b7579f77SDag-Erling Smørgrav free(tm); 2303b7579f77SDag-Erling Smørgrav return NULL; 2304b7579f77SDag-Erling Smørgrav } 2305e2d15004SDag-Erling Smørgrav return &tm->super; 2306b7579f77SDag-Erling Smørgrav } 2307b7579f77SDag-Erling Smørgrav 2308b7579f77SDag-Erling Smørgrav void 2309b7579f77SDag-Erling Smørgrav comm_timer_disable(struct comm_timer* timer) 2310b7579f77SDag-Erling Smørgrav { 2311b7579f77SDag-Erling Smørgrav if(!timer) 2312b7579f77SDag-Erling Smørgrav return; 2313e2d15004SDag-Erling Smørgrav ub_timer_del(timer->ev_timer->ev); 2314b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 0; 2315b7579f77SDag-Erling Smørgrav } 2316b7579f77SDag-Erling Smørgrav 2317b7579f77SDag-Erling Smørgrav void 2318b7579f77SDag-Erling Smørgrav comm_timer_set(struct comm_timer* timer, struct timeval* tv) 2319b7579f77SDag-Erling Smørgrav { 2320b7579f77SDag-Erling Smørgrav log_assert(tv); 2321b7579f77SDag-Erling Smørgrav if(timer->ev_timer->enabled) 2322b7579f77SDag-Erling Smørgrav comm_timer_disable(timer); 2323e2d15004SDag-Erling Smørgrav if(ub_timer_add(timer->ev_timer->ev, timer->ev_timer->base->eb->base, 2324e2d15004SDag-Erling Smørgrav comm_timer_callback, timer, tv) != 0) 2325b7579f77SDag-Erling Smørgrav log_err("comm_timer_set: evtimer_add failed."); 2326b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 1; 2327b7579f77SDag-Erling Smørgrav } 2328b7579f77SDag-Erling Smørgrav 2329b7579f77SDag-Erling Smørgrav void 2330b7579f77SDag-Erling Smørgrav comm_timer_delete(struct comm_timer* timer) 2331b7579f77SDag-Erling Smørgrav { 2332b7579f77SDag-Erling Smørgrav if(!timer) 2333b7579f77SDag-Erling Smørgrav return; 2334b7579f77SDag-Erling Smørgrav comm_timer_disable(timer); 2335e2d15004SDag-Erling Smørgrav /* Free the sub struct timer->ev_timer derived from the super struct timer. 2336e2d15004SDag-Erling Smørgrav * i.e. assert(timer == timer->ev_timer) 2337e2d15004SDag-Erling Smørgrav */ 2338e2d15004SDag-Erling Smørgrav ub_event_free(timer->ev_timer->ev); 2339b7579f77SDag-Erling Smørgrav free(timer->ev_timer); 2340b7579f77SDag-Erling Smørgrav } 2341b7579f77SDag-Erling Smørgrav 2342b7579f77SDag-Erling Smørgrav void 2343b7579f77SDag-Erling Smørgrav comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg) 2344b7579f77SDag-Erling Smørgrav { 2345b7579f77SDag-Erling Smørgrav struct comm_timer* tm = (struct comm_timer*)arg; 2346e2d15004SDag-Erling Smørgrav if(!(event&UB_EV_TIMEOUT)) 2347b7579f77SDag-Erling Smørgrav return; 2348e2d15004SDag-Erling Smørgrav ub_comm_base_now(tm->ev_timer->base); 2349b7579f77SDag-Erling Smørgrav tm->ev_timer->enabled = 0; 2350b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_timer(tm->callback)); 2351b7579f77SDag-Erling Smørgrav (*tm->callback)(tm->cb_arg); 2352b7579f77SDag-Erling Smørgrav } 2353b7579f77SDag-Erling Smørgrav 2354b7579f77SDag-Erling Smørgrav int 2355b7579f77SDag-Erling Smørgrav comm_timer_is_set(struct comm_timer* timer) 2356b7579f77SDag-Erling Smørgrav { 2357b7579f77SDag-Erling Smørgrav return (int)timer->ev_timer->enabled; 2358b7579f77SDag-Erling Smørgrav } 2359b7579f77SDag-Erling Smørgrav 2360b7579f77SDag-Erling Smørgrav size_t 2361e2d15004SDag-Erling Smørgrav comm_timer_get_mem(struct comm_timer* ATTR_UNUSED(timer)) 2362b7579f77SDag-Erling Smørgrav { 2363e2d15004SDag-Erling Smørgrav return sizeof(struct internal_timer); 2364b7579f77SDag-Erling Smørgrav } 2365b7579f77SDag-Erling Smørgrav 2366b7579f77SDag-Erling Smørgrav struct comm_signal* 2367b7579f77SDag-Erling Smørgrav comm_signal_create(struct comm_base* base, 2368b7579f77SDag-Erling Smørgrav void (*callback)(int, void*), void* cb_arg) 2369b7579f77SDag-Erling Smørgrav { 2370b7579f77SDag-Erling Smørgrav struct comm_signal* com = (struct comm_signal*)malloc( 2371b7579f77SDag-Erling Smørgrav sizeof(struct comm_signal)); 2372b7579f77SDag-Erling Smørgrav if(!com) { 2373b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2374b7579f77SDag-Erling Smørgrav return NULL; 2375b7579f77SDag-Erling Smørgrav } 2376b7579f77SDag-Erling Smørgrav com->base = base; 2377b7579f77SDag-Erling Smørgrav com->callback = callback; 2378b7579f77SDag-Erling Smørgrav com->cb_arg = cb_arg; 2379b7579f77SDag-Erling Smørgrav com->ev_signal = NULL; 2380b7579f77SDag-Erling Smørgrav return com; 2381b7579f77SDag-Erling Smørgrav } 2382b7579f77SDag-Erling Smørgrav 2383b7579f77SDag-Erling Smørgrav void 2384b7579f77SDag-Erling Smørgrav comm_signal_callback(int sig, short event, void* arg) 2385b7579f77SDag-Erling Smørgrav { 2386b7579f77SDag-Erling Smørgrav struct comm_signal* comsig = (struct comm_signal*)arg; 2387e2d15004SDag-Erling Smørgrav if(!(event & UB_EV_SIGNAL)) 2388b7579f77SDag-Erling Smørgrav return; 2389e2d15004SDag-Erling Smørgrav ub_comm_base_now(comsig->base); 2390b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_signal(comsig->callback)); 2391b7579f77SDag-Erling Smørgrav (*comsig->callback)(sig, comsig->cb_arg); 2392b7579f77SDag-Erling Smørgrav } 2393b7579f77SDag-Erling Smørgrav 2394b7579f77SDag-Erling Smørgrav int 2395b7579f77SDag-Erling Smørgrav comm_signal_bind(struct comm_signal* comsig, int sig) 2396b7579f77SDag-Erling Smørgrav { 2397b7579f77SDag-Erling Smørgrav struct internal_signal* entry = (struct internal_signal*)calloc(1, 2398b7579f77SDag-Erling Smørgrav sizeof(struct internal_signal)); 2399b7579f77SDag-Erling Smørgrav if(!entry) { 2400b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2401b7579f77SDag-Erling Smørgrav return 0; 2402b7579f77SDag-Erling Smørgrav } 2403b7579f77SDag-Erling Smørgrav log_assert(comsig); 2404b7579f77SDag-Erling Smørgrav /* add signal event */ 2405e2d15004SDag-Erling Smørgrav entry->ev = ub_signal_new(comsig->base->eb->base, sig, 2406e2d15004SDag-Erling Smørgrav comm_signal_callback, comsig); 2407e2d15004SDag-Erling Smørgrav if(entry->ev == NULL) { 2408e2d15004SDag-Erling Smørgrav log_err("Could not create signal event"); 2409b7579f77SDag-Erling Smørgrav free(entry); 2410b7579f77SDag-Erling Smørgrav return 0; 2411b7579f77SDag-Erling Smørgrav } 2412e2d15004SDag-Erling Smørgrav if(ub_signal_add(entry->ev, NULL) != 0) { 2413b7579f77SDag-Erling Smørgrav log_err("Could not add signal handler"); 2414e2d15004SDag-Erling Smørgrav ub_event_free(entry->ev); 2415b7579f77SDag-Erling Smørgrav free(entry); 2416b7579f77SDag-Erling Smørgrav return 0; 2417b7579f77SDag-Erling Smørgrav } 2418b7579f77SDag-Erling Smørgrav /* link into list */ 2419b7579f77SDag-Erling Smørgrav entry->next = comsig->ev_signal; 2420b7579f77SDag-Erling Smørgrav comsig->ev_signal = entry; 2421b7579f77SDag-Erling Smørgrav return 1; 2422b7579f77SDag-Erling Smørgrav } 2423b7579f77SDag-Erling Smørgrav 2424b7579f77SDag-Erling Smørgrav void 2425b7579f77SDag-Erling Smørgrav comm_signal_delete(struct comm_signal* comsig) 2426b7579f77SDag-Erling Smørgrav { 2427b7579f77SDag-Erling Smørgrav struct internal_signal* p, *np; 2428b7579f77SDag-Erling Smørgrav if(!comsig) 2429b7579f77SDag-Erling Smørgrav return; 2430b7579f77SDag-Erling Smørgrav p=comsig->ev_signal; 2431b7579f77SDag-Erling Smørgrav while(p) { 2432b7579f77SDag-Erling Smørgrav np = p->next; 2433e2d15004SDag-Erling Smørgrav ub_signal_del(p->ev); 2434e2d15004SDag-Erling Smørgrav ub_event_free(p->ev); 2435b7579f77SDag-Erling Smørgrav free(p); 2436b7579f77SDag-Erling Smørgrav p = np; 2437b7579f77SDag-Erling Smørgrav } 2438b7579f77SDag-Erling Smørgrav free(comsig); 2439b7579f77SDag-Erling Smørgrav } 2440