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" 43b7579f77SDag-Erling Smørgrav #include "util/log.h" 44b7579f77SDag-Erling Smørgrav #include "util/net_help.h" 45b7579f77SDag-Erling Smørgrav #include "util/fptr_wlist.h" 4609a3aaf3SDag-Erling Smørgrav #include "sldns/pkthdr.h" 4709a3aaf3SDag-Erling Smørgrav #include "sldns/sbuffer.h" 48ff825849SDag-Erling Smørgrav #include "dnstap/dnstap.h" 498ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_SSL_H 50b7579f77SDag-Erling Smørgrav #include <openssl/ssl.h> 518ed2b524SDag-Erling Smørgrav #endif 528ed2b524SDag-Erling Smørgrav #ifdef HAVE_OPENSSL_ERR_H 53b7579f77SDag-Erling Smørgrav #include <openssl/err.h> 548ed2b524SDag-Erling Smørgrav #endif 55b7579f77SDag-Erling Smørgrav 56b7579f77SDag-Erling Smørgrav /* -------- Start of local definitions -------- */ 57b7579f77SDag-Erling Smørgrav /** if CMSG_ALIGN is not defined on this platform, a workaround */ 58b7579f77SDag-Erling Smørgrav #ifndef CMSG_ALIGN 59*f61ef7f6SDag-Erling Smørgrav # ifdef __CMSG_ALIGN 60*f61ef7f6SDag-Erling Smørgrav # define CMSG_ALIGN(n) __CMSG_ALIGN(n) 61*f61ef7f6SDag-Erling Smørgrav # elif defined(CMSG_DATA_ALIGN) 62b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN _CMSG_DATA_ALIGN 63b7579f77SDag-Erling Smørgrav # else 64b7579f77SDag-Erling Smørgrav # define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1)) 65b7579f77SDag-Erling Smørgrav # endif 66b7579f77SDag-Erling Smørgrav #endif 67b7579f77SDag-Erling Smørgrav 68b7579f77SDag-Erling Smørgrav /** if CMSG_LEN is not defined on this platform, a workaround */ 69b7579f77SDag-Erling Smørgrav #ifndef CMSG_LEN 70b7579f77SDag-Erling Smørgrav # define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len)) 71b7579f77SDag-Erling Smørgrav #endif 72b7579f77SDag-Erling Smørgrav 73b7579f77SDag-Erling Smørgrav /** if CMSG_SPACE is not defined on this platform, a workaround */ 74b7579f77SDag-Erling Smørgrav #ifndef CMSG_SPACE 75b7579f77SDag-Erling Smørgrav # ifdef _CMSG_HDR_ALIGN 76b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr))) 77b7579f77SDag-Erling Smørgrav # else 78b7579f77SDag-Erling Smørgrav # define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr))) 79b7579f77SDag-Erling Smørgrav # endif 80b7579f77SDag-Erling Smørgrav #endif 81b7579f77SDag-Erling Smørgrav 82b7579f77SDag-Erling Smørgrav /** The TCP reading or writing query timeout in seconds */ 83b7579f77SDag-Erling Smørgrav #define TCP_QUERY_TIMEOUT 120 84b7579f77SDag-Erling Smørgrav 85b7579f77SDag-Erling Smørgrav #ifndef NONBLOCKING_IS_BROKEN 86b7579f77SDag-Erling Smørgrav /** number of UDP reads to perform per read indication from select */ 87b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 100 88b7579f77SDag-Erling Smørgrav #else 89b7579f77SDag-Erling Smørgrav #define NUM_UDP_PER_SELECT 1 90b7579f77SDag-Erling Smørgrav #endif 91b7579f77SDag-Erling Smørgrav 92b7579f77SDag-Erling Smørgrav /* We define libevent structures here to hide the libevent stuff. */ 93b7579f77SDag-Erling Smørgrav 94b7579f77SDag-Erling Smørgrav #ifdef USE_MINI_EVENT 95b7579f77SDag-Erling Smørgrav # ifdef USE_WINSOCK 96b7579f77SDag-Erling Smørgrav # include "util/winsock_event.h" 97b7579f77SDag-Erling Smørgrav # else 98b7579f77SDag-Erling Smørgrav # include "util/mini_event.h" 99b7579f77SDag-Erling Smørgrav # endif /* USE_WINSOCK */ 100b7579f77SDag-Erling Smørgrav #else /* USE_MINI_EVENT */ 101b7579f77SDag-Erling Smørgrav /* we use libevent */ 1028ed2b524SDag-Erling Smørgrav # ifdef HAVE_EVENT_H 103b7579f77SDag-Erling Smørgrav # include <event.h> 1048ed2b524SDag-Erling Smørgrav # else 1058ed2b524SDag-Erling Smørgrav # include "event2/event.h" 1068ed2b524SDag-Erling Smørgrav # include "event2/event_struct.h" 1078ed2b524SDag-Erling Smørgrav # include "event2/event_compat.h" 1088ed2b524SDag-Erling Smørgrav # endif 109b7579f77SDag-Erling Smørgrav #endif /* USE_MINI_EVENT */ 110b7579f77SDag-Erling Smørgrav 111b7579f77SDag-Erling Smørgrav /** 112b7579f77SDag-Erling Smørgrav * The internal event structure for keeping libevent info for the event. 113b7579f77SDag-Erling Smørgrav * Possibly other structures (list, tree) this is part of. 114b7579f77SDag-Erling Smørgrav */ 115b7579f77SDag-Erling Smørgrav struct internal_event { 116b7579f77SDag-Erling Smørgrav /** the comm base */ 117b7579f77SDag-Erling Smørgrav struct comm_base* base; 118b7579f77SDag-Erling Smørgrav /** libevent event type, alloced here */ 119b7579f77SDag-Erling Smørgrav struct event ev; 120b7579f77SDag-Erling Smørgrav }; 121b7579f77SDag-Erling Smørgrav 122b7579f77SDag-Erling Smørgrav /** 123b7579f77SDag-Erling Smørgrav * Internal base structure, so that every thread has its own events. 124b7579f77SDag-Erling Smørgrav */ 125b7579f77SDag-Erling Smørgrav struct internal_base { 126b7579f77SDag-Erling Smørgrav /** libevent event_base type. */ 127b7579f77SDag-Erling Smørgrav struct event_base* base; 128b7579f77SDag-Erling Smørgrav /** seconds time pointer points here */ 12917d15b25SDag-Erling Smørgrav time_t secs; 130b7579f77SDag-Erling Smørgrav /** timeval with current time */ 131b7579f77SDag-Erling Smørgrav struct timeval now; 132b7579f77SDag-Erling Smørgrav /** the event used for slow_accept timeouts */ 133b7579f77SDag-Erling Smørgrav struct event slow_accept; 134b7579f77SDag-Erling Smørgrav /** true if slow_accept is enabled */ 135b7579f77SDag-Erling Smørgrav int slow_accept_enabled; 136b7579f77SDag-Erling Smørgrav }; 137b7579f77SDag-Erling Smørgrav 138b7579f77SDag-Erling Smørgrav /** 139b7579f77SDag-Erling Smørgrav * Internal timer structure, to store timer event in. 140b7579f77SDag-Erling Smørgrav */ 141b7579f77SDag-Erling Smørgrav struct internal_timer { 142b7579f77SDag-Erling Smørgrav /** the comm base */ 143b7579f77SDag-Erling Smørgrav struct comm_base* base; 144b7579f77SDag-Erling Smørgrav /** libevent event type, alloced here */ 145b7579f77SDag-Erling Smørgrav struct event ev; 146b7579f77SDag-Erling Smørgrav /** is timer enabled */ 147b7579f77SDag-Erling Smørgrav uint8_t enabled; 148b7579f77SDag-Erling Smørgrav }; 149b7579f77SDag-Erling Smørgrav 150b7579f77SDag-Erling Smørgrav /** 151b7579f77SDag-Erling Smørgrav * Internal signal structure, to store signal event in. 152b7579f77SDag-Erling Smørgrav */ 153b7579f77SDag-Erling Smørgrav struct internal_signal { 154b7579f77SDag-Erling Smørgrav /** libevent event type, alloced here */ 155b7579f77SDag-Erling Smørgrav struct event ev; 156b7579f77SDag-Erling Smørgrav /** next in signal list */ 157b7579f77SDag-Erling Smørgrav struct internal_signal* next; 158b7579f77SDag-Erling Smørgrav }; 159b7579f77SDag-Erling Smørgrav 160b7579f77SDag-Erling Smørgrav /** create a tcp handler with a parent */ 161b7579f77SDag-Erling Smørgrav static struct comm_point* comm_point_create_tcp_handler( 162b7579f77SDag-Erling Smørgrav struct comm_base *base, struct comm_point* parent, size_t bufsize, 163b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg); 164b7579f77SDag-Erling Smørgrav 165b7579f77SDag-Erling Smørgrav /* -------- End of local definitions -------- */ 166b7579f77SDag-Erling Smørgrav 167b7579f77SDag-Erling Smørgrav #ifdef USE_MINI_EVENT 168b7579f77SDag-Erling Smørgrav /** minievent updates the time when it blocks. */ 169b7579f77SDag-Erling Smørgrav #define comm_base_now(x) /* nothing to do */ 170b7579f77SDag-Erling Smørgrav #else /* !USE_MINI_EVENT */ 171b7579f77SDag-Erling Smørgrav /** fillup the time values in the event base */ 172b7579f77SDag-Erling Smørgrav static void 173b7579f77SDag-Erling Smørgrav comm_base_now(struct comm_base* b) 174b7579f77SDag-Erling Smørgrav { 175b7579f77SDag-Erling Smørgrav if(gettimeofday(&b->eb->now, NULL) < 0) { 176b7579f77SDag-Erling Smørgrav log_err("gettimeofday: %s", strerror(errno)); 177b7579f77SDag-Erling Smørgrav } 17817d15b25SDag-Erling Smørgrav b->eb->secs = (time_t)b->eb->now.tv_sec; 179b7579f77SDag-Erling Smørgrav } 180b7579f77SDag-Erling Smørgrav #endif /* USE_MINI_EVENT */ 181b7579f77SDag-Erling Smørgrav 182b7579f77SDag-Erling Smørgrav struct comm_base* 183b7579f77SDag-Erling Smørgrav comm_base_create(int sigs) 184b7579f77SDag-Erling Smørgrav { 185b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1, 186b7579f77SDag-Erling Smørgrav sizeof(struct comm_base)); 187b7579f77SDag-Erling Smørgrav if(!b) 188b7579f77SDag-Erling Smørgrav return NULL; 189b7579f77SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 190b7579f77SDag-Erling Smørgrav if(!b->eb) { 191b7579f77SDag-Erling Smørgrav free(b); 192b7579f77SDag-Erling Smørgrav return NULL; 193b7579f77SDag-Erling Smørgrav } 194b7579f77SDag-Erling Smørgrav #ifdef USE_MINI_EVENT 195b7579f77SDag-Erling Smørgrav (void)sigs; 196b7579f77SDag-Erling Smørgrav /* use mini event time-sharing feature */ 197b7579f77SDag-Erling Smørgrav b->eb->base = event_init(&b->eb->secs, &b->eb->now); 198b7579f77SDag-Erling Smørgrav #else 199b7579f77SDag-Erling Smørgrav # if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 200b7579f77SDag-Erling Smørgrav /* libev */ 201b7579f77SDag-Erling Smørgrav if(sigs) 202b7579f77SDag-Erling Smørgrav b->eb->base=(struct event_base *)ev_default_loop(EVFLAG_AUTO); 203b7579f77SDag-Erling Smørgrav else 204b7579f77SDag-Erling Smørgrav b->eb->base=(struct event_base *)ev_loop_new(EVFLAG_AUTO); 205b7579f77SDag-Erling Smørgrav # else 206b7579f77SDag-Erling Smørgrav (void)sigs; 207b7579f77SDag-Erling Smørgrav # ifdef HAVE_EVENT_BASE_NEW 208b7579f77SDag-Erling Smørgrav b->eb->base = event_base_new(); 209b7579f77SDag-Erling Smørgrav # else 210b7579f77SDag-Erling Smørgrav b->eb->base = event_init(); 211b7579f77SDag-Erling Smørgrav # endif 212b7579f77SDag-Erling Smørgrav # endif 213b7579f77SDag-Erling Smørgrav #endif 214b7579f77SDag-Erling Smørgrav if(!b->eb->base) { 215b7579f77SDag-Erling Smørgrav free(b->eb); 216b7579f77SDag-Erling Smørgrav free(b); 217b7579f77SDag-Erling Smørgrav return NULL; 218b7579f77SDag-Erling Smørgrav } 219b7579f77SDag-Erling Smørgrav comm_base_now(b); 220b7579f77SDag-Erling Smørgrav /* avoid event_get_method call which causes crashes even when 221b7579f77SDag-Erling Smørgrav * not printing, because its result is passed */ 222b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, 223b7579f77SDag-Erling Smørgrav #if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP) 224b7579f77SDag-Erling Smørgrav "libev" 225b7579f77SDag-Erling Smørgrav #elif defined(USE_MINI_EVENT) 226b7579f77SDag-Erling Smørgrav "event " 227b7579f77SDag-Erling Smørgrav #else 228b7579f77SDag-Erling Smørgrav "libevent " 229b7579f77SDag-Erling Smørgrav #endif 230b7579f77SDag-Erling Smørgrav "%s uses %s method.", 231b7579f77SDag-Erling Smørgrav event_get_version(), 232b7579f77SDag-Erling Smørgrav #ifdef HAVE_EVENT_BASE_GET_METHOD 233b7579f77SDag-Erling Smørgrav event_base_get_method(b->eb->base) 234b7579f77SDag-Erling Smørgrav #else 235b7579f77SDag-Erling Smørgrav "not_obtainable" 236b7579f77SDag-Erling Smørgrav #endif 237b7579f77SDag-Erling Smørgrav ); 238b7579f77SDag-Erling Smørgrav return b; 239b7579f77SDag-Erling Smørgrav } 240b7579f77SDag-Erling Smørgrav 24117d15b25SDag-Erling Smørgrav struct comm_base* 24217d15b25SDag-Erling Smørgrav comm_base_create_event(struct event_base* base) 24317d15b25SDag-Erling Smørgrav { 24417d15b25SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)calloc(1, 24517d15b25SDag-Erling Smørgrav sizeof(struct comm_base)); 24617d15b25SDag-Erling Smørgrav if(!b) 24717d15b25SDag-Erling Smørgrav return NULL; 24817d15b25SDag-Erling Smørgrav b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base)); 24917d15b25SDag-Erling Smørgrav if(!b->eb) { 25017d15b25SDag-Erling Smørgrav free(b); 25117d15b25SDag-Erling Smørgrav return NULL; 25217d15b25SDag-Erling Smørgrav } 25317d15b25SDag-Erling Smørgrav b->eb->base = base; 25417d15b25SDag-Erling Smørgrav comm_base_now(b); 25517d15b25SDag-Erling Smørgrav return b; 25617d15b25SDag-Erling Smørgrav } 25717d15b25SDag-Erling Smørgrav 258b7579f77SDag-Erling Smørgrav void 259b7579f77SDag-Erling Smørgrav comm_base_delete(struct comm_base* b) 260b7579f77SDag-Erling Smørgrav { 261b7579f77SDag-Erling Smørgrav if(!b) 262b7579f77SDag-Erling Smørgrav return; 263b7579f77SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) { 264b7579f77SDag-Erling Smørgrav if(event_del(&b->eb->slow_accept) != 0) { 265b7579f77SDag-Erling Smørgrav log_err("could not event_del slow_accept"); 266b7579f77SDag-Erling Smørgrav } 267b7579f77SDag-Erling Smørgrav } 268b7579f77SDag-Erling Smørgrav #ifdef USE_MINI_EVENT 269b7579f77SDag-Erling Smørgrav event_base_free(b->eb->base); 270b7579f77SDag-Erling Smørgrav #elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE) 271b7579f77SDag-Erling Smørgrav /* only libevent 1.2+ has it, but in 1.2 it is broken - 272b7579f77SDag-Erling Smørgrav assertion fails on signal handling ev that is not deleted 273b7579f77SDag-Erling Smørgrav in libevent 1.3c (event_base_once appears) this is fixed. */ 274b7579f77SDag-Erling Smørgrav event_base_free(b->eb->base); 275b7579f77SDag-Erling Smørgrav #endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */ 276b7579f77SDag-Erling Smørgrav b->eb->base = NULL; 277b7579f77SDag-Erling Smørgrav free(b->eb); 278b7579f77SDag-Erling Smørgrav free(b); 279b7579f77SDag-Erling Smørgrav } 280b7579f77SDag-Erling Smørgrav 281b7579f77SDag-Erling Smørgrav void 28217d15b25SDag-Erling Smørgrav comm_base_delete_no_base(struct comm_base* b) 28317d15b25SDag-Erling Smørgrav { 28417d15b25SDag-Erling Smørgrav if(!b) 28517d15b25SDag-Erling Smørgrav return; 28617d15b25SDag-Erling Smørgrav if(b->eb->slow_accept_enabled) { 28717d15b25SDag-Erling Smørgrav if(event_del(&b->eb->slow_accept) != 0) { 28817d15b25SDag-Erling Smørgrav log_err("could not event_del slow_accept"); 28917d15b25SDag-Erling Smørgrav } 29017d15b25SDag-Erling Smørgrav } 29117d15b25SDag-Erling Smørgrav b->eb->base = NULL; 29217d15b25SDag-Erling Smørgrav free(b->eb); 29317d15b25SDag-Erling Smørgrav free(b); 29417d15b25SDag-Erling Smørgrav } 29517d15b25SDag-Erling Smørgrav 29617d15b25SDag-Erling Smørgrav void 29717d15b25SDag-Erling Smørgrav comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv) 298b7579f77SDag-Erling Smørgrav { 299b7579f77SDag-Erling Smørgrav *tt = &b->eb->secs; 300b7579f77SDag-Erling Smørgrav *tv = &b->eb->now; 301b7579f77SDag-Erling Smørgrav } 302b7579f77SDag-Erling Smørgrav 303b7579f77SDag-Erling Smørgrav void 304b7579f77SDag-Erling Smørgrav comm_base_dispatch(struct comm_base* b) 305b7579f77SDag-Erling Smørgrav { 306b7579f77SDag-Erling Smørgrav int retval; 307b7579f77SDag-Erling Smørgrav retval = event_base_dispatch(b->eb->base); 308b7579f77SDag-Erling Smørgrav if(retval != 0) { 309b7579f77SDag-Erling Smørgrav fatal_exit("event_dispatch returned error %d, " 310b7579f77SDag-Erling Smørgrav "errno is %s", retval, strerror(errno)); 311b7579f77SDag-Erling Smørgrav } 312b7579f77SDag-Erling Smørgrav } 313b7579f77SDag-Erling Smørgrav 314b7579f77SDag-Erling Smørgrav void comm_base_exit(struct comm_base* b) 315b7579f77SDag-Erling Smørgrav { 316b7579f77SDag-Erling Smørgrav if(event_base_loopexit(b->eb->base, NULL) != 0) { 317b7579f77SDag-Erling Smørgrav log_err("Could not loopexit"); 318b7579f77SDag-Erling Smørgrav } 319b7579f77SDag-Erling Smørgrav } 320b7579f77SDag-Erling Smørgrav 321b7579f77SDag-Erling Smørgrav void comm_base_set_slow_accept_handlers(struct comm_base* b, 322b7579f77SDag-Erling Smørgrav void (*stop_acc)(void*), void (*start_acc)(void*), void* arg) 323b7579f77SDag-Erling Smørgrav { 324b7579f77SDag-Erling Smørgrav b->stop_accept = stop_acc; 325b7579f77SDag-Erling Smørgrav b->start_accept = start_acc; 326b7579f77SDag-Erling Smørgrav b->cb_arg = arg; 327b7579f77SDag-Erling Smørgrav } 328b7579f77SDag-Erling Smørgrav 329b7579f77SDag-Erling Smørgrav struct event_base* comm_base_internal(struct comm_base* b) 330b7579f77SDag-Erling Smørgrav { 331b7579f77SDag-Erling Smørgrav return b->eb->base; 332b7579f77SDag-Erling Smørgrav } 333b7579f77SDag-Erling Smørgrav 334b7579f77SDag-Erling Smørgrav /** see if errno for udp has to be logged or not uses globals */ 335b7579f77SDag-Erling Smørgrav static int 336b7579f77SDag-Erling Smørgrav udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 337b7579f77SDag-Erling Smørgrav { 338b7579f77SDag-Erling Smørgrav /* do not log transient errors (unless high verbosity) */ 339b7579f77SDag-Erling Smørgrav #if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN) 340b7579f77SDag-Erling Smørgrav switch(errno) { 341b7579f77SDag-Erling Smørgrav # ifdef ENETUNREACH 342b7579f77SDag-Erling Smørgrav case ENETUNREACH: 343b7579f77SDag-Erling Smørgrav # endif 344b7579f77SDag-Erling Smørgrav # ifdef EHOSTDOWN 345b7579f77SDag-Erling Smørgrav case EHOSTDOWN: 346b7579f77SDag-Erling Smørgrav # endif 347b7579f77SDag-Erling Smørgrav # ifdef EHOSTUNREACH 348b7579f77SDag-Erling Smørgrav case EHOSTUNREACH: 349b7579f77SDag-Erling Smørgrav # endif 350b7579f77SDag-Erling Smørgrav # ifdef ENETDOWN 351b7579f77SDag-Erling Smørgrav case ENETDOWN: 352b7579f77SDag-Erling Smørgrav # endif 353b7579f77SDag-Erling Smørgrav if(verbosity < VERB_ALGO) 354b7579f77SDag-Erling Smørgrav return 0; 355b7579f77SDag-Erling Smørgrav default: 356b7579f77SDag-Erling Smørgrav break; 357b7579f77SDag-Erling Smørgrav } 358b7579f77SDag-Erling Smørgrav #endif 35917d15b25SDag-Erling Smørgrav /* permission denied is gotten for every send if the 36017d15b25SDag-Erling Smørgrav * network is disconnected (on some OS), squelch it */ 361*f61ef7f6SDag-Erling Smørgrav if( ((errno == EPERM) 362*f61ef7f6SDag-Erling Smørgrav # ifdef EADDRNOTAVAIL 363*f61ef7f6SDag-Erling Smørgrav /* 'Cannot assign requested address' also when disconnected */ 364*f61ef7f6SDag-Erling Smørgrav || (errno == EADDRNOTAVAIL) 365*f61ef7f6SDag-Erling Smørgrav # endif 366*f61ef7f6SDag-Erling Smørgrav ) && verbosity < VERB_DETAIL) 36717d15b25SDag-Erling Smørgrav return 0; 368b7579f77SDag-Erling Smørgrav /* squelch errors where people deploy AAAA ::ffff:bla for 369b7579f77SDag-Erling Smørgrav * authority servers, which we try for intranets. */ 370b7579f77SDag-Erling Smørgrav if(errno == EINVAL && addr_is_ip4mapped( 371b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) && 372b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL) 373b7579f77SDag-Erling Smørgrav return 0; 374b7579f77SDag-Erling Smørgrav /* SO_BROADCAST sockopt can give access to 255.255.255.255, 375b7579f77SDag-Erling Smørgrav * but a dns cache does not need it. */ 376b7579f77SDag-Erling Smørgrav if(errno == EACCES && addr_is_broadcast( 377b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen) && 378b7579f77SDag-Erling Smørgrav verbosity < VERB_DETAIL) 379b7579f77SDag-Erling Smørgrav return 0; 380b7579f77SDag-Erling Smørgrav return 1; 381b7579f77SDag-Erling Smørgrav } 382b7579f77SDag-Erling Smørgrav 383b7579f77SDag-Erling Smørgrav int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen) 384b7579f77SDag-Erling Smørgrav { 385b7579f77SDag-Erling Smørgrav return udp_send_errno_needs_log(addr, addrlen); 386b7579f77SDag-Erling Smørgrav } 387b7579f77SDag-Erling Smørgrav 388b7579f77SDag-Erling Smørgrav /* send a UDP reply */ 389b7579f77SDag-Erling Smørgrav int 39017d15b25SDag-Erling Smørgrav comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet, 391b7579f77SDag-Erling Smørgrav struct sockaddr* addr, socklen_t addrlen) 392b7579f77SDag-Erling Smørgrav { 393b7579f77SDag-Erling Smørgrav ssize_t sent; 394b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1); 395b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG 39617d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0) 397b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet"); 398b7579f77SDag-Erling Smørgrav #endif 399b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0); 40017d15b25SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet), 40117d15b25SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0, 402b7579f77SDag-Erling Smørgrav addr, addrlen); 403b7579f77SDag-Erling Smørgrav if(sent == -1) { 404*f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete, 405*f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for 406*f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */ 407*f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK 408*f61ef7f6SDag-Erling Smørgrav if(errno == EAGAIN || 409*f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK 410*f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK || 411*f61ef7f6SDag-Erling Smørgrav # endif 412*f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) { 413*f61ef7f6SDag-Erling Smørgrav #else 414*f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 415*f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS || 416*f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) { 417*f61ef7f6SDag-Erling Smørgrav #endif 418*f61ef7f6SDag-Erling Smørgrav int e; 419*f61ef7f6SDag-Erling Smørgrav fd_set_block(c->fd); 420*f61ef7f6SDag-Erling Smørgrav sent = sendto(c->fd, (void*)sldns_buffer_begin(packet), 421*f61ef7f6SDag-Erling Smørgrav sldns_buffer_remaining(packet), 0, 422*f61ef7f6SDag-Erling Smørgrav addr, addrlen); 423*f61ef7f6SDag-Erling Smørgrav e = errno; 424*f61ef7f6SDag-Erling Smørgrav fd_set_nonblock(c->fd); 425*f61ef7f6SDag-Erling Smørgrav errno = e; 426*f61ef7f6SDag-Erling Smørgrav } 427*f61ef7f6SDag-Erling Smørgrav } 428*f61ef7f6SDag-Erling Smørgrav if(sent == -1) { 429b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen)) 430b7579f77SDag-Erling Smørgrav return 0; 431b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 432b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendto failed: %s", strerror(errno)); 433b7579f77SDag-Erling Smørgrav #else 434b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendto failed: %s", 435b7579f77SDag-Erling Smørgrav wsa_strerror(WSAGetLastError())); 436b7579f77SDag-Erling Smørgrav #endif 437b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is", 438b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen); 439b7579f77SDag-Erling Smørgrav return 0; 44017d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) { 441b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes", 44217d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet)); 443b7579f77SDag-Erling Smørgrav return 0; 444b7579f77SDag-Erling Smørgrav } 445b7579f77SDag-Erling Smørgrav return 1; 446b7579f77SDag-Erling Smørgrav } 447b7579f77SDag-Erling Smørgrav 448b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG)) 449b7579f77SDag-Erling Smørgrav /** print debug ancillary info */ 450b7579f77SDag-Erling Smørgrav static void p_ancil(const char* str, struct comm_reply* r) 451b7579f77SDag-Erling Smørgrav { 452b7579f77SDag-Erling Smørgrav if(r->srctype != 4 && r->srctype != 6) { 453b7579f77SDag-Erling Smørgrav log_info("%s: unknown srctype %d", str, r->srctype); 454b7579f77SDag-Erling Smørgrav return; 455b7579f77SDag-Erling Smørgrav } 456b7579f77SDag-Erling Smørgrav if(r->srctype == 6) { 457b7579f77SDag-Erling Smørgrav char buf[1024]; 458b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr, 459b7579f77SDag-Erling Smørgrav buf, (socklen_t)sizeof(buf)) == 0) { 46017d15b25SDag-Erling Smørgrav (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf)); 461b7579f77SDag-Erling Smørgrav } 462b7579f77SDag-Erling Smørgrav buf[sizeof(buf)-1]=0; 463b7579f77SDag-Erling Smørgrav log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex); 464b7579f77SDag-Erling Smørgrav } else if(r->srctype == 4) { 465b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 466b7579f77SDag-Erling Smørgrav char buf1[1024], buf2[1024]; 467b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr, 468b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) { 46917d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 470b7579f77SDag-Erling Smørgrav } 471b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0; 472b7579f77SDag-Erling Smørgrav #ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST 473b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst, 474b7579f77SDag-Erling Smørgrav buf2, (socklen_t)sizeof(buf2)) == 0) { 47517d15b25SDag-Erling Smørgrav (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2)); 476b7579f77SDag-Erling Smørgrav } 477b7579f77SDag-Erling Smørgrav buf2[sizeof(buf2)-1]=0; 478b7579f77SDag-Erling Smørgrav #else 479b7579f77SDag-Erling Smørgrav buf2[0]=0; 480b7579f77SDag-Erling Smørgrav #endif 481b7579f77SDag-Erling Smørgrav log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex, 482b7579f77SDag-Erling Smørgrav buf1, buf2); 483b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR) 484b7579f77SDag-Erling Smørgrav char buf1[1024]; 485b7579f77SDag-Erling Smørgrav if(inet_ntop(AF_INET, &r->pktinfo.v4addr, 486b7579f77SDag-Erling Smørgrav buf1, (socklen_t)sizeof(buf1)) == 0) { 48717d15b25SDag-Erling Smørgrav (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1)); 488b7579f77SDag-Erling Smørgrav } 489b7579f77SDag-Erling Smørgrav buf1[sizeof(buf1)-1]=0; 490b7579f77SDag-Erling Smørgrav log_info("%s: %s", str, buf1); 491b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or PI_RECVDSTDADDR */ 492b7579f77SDag-Erling Smørgrav } 493b7579f77SDag-Erling Smørgrav } 494b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */ 495b7579f77SDag-Erling Smørgrav 496b7579f77SDag-Erling Smørgrav /** send a UDP reply over specified interface*/ 497b7579f77SDag-Erling Smørgrav static int 49817d15b25SDag-Erling Smørgrav comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet, 499b7579f77SDag-Erling Smørgrav struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r) 500b7579f77SDag-Erling Smørgrav { 501b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG) 502b7579f77SDag-Erling Smørgrav ssize_t sent; 503b7579f77SDag-Erling Smørgrav struct msghdr msg; 504b7579f77SDag-Erling Smørgrav struct iovec iov[1]; 505b7579f77SDag-Erling Smørgrav char control[256]; 506b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 507b7579f77SDag-Erling Smørgrav struct cmsghdr *cmsg; 508b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 509b7579f77SDag-Erling Smørgrav 510b7579f77SDag-Erling Smørgrav log_assert(c->fd != -1); 511b7579f77SDag-Erling Smørgrav #ifdef UNBOUND_DEBUG 51217d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(packet) == 0) 513b7579f77SDag-Erling Smørgrav log_err("error: send empty UDP packet"); 514b7579f77SDag-Erling Smørgrav #endif 515b7579f77SDag-Erling Smørgrav log_assert(addr && addrlen > 0); 516b7579f77SDag-Erling Smørgrav 517b7579f77SDag-Erling Smørgrav msg.msg_name = addr; 518b7579f77SDag-Erling Smørgrav msg.msg_namelen = addrlen; 51917d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(packet); 52017d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(packet); 521b7579f77SDag-Erling Smørgrav msg.msg_iov = iov; 522b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1; 523b7579f77SDag-Erling Smørgrav msg.msg_control = control; 524b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 525b7579f77SDag-Erling Smørgrav msg.msg_controllen = sizeof(control); 526b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 527b7579f77SDag-Erling Smørgrav msg.msg_flags = 0; 528b7579f77SDag-Erling Smørgrav 529b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 530b7579f77SDag-Erling Smørgrav cmsg = CMSG_FIRSTHDR(&msg); 531b7579f77SDag-Erling Smørgrav if(r->srctype == 4) { 532b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 53309a3aaf3SDag-Erling Smørgrav void* cmsg_data; 534b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo)); 535b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 536b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP; 537b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_PKTINFO; 538b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info, 539b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo)); 54009a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */ 54109a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg); 54209a3aaf3SDag-Erling Smørgrav ((struct in_pktinfo *) cmsg_data)->ipi_ifindex = 0; 543b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo)); 544b7579f77SDag-Erling Smørgrav #elif defined(IP_SENDSRCADDR) 545b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); 546b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 547b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IP; 548b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IP_SENDSRCADDR; 549b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr, 550b7579f77SDag-Erling Smørgrav sizeof(struct in_addr)); 551b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); 552b7579f77SDag-Erling Smørgrav #else 553b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR"); 554b7579f77SDag-Erling Smørgrav msg.msg_control = NULL; 555b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_SENDSRCADDR */ 556b7579f77SDag-Erling Smørgrav } else if(r->srctype == 6) { 55709a3aaf3SDag-Erling Smørgrav void* cmsg_data; 558b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 559b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 560b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6; 561b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO; 562b7579f77SDag-Erling Smørgrav memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info, 563b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo)); 56409a3aaf3SDag-Erling Smørgrav /* unset the ifindex to not bypass the routing tables */ 56509a3aaf3SDag-Erling Smørgrav cmsg_data = CMSG_DATA(cmsg); 56609a3aaf3SDag-Erling Smørgrav ((struct in6_pktinfo *) cmsg_data)->ipi6_ifindex = 0; 567b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 568b7579f77SDag-Erling Smørgrav } else { 569b7579f77SDag-Erling Smørgrav /* try to pass all 0 to use default route */ 570b7579f77SDag-Erling Smørgrav msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); 571b7579f77SDag-Erling Smørgrav log_assert(msg.msg_controllen <= sizeof(control)); 572b7579f77SDag-Erling Smørgrav cmsg->cmsg_level = IPPROTO_IPV6; 573b7579f77SDag-Erling Smørgrav cmsg->cmsg_type = IPV6_PKTINFO; 574b7579f77SDag-Erling Smørgrav memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo)); 575b7579f77SDag-Erling Smørgrav cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 576b7579f77SDag-Erling Smørgrav } 577b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 578b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_ALGO) 579b7579f77SDag-Erling Smørgrav p_ancil("send_udp over interface", r); 580b7579f77SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0); 581b7579f77SDag-Erling Smørgrav if(sent == -1) { 582*f61ef7f6SDag-Erling Smørgrav /* try again and block, waiting for IO to complete, 583*f61ef7f6SDag-Erling Smørgrav * we want to send the answer, and we will wait for 584*f61ef7f6SDag-Erling Smørgrav * the ethernet interface buffer to have space. */ 585*f61ef7f6SDag-Erling Smørgrav #ifndef USE_WINSOCK 586*f61ef7f6SDag-Erling Smørgrav if(errno == EAGAIN || 587*f61ef7f6SDag-Erling Smørgrav # ifdef EWOULDBLOCK 588*f61ef7f6SDag-Erling Smørgrav errno == EWOULDBLOCK || 589*f61ef7f6SDag-Erling Smørgrav # endif 590*f61ef7f6SDag-Erling Smørgrav errno == ENOBUFS) { 591*f61ef7f6SDag-Erling Smørgrav #else 592*f61ef7f6SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 593*f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAENOBUFS || 594*f61ef7f6SDag-Erling Smørgrav WSAGetLastError() == WSAEWOULDBLOCK) { 595*f61ef7f6SDag-Erling Smørgrav #endif 596*f61ef7f6SDag-Erling Smørgrav int e; 597*f61ef7f6SDag-Erling Smørgrav fd_set_block(c->fd); 598*f61ef7f6SDag-Erling Smørgrav sent = sendmsg(c->fd, &msg, 0); 599*f61ef7f6SDag-Erling Smørgrav e = errno; 600*f61ef7f6SDag-Erling Smørgrav fd_set_nonblock(c->fd); 601*f61ef7f6SDag-Erling Smørgrav errno = e; 602*f61ef7f6SDag-Erling Smørgrav } 603*f61ef7f6SDag-Erling Smørgrav } 604*f61ef7f6SDag-Erling Smørgrav if(sent == -1) { 605b7579f77SDag-Erling Smørgrav if(!udp_send_errno_needs_log(addr, addrlen)) 606b7579f77SDag-Erling Smørgrav return 0; 607b7579f77SDag-Erling Smørgrav verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno)); 608b7579f77SDag-Erling Smørgrav log_addr(VERB_OPS, "remote address is", 609b7579f77SDag-Erling Smørgrav (struct sockaddr_storage*)addr, addrlen); 610*f61ef7f6SDag-Erling Smørgrav #ifdef __NetBSD__ 611*f61ef7f6SDag-Erling Smørgrav /* netbsd 7 has IP_PKTINFO for recv but not send */ 612*f61ef7f6SDag-Erling Smørgrav if(errno == EINVAL && r->srctype == 4) 613*f61ef7f6SDag-Erling Smørgrav log_err("sendmsg: No support for sendmsg(IP_PKTINFO). " 614*f61ef7f6SDag-Erling Smørgrav "Please disable interface-automatic"); 615*f61ef7f6SDag-Erling Smørgrav #endif 616b7579f77SDag-Erling Smørgrav return 0; 61717d15b25SDag-Erling Smørgrav } else if((size_t)sent != sldns_buffer_remaining(packet)) { 618b7579f77SDag-Erling Smørgrav log_err("sent %d in place of %d bytes", 61917d15b25SDag-Erling Smørgrav (int)sent, (int)sldns_buffer_remaining(packet)); 620b7579f77SDag-Erling Smørgrav return 0; 621b7579f77SDag-Erling Smørgrav } 622b7579f77SDag-Erling Smørgrav return 1; 623b7579f77SDag-Erling Smørgrav #else 624b7579f77SDag-Erling Smørgrav (void)c; 625b7579f77SDag-Erling Smørgrav (void)packet; 626b7579f77SDag-Erling Smørgrav (void)addr; 627b7579f77SDag-Erling Smørgrav (void)addrlen; 628b7579f77SDag-Erling Smørgrav (void)r; 629b7579f77SDag-Erling Smørgrav log_err("sendmsg: IPV6_PKTINFO not supported"); 630b7579f77SDag-Erling Smørgrav return 0; 631b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */ 632b7579f77SDag-Erling Smørgrav } 633b7579f77SDag-Erling Smørgrav 634b7579f77SDag-Erling Smørgrav void 635b7579f77SDag-Erling Smørgrav comm_point_udp_ancil_callback(int fd, short event, void* arg) 636b7579f77SDag-Erling Smørgrav { 637b7579f77SDag-Erling Smørgrav #if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG) 638b7579f77SDag-Erling Smørgrav struct comm_reply rep; 639b7579f77SDag-Erling Smørgrav struct msghdr msg; 640b7579f77SDag-Erling Smørgrav struct iovec iov[1]; 641b7579f77SDag-Erling Smørgrav ssize_t rcv; 642b7579f77SDag-Erling Smørgrav char ancil[256]; 643b7579f77SDag-Erling Smørgrav int i; 644b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 645b7579f77SDag-Erling Smørgrav struct cmsghdr* cmsg; 646b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 647b7579f77SDag-Erling Smørgrav 648b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg; 649b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp); 650b7579f77SDag-Erling Smørgrav 651b7579f77SDag-Erling Smørgrav if(!(event&EV_READ)) 652b7579f77SDag-Erling Smørgrav return; 653b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 654b7579f77SDag-Erling Smørgrav comm_base_now(rep.c->ev->base); 655b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) { 65617d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer); 657b7579f77SDag-Erling Smørgrav rep.addrlen = (socklen_t)sizeof(rep.addr); 658b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 65917d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 660b7579f77SDag-Erling Smørgrav msg.msg_name = &rep.addr; 661b7579f77SDag-Erling Smørgrav msg.msg_namelen = (socklen_t)sizeof(rep.addr); 66217d15b25SDag-Erling Smørgrav iov[0].iov_base = sldns_buffer_begin(rep.c->buffer); 66317d15b25SDag-Erling Smørgrav iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer); 664b7579f77SDag-Erling Smørgrav msg.msg_iov = iov; 665b7579f77SDag-Erling Smørgrav msg.msg_iovlen = 1; 666b7579f77SDag-Erling Smørgrav msg.msg_control = ancil; 667b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 668b7579f77SDag-Erling Smørgrav msg.msg_controllen = sizeof(ancil); 669b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 670b7579f77SDag-Erling Smørgrav msg.msg_flags = 0; 671b7579f77SDag-Erling Smørgrav rcv = recvmsg(fd, &msg, 0); 672b7579f77SDag-Erling Smørgrav if(rcv == -1) { 673b7579f77SDag-Erling Smørgrav if(errno != EAGAIN && errno != EINTR) { 674b7579f77SDag-Erling Smørgrav log_err("recvmsg failed: %s", strerror(errno)); 675b7579f77SDag-Erling Smørgrav } 676b7579f77SDag-Erling Smørgrav return; 677b7579f77SDag-Erling Smørgrav } 678b7579f77SDag-Erling Smørgrav rep.addrlen = msg.msg_namelen; 67917d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv); 68017d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer); 681b7579f77SDag-Erling Smørgrav rep.srctype = 0; 682b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S 683b7579f77SDag-Erling Smørgrav for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 684b7579f77SDag-Erling Smørgrav cmsg = CMSG_NXTHDR(&msg, cmsg)) { 685b7579f77SDag-Erling Smørgrav if( cmsg->cmsg_level == IPPROTO_IPV6 && 686b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IPV6_PKTINFO) { 687b7579f77SDag-Erling Smørgrav rep.srctype = 6; 688b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg), 689b7579f77SDag-Erling Smørgrav sizeof(struct in6_pktinfo)); 690b7579f77SDag-Erling Smørgrav break; 691b7579f77SDag-Erling Smørgrav #ifdef IP_PKTINFO 692b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP && 693b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_PKTINFO) { 694b7579f77SDag-Erling Smørgrav rep.srctype = 4; 695b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg), 696b7579f77SDag-Erling Smørgrav sizeof(struct in_pktinfo)); 697b7579f77SDag-Erling Smørgrav break; 698b7579f77SDag-Erling Smørgrav #elif defined(IP_RECVDSTADDR) 699b7579f77SDag-Erling Smørgrav } else if( cmsg->cmsg_level == IPPROTO_IP && 700b7579f77SDag-Erling Smørgrav cmsg->cmsg_type == IP_RECVDSTADDR) { 701b7579f77SDag-Erling Smørgrav rep.srctype = 4; 702b7579f77SDag-Erling Smørgrav memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg), 703b7579f77SDag-Erling Smørgrav sizeof(struct in_addr)); 704b7579f77SDag-Erling Smørgrav break; 705b7579f77SDag-Erling Smørgrav #endif /* IP_PKTINFO or IP_RECVDSTADDR */ 706b7579f77SDag-Erling Smørgrav } 707b7579f77SDag-Erling Smørgrav } 708b7579f77SDag-Erling Smørgrav if(verbosity >= VERB_ALGO) 709b7579f77SDag-Erling Smørgrav p_ancil("receive_udp on interface", &rep); 710b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 711b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 712b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 713b7579f77SDag-Erling Smørgrav /* send back immediate reply */ 714b7579f77SDag-Erling Smørgrav (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer, 715b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, rep.addrlen, &rep); 716b7579f77SDag-Erling Smørgrav } 717b7579f77SDag-Erling Smørgrav if(rep.c->fd == -1) /* commpoint closed */ 718b7579f77SDag-Erling Smørgrav break; 719b7579f77SDag-Erling Smørgrav } 720b7579f77SDag-Erling Smørgrav #else 721b7579f77SDag-Erling Smørgrav (void)fd; 722b7579f77SDag-Erling Smørgrav (void)event; 723b7579f77SDag-Erling Smørgrav (void)arg; 724b7579f77SDag-Erling Smørgrav fatal_exit("recvmsg: No support for IPV6_PKTINFO. " 725b7579f77SDag-Erling Smørgrav "Please disable interface-automatic"); 726b7579f77SDag-Erling Smørgrav #endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */ 727b7579f77SDag-Erling Smørgrav } 728b7579f77SDag-Erling Smørgrav 729b7579f77SDag-Erling Smørgrav void 730b7579f77SDag-Erling Smørgrav comm_point_udp_callback(int fd, short event, void* arg) 731b7579f77SDag-Erling Smørgrav { 732b7579f77SDag-Erling Smørgrav struct comm_reply rep; 733b7579f77SDag-Erling Smørgrav ssize_t rcv; 734b7579f77SDag-Erling Smørgrav int i; 735b7579f77SDag-Erling Smørgrav 736b7579f77SDag-Erling Smørgrav rep.c = (struct comm_point*)arg; 737b7579f77SDag-Erling Smørgrav log_assert(rep.c->type == comm_udp); 738b7579f77SDag-Erling Smørgrav 739b7579f77SDag-Erling Smørgrav if(!(event&EV_READ)) 740b7579f77SDag-Erling Smørgrav return; 741b7579f77SDag-Erling Smørgrav log_assert(rep.c && rep.c->buffer && rep.c->fd == fd); 742b7579f77SDag-Erling Smørgrav comm_base_now(rep.c->ev->base); 743b7579f77SDag-Erling Smørgrav for(i=0; i<NUM_UDP_PER_SELECT; i++) { 74417d15b25SDag-Erling Smørgrav sldns_buffer_clear(rep.c->buffer); 745b7579f77SDag-Erling Smørgrav rep.addrlen = (socklen_t)sizeof(rep.addr); 746b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 74717d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(rep.c->buffer) > 0); 74817d15b25SDag-Erling Smørgrav rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer), 74917d15b25SDag-Erling Smørgrav sldns_buffer_remaining(rep.c->buffer), 0, 750b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, &rep.addrlen); 751b7579f77SDag-Erling Smørgrav if(rcv == -1) { 752b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 753b7579f77SDag-Erling Smørgrav if(errno != EAGAIN && errno != EINTR) 754b7579f77SDag-Erling Smørgrav log_err("recvfrom %d failed: %s", 755b7579f77SDag-Erling Smørgrav fd, strerror(errno)); 756b7579f77SDag-Erling Smørgrav #else 757b7579f77SDag-Erling Smørgrav if(WSAGetLastError() != WSAEINPROGRESS && 758b7579f77SDag-Erling Smørgrav WSAGetLastError() != WSAECONNRESET && 759b7579f77SDag-Erling Smørgrav WSAGetLastError()!= WSAEWOULDBLOCK) 760b7579f77SDag-Erling Smørgrav log_err("recvfrom failed: %s", 761b7579f77SDag-Erling Smørgrav wsa_strerror(WSAGetLastError())); 762b7579f77SDag-Erling Smørgrav #endif 763b7579f77SDag-Erling Smørgrav return; 764b7579f77SDag-Erling Smørgrav } 76517d15b25SDag-Erling Smørgrav sldns_buffer_skip(rep.c->buffer, rcv); 76617d15b25SDag-Erling Smørgrav sldns_buffer_flip(rep.c->buffer); 767b7579f77SDag-Erling Smørgrav rep.srctype = 0; 768b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(rep.c->callback)); 769b7579f77SDag-Erling Smørgrav if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) { 770b7579f77SDag-Erling Smørgrav /* send back immediate reply */ 771b7579f77SDag-Erling Smørgrav (void)comm_point_send_udp_msg(rep.c, rep.c->buffer, 772b7579f77SDag-Erling Smørgrav (struct sockaddr*)&rep.addr, rep.addrlen); 773b7579f77SDag-Erling Smørgrav } 774b7579f77SDag-Erling Smørgrav if(rep.c->fd != fd) /* commpoint closed to -1 or reused for 775b7579f77SDag-Erling Smørgrav another UDP port. Note rep.c cannot be reused with TCP fd. */ 776b7579f77SDag-Erling Smørgrav break; 777b7579f77SDag-Erling Smørgrav } 778b7579f77SDag-Erling Smørgrav } 779b7579f77SDag-Erling Smørgrav 780b7579f77SDag-Erling Smørgrav /** Use a new tcp handler for new query fd, set to read query */ 781b7579f77SDag-Erling Smørgrav static void 782b7579f77SDag-Erling Smørgrav setup_tcp_handler(struct comm_point* c, int fd) 783b7579f77SDag-Erling Smørgrav { 784b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 785b7579f77SDag-Erling Smørgrav log_assert(c->fd == -1); 78617d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer); 787b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 788b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 789b7579f77SDag-Erling Smørgrav comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT); 790b7579f77SDag-Erling Smørgrav } 791b7579f77SDag-Erling Smørgrav 792b7579f77SDag-Erling Smørgrav void comm_base_handle_slow_accept(int ATTR_UNUSED(fd), 793b7579f77SDag-Erling Smørgrav short ATTR_UNUSED(event), void* arg) 794b7579f77SDag-Erling Smørgrav { 795b7579f77SDag-Erling Smørgrav struct comm_base* b = (struct comm_base*)arg; 796b7579f77SDag-Erling Smørgrav /* timeout for the slow accept, re-enable accepts again */ 797b7579f77SDag-Erling Smørgrav if(b->start_accept) { 798b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "wait is over, slow accept disabled"); 799b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_start_accept(b->start_accept)); 800b7579f77SDag-Erling Smørgrav (*b->start_accept)(b->cb_arg); 801b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 0; 802b7579f77SDag-Erling Smørgrav } 803b7579f77SDag-Erling Smørgrav } 804b7579f77SDag-Erling Smørgrav 805b7579f77SDag-Erling Smørgrav int comm_point_perform_accept(struct comm_point* c, 806b7579f77SDag-Erling Smørgrav struct sockaddr_storage* addr, socklen_t* addrlen) 807b7579f77SDag-Erling Smørgrav { 808b7579f77SDag-Erling Smørgrav int new_fd; 809b7579f77SDag-Erling Smørgrav *addrlen = (socklen_t)sizeof(*addr); 810b7579f77SDag-Erling Smørgrav new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen); 811b7579f77SDag-Erling Smørgrav if(new_fd == -1) { 812b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 813b7579f77SDag-Erling Smørgrav /* EINTR is signal interrupt. others are closed connection. */ 814b7579f77SDag-Erling Smørgrav if( errno == EINTR || errno == EAGAIN 815b7579f77SDag-Erling Smørgrav #ifdef EWOULDBLOCK 816b7579f77SDag-Erling Smørgrav || errno == EWOULDBLOCK 817b7579f77SDag-Erling Smørgrav #endif 818b7579f77SDag-Erling Smørgrav #ifdef ECONNABORTED 819b7579f77SDag-Erling Smørgrav || errno == ECONNABORTED 820b7579f77SDag-Erling Smørgrav #endif 821b7579f77SDag-Erling Smørgrav #ifdef EPROTO 822b7579f77SDag-Erling Smørgrav || errno == EPROTO 823b7579f77SDag-Erling Smørgrav #endif /* EPROTO */ 824b7579f77SDag-Erling Smørgrav ) 825b7579f77SDag-Erling Smørgrav return -1; 826b7579f77SDag-Erling Smørgrav #if defined(ENFILE) && defined(EMFILE) 827b7579f77SDag-Erling Smørgrav if(errno == ENFILE || errno == EMFILE) { 828b7579f77SDag-Erling Smørgrav /* out of file descriptors, likely outside of our 829b7579f77SDag-Erling Smørgrav * control. stop accept() calls for some time */ 830b7579f77SDag-Erling Smørgrav if(c->ev->base->stop_accept) { 831b7579f77SDag-Erling Smørgrav struct comm_base* b = c->ev->base; 832b7579f77SDag-Erling Smørgrav struct timeval tv; 833b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "out of file descriptors: " 834b7579f77SDag-Erling Smørgrav "slow accept"); 835b7579f77SDag-Erling Smørgrav b->eb->slow_accept_enabled = 1; 836b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_stop_accept( 837b7579f77SDag-Erling Smørgrav b->stop_accept)); 838b7579f77SDag-Erling Smørgrav (*b->stop_accept)(b->cb_arg); 839b7579f77SDag-Erling Smørgrav /* set timeout, no mallocs */ 840b7579f77SDag-Erling Smørgrav tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000; 841b7579f77SDag-Erling Smørgrav tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000; 842b7579f77SDag-Erling Smørgrav event_set(&b->eb->slow_accept, -1, EV_TIMEOUT, 843b7579f77SDag-Erling Smørgrav comm_base_handle_slow_accept, b); 844b7579f77SDag-Erling Smørgrav if(event_base_set(b->eb->base, 845b7579f77SDag-Erling Smørgrav &b->eb->slow_accept) != 0) { 846b7579f77SDag-Erling Smørgrav /* we do not want to log here, because 847b7579f77SDag-Erling Smørgrav * that would spam the logfiles. 848b7579f77SDag-Erling Smørgrav * error: "event_base_set failed." */ 849b7579f77SDag-Erling Smørgrav } 850b7579f77SDag-Erling Smørgrav if(event_add(&b->eb->slow_accept, &tv) != 0) { 851b7579f77SDag-Erling Smørgrav /* we do not want to log here, 852b7579f77SDag-Erling Smørgrav * error: "event_add failed." */ 853b7579f77SDag-Erling Smørgrav } 854b7579f77SDag-Erling Smørgrav } 855b7579f77SDag-Erling Smørgrav return -1; 856b7579f77SDag-Erling Smørgrav } 857b7579f77SDag-Erling Smørgrav #endif 858ff825849SDag-Erling Smørgrav log_err_addr("accept failed", strerror(errno), addr, *addrlen); 859b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 860b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS || 861b7579f77SDag-Erling Smørgrav WSAGetLastError() == WSAECONNRESET) 862b7579f77SDag-Erling Smørgrav return -1; 863b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 864b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 865b7579f77SDag-Erling Smørgrav return -1; 866b7579f77SDag-Erling Smørgrav } 867ff825849SDag-Erling Smørgrav log_err_addr("accept failed", wsa_strerror(WSAGetLastError()), 868ff825849SDag-Erling Smørgrav addr, *addrlen); 869b7579f77SDag-Erling Smørgrav #endif 870b7579f77SDag-Erling Smørgrav return -1; 871b7579f77SDag-Erling Smørgrav } 872b7579f77SDag-Erling Smørgrav fd_set_nonblock(new_fd); 873b7579f77SDag-Erling Smørgrav return new_fd; 874b7579f77SDag-Erling Smørgrav } 875b7579f77SDag-Erling Smørgrav 876b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 877b7579f77SDag-Erling Smørgrav static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp), 878b7579f77SDag-Erling Smørgrav int ATTR_UNUSED(argi), long argl, long retvalue) 879b7579f77SDag-Erling Smørgrav { 880b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper, 881b7579f77SDag-Erling Smørgrav (oper&BIO_CB_RETURN)?"return":"before", 882b7579f77SDag-Erling Smørgrav (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"), 883b7579f77SDag-Erling Smørgrav WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":""); 884b7579f77SDag-Erling Smørgrav /* on windows, check if previous operation caused EWOULDBLOCK */ 885b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) || 886b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) { 887b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) 888b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock((struct event*) 889b7579f77SDag-Erling Smørgrav BIO_get_callback_arg(b), EV_READ); 890b7579f77SDag-Erling Smørgrav } 891b7579f77SDag-Erling Smørgrav if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) || 892b7579f77SDag-Erling Smørgrav (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) { 893b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) 894b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock((struct event*) 895b7579f77SDag-Erling Smørgrav BIO_get_callback_arg(b), EV_WRITE); 896b7579f77SDag-Erling Smørgrav } 897b7579f77SDag-Erling Smørgrav /* return original return value */ 898b7579f77SDag-Erling Smørgrav return retvalue; 899b7579f77SDag-Erling Smørgrav } 900b7579f77SDag-Erling Smørgrav 901b7579f77SDag-Erling Smørgrav /** set win bio callbacks for nonblocking operations */ 902b7579f77SDag-Erling Smørgrav void 903b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl) 904b7579f77SDag-Erling Smørgrav { 905b7579f77SDag-Erling Smørgrav SSL* ssl = (SSL*)thessl; 906b7579f77SDag-Erling Smørgrav /* set them both just in case, but usually they are the same BIO */ 907b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb); 908b7579f77SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)&c->ev->ev); 909b7579f77SDag-Erling Smørgrav BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb); 910b7579f77SDag-Erling Smørgrav BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)&c->ev->ev); 911b7579f77SDag-Erling Smørgrav } 912b7579f77SDag-Erling Smørgrav #endif 913b7579f77SDag-Erling Smørgrav 914b7579f77SDag-Erling Smørgrav void 915b7579f77SDag-Erling Smørgrav comm_point_tcp_accept_callback(int fd, short event, void* arg) 916b7579f77SDag-Erling Smørgrav { 917b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg, *c_hdl; 918b7579f77SDag-Erling Smørgrav int new_fd; 919b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp_accept); 920b7579f77SDag-Erling Smørgrav if(!(event & EV_READ)) { 921b7579f77SDag-Erling Smørgrav log_info("ignoring tcp accept event %d", (int)event); 922b7579f77SDag-Erling Smørgrav return; 923b7579f77SDag-Erling Smørgrav } 924b7579f77SDag-Erling Smørgrav comm_base_now(c->ev->base); 925b7579f77SDag-Erling Smørgrav /* find free tcp handler. */ 926b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 927b7579f77SDag-Erling Smørgrav log_warn("accepted too many tcp, connections full"); 928b7579f77SDag-Erling Smørgrav return; 929b7579f77SDag-Erling Smørgrav } 930b7579f77SDag-Erling Smørgrav /* accept incoming connection. */ 931b7579f77SDag-Erling Smørgrav c_hdl = c->tcp_free; 932b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 933b7579f77SDag-Erling Smørgrav new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr, 934b7579f77SDag-Erling Smørgrav &c_hdl->repinfo.addrlen); 935b7579f77SDag-Erling Smørgrav if(new_fd == -1) 936b7579f77SDag-Erling Smørgrav return; 937b7579f77SDag-Erling Smørgrav if(c->ssl) { 938b7579f77SDag-Erling Smørgrav c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd); 939b7579f77SDag-Erling Smørgrav if(!c_hdl->ssl) { 940b7579f77SDag-Erling Smørgrav c_hdl->fd = new_fd; 941b7579f77SDag-Erling Smørgrav comm_point_close(c_hdl); 942b7579f77SDag-Erling Smørgrav return; 943b7579f77SDag-Erling Smørgrav } 944b7579f77SDag-Erling Smørgrav c_hdl->ssl_shake_state = comm_ssl_shake_read; 945b7579f77SDag-Erling Smørgrav #ifdef USE_WINSOCK 946b7579f77SDag-Erling Smørgrav comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl); 947b7579f77SDag-Erling Smørgrav #endif 948b7579f77SDag-Erling Smørgrav } 949b7579f77SDag-Erling Smørgrav 950b7579f77SDag-Erling Smørgrav /* grab the tcp handler buffers */ 95109a3aaf3SDag-Erling Smørgrav c->cur_tcp_count++; 952b7579f77SDag-Erling Smørgrav c->tcp_free = c_hdl->tcp_free; 953b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 954b7579f77SDag-Erling Smørgrav /* stop accepting incoming queries for now. */ 955b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 956b7579f77SDag-Erling Smørgrav } 957b7579f77SDag-Erling Smørgrav setup_tcp_handler(c_hdl, new_fd); 958b7579f77SDag-Erling Smørgrav } 959b7579f77SDag-Erling Smørgrav 960b7579f77SDag-Erling Smørgrav /** Make tcp handler free for next assignment */ 961b7579f77SDag-Erling Smørgrav static void 962b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(struct comm_point* c) 963b7579f77SDag-Erling Smørgrav { 964b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 965b7579f77SDag-Erling Smørgrav if(c->ssl) { 9668ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 967b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl); 968b7579f77SDag-Erling Smørgrav SSL_free(c->ssl); 969b7579f77SDag-Erling Smørgrav c->ssl = NULL; 9708ed2b524SDag-Erling Smørgrav #endif 971b7579f77SDag-Erling Smørgrav } 972b7579f77SDag-Erling Smørgrav comm_point_close(c); 973b7579f77SDag-Erling Smørgrav if(c->tcp_parent) { 97409a3aaf3SDag-Erling Smørgrav c->tcp_parent->cur_tcp_count--; 975b7579f77SDag-Erling Smørgrav c->tcp_free = c->tcp_parent->tcp_free; 976b7579f77SDag-Erling Smørgrav c->tcp_parent->tcp_free = c; 977b7579f77SDag-Erling Smørgrav if(!c->tcp_free) { 978b7579f77SDag-Erling Smørgrav /* re-enable listening on accept socket */ 979b7579f77SDag-Erling Smørgrav comm_point_start_listening(c->tcp_parent, -1, -1); 980b7579f77SDag-Erling Smørgrav } 981b7579f77SDag-Erling Smørgrav } 982b7579f77SDag-Erling Smørgrav } 983b7579f77SDag-Erling Smørgrav 984b7579f77SDag-Erling Smørgrav /** do the callback when writing is done */ 985b7579f77SDag-Erling Smørgrav static void 986b7579f77SDag-Erling Smørgrav tcp_callback_writer(struct comm_point* c) 987b7579f77SDag-Erling Smørgrav { 988b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 98917d15b25SDag-Erling Smørgrav sldns_buffer_clear(c->buffer); 990b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw) 991b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 992b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 993b7579f77SDag-Erling Smørgrav /* switch from listening(write) to listening(read) */ 994b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 995b7579f77SDag-Erling Smørgrav comm_point_start_listening(c, -1, -1); 996b7579f77SDag-Erling Smørgrav } 997b7579f77SDag-Erling Smørgrav 998b7579f77SDag-Erling Smørgrav /** do the callback when reading is done */ 999b7579f77SDag-Erling Smørgrav static void 1000b7579f77SDag-Erling Smørgrav tcp_callback_reader(struct comm_point* c) 1001b7579f77SDag-Erling Smørgrav { 1002b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local); 100317d15b25SDag-Erling Smørgrav sldns_buffer_flip(c->buffer); 1004b7579f77SDag-Erling Smørgrav if(c->tcp_do_toggle_rw) 1005b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1006b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1007b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp) 1008b7579f77SDag-Erling Smørgrav comm_point_stop_listening(c); 1009b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 1010b7579f77SDag-Erling Smørgrav if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) { 1011b7579f77SDag-Erling Smørgrav comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT); 1012b7579f77SDag-Erling Smørgrav } 1013b7579f77SDag-Erling Smørgrav } 1014b7579f77SDag-Erling Smørgrav 1015b7579f77SDag-Erling Smørgrav /** continue ssl handshake */ 10168ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1017b7579f77SDag-Erling Smørgrav static int 1018b7579f77SDag-Erling Smørgrav ssl_handshake(struct comm_point* c) 1019b7579f77SDag-Erling Smørgrav { 1020b7579f77SDag-Erling Smørgrav int r; 1021b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_read) { 1022b7579f77SDag-Erling Smørgrav /* read condition satisfied back to writing */ 1023b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 1); 1024b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 1025b7579f77SDag-Erling Smørgrav return 1; 1026b7579f77SDag-Erling Smørgrav } 1027b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_hs_write) { 1028b7579f77SDag-Erling Smørgrav /* write condition satisfied, back to reading */ 1029b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1030b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 1031b7579f77SDag-Erling Smørgrav return 1; 1032b7579f77SDag-Erling Smørgrav } 1033b7579f77SDag-Erling Smørgrav 1034b7579f77SDag-Erling Smørgrav ERR_clear_error(); 1035b7579f77SDag-Erling Smørgrav r = SSL_do_handshake(c->ssl); 1036b7579f77SDag-Erling Smørgrav if(r != 1) { 1037b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1038b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_WANT_READ) { 1039b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_read) 1040b7579f77SDag-Erling Smørgrav return 1; 1041b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 1042b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1043b7579f77SDag-Erling Smørgrav return 1; 1044b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1045b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state == comm_ssl_shake_write) 1046b7579f77SDag-Erling Smørgrav return 1; 1047b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_write; 1048b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1049b7579f77SDag-Erling Smørgrav return 1; 1050b7579f77SDag-Erling Smørgrav } else if(r == 0) { 1051b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1052b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1053b7579f77SDag-Erling Smørgrav /* SYSCALL and errno==0 means closed uncleanly */ 1054b7579f77SDag-Erling Smørgrav if(errno != 0) 1055b7579f77SDag-Erling Smørgrav log_err("SSL_handshake syscall: %s", 1056b7579f77SDag-Erling Smørgrav strerror(errno)); 1057b7579f77SDag-Erling Smørgrav return 0; 1058b7579f77SDag-Erling Smørgrav } else { 1059b7579f77SDag-Erling Smørgrav log_crypto_err("ssl handshake failed"); 1060b7579f77SDag-Erling Smørgrav log_addr(1, "ssl handshake failed", &c->repinfo.addr, 1061b7579f77SDag-Erling Smørgrav c->repinfo.addrlen); 1062b7579f77SDag-Erling Smørgrav return 0; 1063b7579f77SDag-Erling Smørgrav } 1064b7579f77SDag-Erling Smørgrav } 1065b7579f77SDag-Erling Smørgrav /* this is where peer verification could take place */ 1066b7579f77SDag-Erling Smørgrav log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr, 1067b7579f77SDag-Erling Smørgrav c->repinfo.addrlen); 1068b7579f77SDag-Erling Smørgrav 1069b7579f77SDag-Erling Smørgrav /* setup listen rw correctly */ 1070b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) { 1071b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_read) 1072b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1073b7579f77SDag-Erling Smørgrav } else { 1074b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 1); 1075b7579f77SDag-Erling Smørgrav } 1076b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_none; 1077b7579f77SDag-Erling Smørgrav return 1; 1078b7579f77SDag-Erling Smørgrav } 10798ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1080b7579f77SDag-Erling Smørgrav 1081b7579f77SDag-Erling Smørgrav /** ssl read callback on TCP */ 1082b7579f77SDag-Erling Smørgrav static int 1083b7579f77SDag-Erling Smørgrav ssl_handle_read(struct comm_point* c) 1084b7579f77SDag-Erling Smørgrav { 10858ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1086b7579f77SDag-Erling Smørgrav int r; 1087b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) { 1088b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c)) 1089b7579f77SDag-Erling Smørgrav return 0; 1090b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) 1091b7579f77SDag-Erling Smørgrav return 1; 1092b7579f77SDag-Erling Smørgrav } 1093b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 1094b7579f77SDag-Erling Smørgrav /* read length bytes */ 1095b7579f77SDag-Erling Smørgrav ERR_clear_error(); 109617d15b25SDag-Erling Smørgrav if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer, 1097b7579f77SDag-Erling Smørgrav c->tcp_byte_count), (int)(sizeof(uint16_t) - 1098b7579f77SDag-Erling Smørgrav c->tcp_byte_count))) <= 0) { 1099b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1100b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1101b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */ 1102b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1103b7579f77SDag-Erling Smørgrav return 1; /* read more later */ 1104b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1105b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write; 1106b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1107b7579f77SDag-Erling Smørgrav return 1; 1108b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1109b7579f77SDag-Erling Smørgrav if(errno != 0) 1110b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s", 1111b7579f77SDag-Erling Smørgrav strerror(errno)); 1112b7579f77SDag-Erling Smørgrav return 0; 1113b7579f77SDag-Erling Smørgrav } 1114b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_read"); 1115b7579f77SDag-Erling Smørgrav return 0; 1116b7579f77SDag-Erling Smørgrav } 1117b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1118b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count != sizeof(uint16_t)) 1119b7579f77SDag-Erling Smørgrav return 1; 112017d15b25SDag-Erling Smørgrav if(sldns_buffer_read_u16_at(c->buffer, 0) > 112117d15b25SDag-Erling Smørgrav sldns_buffer_capacity(c->buffer)) { 1122b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped larger than buffer"); 1123b7579f77SDag-Erling Smørgrav return 0; 1124b7579f77SDag-Erling Smørgrav } 112517d15b25SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, 112617d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 0)); 112717d15b25SDag-Erling Smørgrav if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1128b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "ssl: dropped bogus too short."); 1129b7579f77SDag-Erling Smørgrav return 0; 1130b7579f77SDag-Erling Smørgrav } 1131b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Reading ssl tcp query of length %d", 113217d15b25SDag-Erling Smørgrav (int)sldns_buffer_limit(c->buffer)); 1133b7579f77SDag-Erling Smørgrav } 113417d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 1135b7579f77SDag-Erling Smørgrav ERR_clear_error(); 113617d15b25SDag-Erling Smørgrav r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer), 113717d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer)); 1138b7579f77SDag-Erling Smørgrav if(r <= 0) { 1139b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1140b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1141b7579f77SDag-Erling Smørgrav return 0; /* shutdown, closed */ 1142b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1143b7579f77SDag-Erling Smørgrav return 1; /* read more later */ 1144b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1145b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_hs_write; 1146b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 0, 1); 1147b7579f77SDag-Erling Smørgrav return 1; 1148b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1149b7579f77SDag-Erling Smørgrav if(errno != 0) 1150b7579f77SDag-Erling Smørgrav log_err("SSL_read syscall: %s", 1151b7579f77SDag-Erling Smørgrav strerror(errno)); 1152b7579f77SDag-Erling Smørgrav return 0; 1153b7579f77SDag-Erling Smørgrav } 1154b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_read"); 1155b7579f77SDag-Erling Smørgrav return 0; 1156b7579f77SDag-Erling Smørgrav } 115717d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r); 115817d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) <= 0) { 1159b7579f77SDag-Erling Smørgrav tcp_callback_reader(c); 1160b7579f77SDag-Erling Smørgrav } 1161b7579f77SDag-Erling Smørgrav return 1; 11628ed2b524SDag-Erling Smørgrav #else 11638ed2b524SDag-Erling Smørgrav (void)c; 11648ed2b524SDag-Erling Smørgrav return 0; 11658ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1166b7579f77SDag-Erling Smørgrav } 1167b7579f77SDag-Erling Smørgrav 1168b7579f77SDag-Erling Smørgrav /** ssl write callback on TCP */ 1169b7579f77SDag-Erling Smørgrav static int 1170b7579f77SDag-Erling Smørgrav ssl_handle_write(struct comm_point* c) 1171b7579f77SDag-Erling Smørgrav { 11728ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1173b7579f77SDag-Erling Smørgrav int r; 1174b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) { 1175b7579f77SDag-Erling Smørgrav if(!ssl_handshake(c)) 1176b7579f77SDag-Erling Smørgrav return 0; 1177b7579f77SDag-Erling Smørgrav if(c->ssl_shake_state != comm_ssl_shake_none) 1178b7579f77SDag-Erling Smørgrav return 1; 1179b7579f77SDag-Erling Smørgrav } 1180b7579f77SDag-Erling Smørgrav /* ignore return, if fails we may simply block */ 1181b7579f77SDag-Erling Smørgrav (void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE); 1182b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 118317d15b25SDag-Erling Smørgrav uint16_t len = htons(sldns_buffer_limit(c->buffer)); 1184b7579f77SDag-Erling Smørgrav ERR_clear_error(); 1185b7579f77SDag-Erling Smørgrav r = SSL_write(c->ssl, 1186b7579f77SDag-Erling Smørgrav (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1187b7579f77SDag-Erling Smørgrav (int)(sizeof(uint16_t)-c->tcp_byte_count)); 1188b7579f77SDag-Erling Smørgrav if(r <= 0) { 1189b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1190b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1191b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1192b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1193b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 1194b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1195b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */ 1196b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1197b7579f77SDag-Erling Smørgrav return 1; /* write more later */ 1198b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1199b7579f77SDag-Erling Smørgrav if(errno != 0) 1200b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s", 1201b7579f77SDag-Erling Smørgrav strerror(errno)); 1202b7579f77SDag-Erling Smørgrav return 0; 1203b7579f77SDag-Erling Smørgrav } 1204b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_write"); 1205b7579f77SDag-Erling Smørgrav return 0; 1206b7579f77SDag-Erling Smørgrav } 1207b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1208b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) 1209b7579f77SDag-Erling Smørgrav return 1; 121017d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, c->tcp_byte_count - 1211b7579f77SDag-Erling Smørgrav sizeof(uint16_t)); 121217d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1213b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1214b7579f77SDag-Erling Smørgrav return 1; 1215b7579f77SDag-Erling Smørgrav } 1216b7579f77SDag-Erling Smørgrav } 121717d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 1218b7579f77SDag-Erling Smørgrav ERR_clear_error(); 121917d15b25SDag-Erling Smørgrav r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer), 122017d15b25SDag-Erling Smørgrav (int)sldns_buffer_remaining(c->buffer)); 1221b7579f77SDag-Erling Smørgrav if(r <= 0) { 1222b7579f77SDag-Erling Smørgrav int want = SSL_get_error(c->ssl, r); 1223b7579f77SDag-Erling Smørgrav if(want == SSL_ERROR_ZERO_RETURN) { 1224b7579f77SDag-Erling Smørgrav return 0; /* closed */ 1225b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_READ) { 1226b7579f77SDag-Erling Smørgrav c->ssl_shake_state = comm_ssl_shake_read; 1227b7579f77SDag-Erling Smørgrav comm_point_listen_for_rw(c, 1, 0); 1228b7579f77SDag-Erling Smørgrav return 1; /* wait for read condition */ 1229b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_WANT_WRITE) { 1230b7579f77SDag-Erling Smørgrav return 1; /* write more later */ 1231b7579f77SDag-Erling Smørgrav } else if(want == SSL_ERROR_SYSCALL) { 1232b7579f77SDag-Erling Smørgrav if(errno != 0) 1233b7579f77SDag-Erling Smørgrav log_err("SSL_write syscall: %s", 1234b7579f77SDag-Erling Smørgrav strerror(errno)); 1235b7579f77SDag-Erling Smørgrav return 0; 1236b7579f77SDag-Erling Smørgrav } 1237b7579f77SDag-Erling Smørgrav log_crypto_err("could not SSL_write"); 1238b7579f77SDag-Erling Smørgrav return 0; 1239b7579f77SDag-Erling Smørgrav } 124017d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, (ssize_t)r); 1241b7579f77SDag-Erling Smørgrav 124217d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1243b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1244b7579f77SDag-Erling Smørgrav } 1245b7579f77SDag-Erling Smørgrav return 1; 12468ed2b524SDag-Erling Smørgrav #else 12478ed2b524SDag-Erling Smørgrav (void)c; 12488ed2b524SDag-Erling Smørgrav return 0; 12498ed2b524SDag-Erling Smørgrav #endif /* HAVE_SSL */ 1250b7579f77SDag-Erling Smørgrav } 1251b7579f77SDag-Erling Smørgrav 1252b7579f77SDag-Erling Smørgrav /** handle ssl tcp connection with dns contents */ 1253b7579f77SDag-Erling Smørgrav static int 1254b7579f77SDag-Erling Smørgrav ssl_handle_it(struct comm_point* c) 1255b7579f77SDag-Erling Smørgrav { 1256b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) 1257b7579f77SDag-Erling Smørgrav return ssl_handle_read(c); 1258b7579f77SDag-Erling Smørgrav return ssl_handle_write(c); 1259b7579f77SDag-Erling Smørgrav } 1260b7579f77SDag-Erling Smørgrav 1261b7579f77SDag-Erling Smørgrav /** Handle tcp reading callback. 1262b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket. 1263b7579f77SDag-Erling Smørgrav * @param c: comm point to read from into buffer. 1264b7579f77SDag-Erling Smørgrav * @param short_ok: if true, very short packets are OK (for comm_local). 1265b7579f77SDag-Erling Smørgrav * @return: 0 on error 1266b7579f77SDag-Erling Smørgrav */ 1267b7579f77SDag-Erling Smørgrav static int 1268b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok) 1269b7579f77SDag-Erling Smørgrav { 1270b7579f77SDag-Erling Smørgrav ssize_t r; 1271b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp || c->type == comm_local); 1272b7579f77SDag-Erling Smørgrav if(c->ssl) 1273b7579f77SDag-Erling Smørgrav return ssl_handle_it(c); 1274b7579f77SDag-Erling Smørgrav if(!c->tcp_is_reading) 1275b7579f77SDag-Erling Smørgrav return 0; 1276b7579f77SDag-Erling Smørgrav 1277b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 1278b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 1279b7579f77SDag-Erling Smørgrav /* read length bytes */ 128017d15b25SDag-Erling Smørgrav r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count), 1281b7579f77SDag-Erling Smørgrav sizeof(uint16_t)-c->tcp_byte_count, 0); 1282b7579f77SDag-Erling Smørgrav if(r == 0) 1283b7579f77SDag-Erling Smørgrav return 0; 1284b7579f77SDag-Erling Smørgrav else if(r == -1) { 1285b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1286b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1287b7579f77SDag-Erling Smørgrav return 1; 1288b7579f77SDag-Erling Smørgrav #ifdef ECONNRESET 1289b7579f77SDag-Erling Smørgrav if(errno == ECONNRESET && verbosity < 2) 1290b7579f77SDag-Erling Smørgrav return 0; /* silence reset by peer */ 1291b7579f77SDag-Erling Smørgrav #endif 1292ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp s)", strerror(errno), 1293ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1294b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1295b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET) 1296b7579f77SDag-Erling Smørgrav return 0; 1297b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1298b7579f77SDag-Erling Smørgrav return 1; 1299b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1300b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 1301b7579f77SDag-Erling Smørgrav return 1; 1302b7579f77SDag-Erling Smørgrav } 1303ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp s)", 1304ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1305ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1306b7579f77SDag-Erling Smørgrav #endif 1307b7579f77SDag-Erling Smørgrav return 0; 1308b7579f77SDag-Erling Smørgrav } 1309b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1310b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count != sizeof(uint16_t)) 1311b7579f77SDag-Erling Smørgrav return 1; 131217d15b25SDag-Erling Smørgrav if(sldns_buffer_read_u16_at(c->buffer, 0) > 131317d15b25SDag-Erling Smørgrav sldns_buffer_capacity(c->buffer)) { 1314b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp: dropped larger than buffer"); 1315b7579f77SDag-Erling Smørgrav return 0; 1316b7579f77SDag-Erling Smørgrav } 131717d15b25SDag-Erling Smørgrav sldns_buffer_set_limit(c->buffer, 131817d15b25SDag-Erling Smørgrav sldns_buffer_read_u16_at(c->buffer, 0)); 1319b7579f77SDag-Erling Smørgrav if(!short_ok && 132017d15b25SDag-Erling Smørgrav sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) { 1321b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp: dropped bogus too short."); 1322b7579f77SDag-Erling Smørgrav return 0; 1323b7579f77SDag-Erling Smørgrav } 1324b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "Reading tcp query of length %d", 132517d15b25SDag-Erling Smørgrav (int)sldns_buffer_limit(c->buffer)); 1326b7579f77SDag-Erling Smørgrav } 1327b7579f77SDag-Erling Smørgrav 132817d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 132917d15b25SDag-Erling Smørgrav r = recv(fd, (void*)sldns_buffer_current(c->buffer), 133017d15b25SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer), 0); 1331b7579f77SDag-Erling Smørgrav if(r == 0) { 1332b7579f77SDag-Erling Smørgrav return 0; 1333b7579f77SDag-Erling Smørgrav } else if(r == -1) { 1334b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1335b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1336b7579f77SDag-Erling Smørgrav return 1; 1337ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp r)", strerror(errno), 1338ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1339b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1340b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAECONNRESET) 1341b7579f77SDag-Erling Smørgrav return 0; 1342b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1343b7579f77SDag-Erling Smørgrav return 1; 1344b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1345b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_READ); 1346b7579f77SDag-Erling Smørgrav return 1; 1347b7579f77SDag-Erling Smørgrav } 1348ff825849SDag-Erling Smørgrav log_err_addr("read (in tcp r)", 1349ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1350ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1351b7579f77SDag-Erling Smørgrav #endif 1352b7579f77SDag-Erling Smørgrav return 0; 1353b7579f77SDag-Erling Smørgrav } 135417d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, r); 135517d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) <= 0) { 1356b7579f77SDag-Erling Smørgrav tcp_callback_reader(c); 1357b7579f77SDag-Erling Smørgrav } 1358b7579f77SDag-Erling Smørgrav return 1; 1359b7579f77SDag-Erling Smørgrav } 1360b7579f77SDag-Erling Smørgrav 1361b7579f77SDag-Erling Smørgrav /** 1362b7579f77SDag-Erling Smørgrav * Handle tcp writing callback. 1363b7579f77SDag-Erling Smørgrav * @param fd: file descriptor of socket. 1364b7579f77SDag-Erling Smørgrav * @param c: comm point to write buffer out of. 1365b7579f77SDag-Erling Smørgrav * @return: 0 on error 1366b7579f77SDag-Erling Smørgrav */ 1367b7579f77SDag-Erling Smørgrav static int 1368b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_write(int fd, struct comm_point* c) 1369b7579f77SDag-Erling Smørgrav { 1370b7579f77SDag-Erling Smørgrav ssize_t r; 1371b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 1372b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading && !c->ssl) 1373b7579f77SDag-Erling Smørgrav return 0; 1374b7579f77SDag-Erling Smørgrav log_assert(fd != -1); 1375b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) { 1376b7579f77SDag-Erling Smørgrav /* check for pending error from nonblocking connect */ 1377b7579f77SDag-Erling Smørgrav /* from Stevens, unix network programming, vol1, 3rd ed, p450*/ 1378b7579f77SDag-Erling Smørgrav int error = 0; 1379b7579f77SDag-Erling Smørgrav socklen_t len = (socklen_t)sizeof(error); 1380b7579f77SDag-Erling Smørgrav if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error, 1381b7579f77SDag-Erling Smørgrav &len) < 0){ 1382b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1383b7579f77SDag-Erling Smørgrav error = errno; /* on solaris errno is error */ 1384b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1385b7579f77SDag-Erling Smørgrav error = WSAGetLastError(); 1386b7579f77SDag-Erling Smørgrav #endif 1387b7579f77SDag-Erling Smørgrav } 1388b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1389b7579f77SDag-Erling Smørgrav #if defined(EINPROGRESS) && defined(EWOULDBLOCK) 1390b7579f77SDag-Erling Smørgrav if(error == EINPROGRESS || error == EWOULDBLOCK) 1391b7579f77SDag-Erling Smørgrav return 1; /* try again later */ 1392b7579f77SDag-Erling Smørgrav else 1393b7579f77SDag-Erling Smørgrav #endif 1394b7579f77SDag-Erling Smørgrav if(error != 0 && verbosity < 2) 1395b7579f77SDag-Erling Smørgrav return 0; /* silence lots of chatter in the logs */ 1396b7579f77SDag-Erling Smørgrav else if(error != 0) { 1397ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", strerror(error), 1398ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1399b7579f77SDag-Erling Smørgrav #else /* USE_WINSOCK */ 1400b7579f77SDag-Erling Smørgrav /* examine error */ 1401b7579f77SDag-Erling Smørgrav if(error == WSAEINPROGRESS) 1402b7579f77SDag-Erling Smørgrav return 1; 1403b7579f77SDag-Erling Smørgrav else if(error == WSAEWOULDBLOCK) { 1404b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1405b7579f77SDag-Erling Smørgrav return 1; 1406b7579f77SDag-Erling Smørgrav } else if(error != 0 && verbosity < 2) 1407b7579f77SDag-Erling Smørgrav return 0; 1408b7579f77SDag-Erling Smørgrav else if(error != 0) { 1409ff825849SDag-Erling Smørgrav log_err_addr("tcp connect", wsa_strerror(error), 1410ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1411b7579f77SDag-Erling Smørgrav #endif /* USE_WINSOCK */ 1412b7579f77SDag-Erling Smørgrav return 0; 1413b7579f77SDag-Erling Smørgrav } 1414b7579f77SDag-Erling Smørgrav } 1415b7579f77SDag-Erling Smørgrav if(c->ssl) 1416b7579f77SDag-Erling Smørgrav return ssl_handle_it(c); 1417b7579f77SDag-Erling Smørgrav 1418b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) { 141917d15b25SDag-Erling Smørgrav uint16_t len = htons(sldns_buffer_limit(c->buffer)); 1420b7579f77SDag-Erling Smørgrav #ifdef HAVE_WRITEV 1421b7579f77SDag-Erling Smørgrav struct iovec iov[2]; 1422b7579f77SDag-Erling Smørgrav iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count; 1423b7579f77SDag-Erling Smørgrav iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count; 142417d15b25SDag-Erling Smørgrav iov[1].iov_base = sldns_buffer_begin(c->buffer); 142517d15b25SDag-Erling Smørgrav iov[1].iov_len = sldns_buffer_limit(c->buffer); 1426b7579f77SDag-Erling Smørgrav log_assert(iov[0].iov_len > 0); 1427b7579f77SDag-Erling Smørgrav log_assert(iov[1].iov_len > 0); 1428b7579f77SDag-Erling Smørgrav r = writev(fd, iov, 2); 1429b7579f77SDag-Erling Smørgrav #else /* HAVE_WRITEV */ 1430b7579f77SDag-Erling Smørgrav r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count), 1431b7579f77SDag-Erling Smørgrav sizeof(uint16_t)-c->tcp_byte_count, 0); 1432b7579f77SDag-Erling Smørgrav #endif /* HAVE_WRITEV */ 1433b7579f77SDag-Erling Smørgrav if(r == -1) { 1434b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1435b7579f77SDag-Erling Smørgrav # ifdef EPIPE 1436b7579f77SDag-Erling Smørgrav if(errno == EPIPE && verbosity < 2) 1437b7579f77SDag-Erling Smørgrav return 0; /* silence 'broken pipe' */ 1438b7579f77SDag-Erling Smørgrav #endif 1439b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1440b7579f77SDag-Erling Smørgrav return 1; 1441ff825849SDag-Erling Smørgrav # ifdef HAVE_WRITEV 1442ff825849SDag-Erling Smørgrav log_err_addr("tcp writev", strerror(errno), 1443ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1444ff825849SDag-Erling Smørgrav # else /* HAVE_WRITEV */ 1445ff825849SDag-Erling Smørgrav log_err_addr("tcp send s", strerror(errno), 1446ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1447ff825849SDag-Erling Smørgrav # endif /* HAVE_WRITEV */ 1448b7579f77SDag-Erling Smørgrav #else 1449b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAENOTCONN) 1450b7579f77SDag-Erling Smørgrav return 1; 1451b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1452b7579f77SDag-Erling Smørgrav return 1; 1453b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1454b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1455b7579f77SDag-Erling Smørgrav return 1; 1456b7579f77SDag-Erling Smørgrav } 1457ff825849SDag-Erling Smørgrav log_err_addr("tcp send s", 1458ff825849SDag-Erling Smørgrav wsa_strerror(WSAGetLastError()), 1459ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1460b7579f77SDag-Erling Smørgrav #endif 1461b7579f77SDag-Erling Smørgrav return 0; 1462b7579f77SDag-Erling Smørgrav } 1463b7579f77SDag-Erling Smørgrav c->tcp_byte_count += r; 1464b7579f77SDag-Erling Smørgrav if(c->tcp_byte_count < sizeof(uint16_t)) 1465b7579f77SDag-Erling Smørgrav return 1; 146617d15b25SDag-Erling Smørgrav sldns_buffer_set_position(c->buffer, c->tcp_byte_count - 1467b7579f77SDag-Erling Smørgrav sizeof(uint16_t)); 146817d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1469b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1470b7579f77SDag-Erling Smørgrav return 1; 1471b7579f77SDag-Erling Smørgrav } 1472b7579f77SDag-Erling Smørgrav } 147317d15b25SDag-Erling Smørgrav log_assert(sldns_buffer_remaining(c->buffer) > 0); 147417d15b25SDag-Erling Smørgrav r = send(fd, (void*)sldns_buffer_current(c->buffer), 147517d15b25SDag-Erling Smørgrav sldns_buffer_remaining(c->buffer), 0); 1476b7579f77SDag-Erling Smørgrav if(r == -1) { 1477b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1478b7579f77SDag-Erling Smørgrav if(errno == EINTR || errno == EAGAIN) 1479b7579f77SDag-Erling Smørgrav return 1; 1480ff825849SDag-Erling Smørgrav log_err_addr("tcp send r", strerror(errno), 1481ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1482b7579f77SDag-Erling Smørgrav #else 1483b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEINPROGRESS) 1484b7579f77SDag-Erling Smørgrav return 1; 1485b7579f77SDag-Erling Smørgrav if(WSAGetLastError() == WSAEWOULDBLOCK) { 1486b7579f77SDag-Erling Smørgrav winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE); 1487b7579f77SDag-Erling Smørgrav return 1; 1488b7579f77SDag-Erling Smørgrav } 1489ff825849SDag-Erling Smørgrav log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()), 1490ff825849SDag-Erling Smørgrav &c->repinfo.addr, c->repinfo.addrlen); 1491b7579f77SDag-Erling Smørgrav #endif 1492b7579f77SDag-Erling Smørgrav return 0; 1493b7579f77SDag-Erling Smørgrav } 149417d15b25SDag-Erling Smørgrav sldns_buffer_skip(c->buffer, r); 1495b7579f77SDag-Erling Smørgrav 149617d15b25SDag-Erling Smørgrav if(sldns_buffer_remaining(c->buffer) == 0) { 1497b7579f77SDag-Erling Smørgrav tcp_callback_writer(c); 1498b7579f77SDag-Erling Smørgrav } 1499b7579f77SDag-Erling Smørgrav 1500b7579f77SDag-Erling Smørgrav return 1; 1501b7579f77SDag-Erling Smørgrav } 1502b7579f77SDag-Erling Smørgrav 1503b7579f77SDag-Erling Smørgrav void 1504b7579f77SDag-Erling Smørgrav comm_point_tcp_handle_callback(int fd, short event, void* arg) 1505b7579f77SDag-Erling Smørgrav { 1506b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1507b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_tcp); 1508b7579f77SDag-Erling Smørgrav comm_base_now(c->ev->base); 1509b7579f77SDag-Erling Smørgrav 1510b7579f77SDag-Erling Smørgrav if(event&EV_READ) { 1511b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 0)) { 1512b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1513b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1514b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point( 1515b7579f77SDag-Erling Smørgrav c->callback)); 1516b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1517b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL); 1518b7579f77SDag-Erling Smørgrav } 1519b7579f77SDag-Erling Smørgrav } 1520b7579f77SDag-Erling Smørgrav return; 1521b7579f77SDag-Erling Smørgrav } 1522b7579f77SDag-Erling Smørgrav if(event&EV_WRITE) { 1523b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_write(fd, c)) { 1524b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1525b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1526b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point( 1527b7579f77SDag-Erling Smørgrav c->callback)); 1528b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1529b7579f77SDag-Erling Smørgrav NETEVENT_CLOSED, NULL); 1530b7579f77SDag-Erling Smørgrav } 1531b7579f77SDag-Erling Smørgrav } 1532b7579f77SDag-Erling Smørgrav return; 1533b7579f77SDag-Erling Smørgrav } 1534b7579f77SDag-Erling Smørgrav if(event&EV_TIMEOUT) { 1535b7579f77SDag-Erling Smørgrav verbose(VERB_QUERY, "tcp took too long, dropped"); 1536b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(c); 1537b7579f77SDag-Erling Smørgrav if(!c->tcp_do_close) { 1538b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 1539b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, 1540b7579f77SDag-Erling Smørgrav NETEVENT_TIMEOUT, NULL); 1541b7579f77SDag-Erling Smørgrav } 1542b7579f77SDag-Erling Smørgrav return; 1543b7579f77SDag-Erling Smørgrav } 1544b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for tcphdl.", event); 1545b7579f77SDag-Erling Smørgrav } 1546b7579f77SDag-Erling Smørgrav 1547b7579f77SDag-Erling Smørgrav void comm_point_local_handle_callback(int fd, short event, void* arg) 1548b7579f77SDag-Erling Smørgrav { 1549b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1550b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_local); 1551b7579f77SDag-Erling Smørgrav comm_base_now(c->ev->base); 1552b7579f77SDag-Erling Smørgrav 1553b7579f77SDag-Erling Smørgrav if(event&EV_READ) { 1554b7579f77SDag-Erling Smørgrav if(!comm_point_tcp_handle_read(fd, c, 1)) { 1555b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point(c->callback)); 1556b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED, 1557b7579f77SDag-Erling Smørgrav NULL); 1558b7579f77SDag-Erling Smørgrav } 1559b7579f77SDag-Erling Smørgrav return; 1560b7579f77SDag-Erling Smørgrav } 1561b7579f77SDag-Erling Smørgrav log_err("Ignored event %d for localhdl.", event); 1562b7579f77SDag-Erling Smørgrav } 1563b7579f77SDag-Erling Smørgrav 1564b7579f77SDag-Erling Smørgrav void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), 1565b7579f77SDag-Erling Smørgrav short event, void* arg) 1566b7579f77SDag-Erling Smørgrav { 1567b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)arg; 1568b7579f77SDag-Erling Smørgrav int err = NETEVENT_NOERROR; 1569b7579f77SDag-Erling Smørgrav log_assert(c->type == comm_raw); 1570b7579f77SDag-Erling Smørgrav comm_base_now(c->ev->base); 1571b7579f77SDag-Erling Smørgrav 1572b7579f77SDag-Erling Smørgrav if(event&EV_TIMEOUT) 1573b7579f77SDag-Erling Smørgrav err = NETEVENT_TIMEOUT; 1574b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_point_raw(c->callback)); 1575b7579f77SDag-Erling Smørgrav (void)(*c->callback)(c, c->cb_arg, err, NULL); 1576b7579f77SDag-Erling Smørgrav } 1577b7579f77SDag-Erling Smørgrav 1578b7579f77SDag-Erling Smørgrav struct comm_point* 157917d15b25SDag-Erling Smørgrav comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer, 1580b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1581b7579f77SDag-Erling Smørgrav { 1582b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1583b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1584b7579f77SDag-Erling Smørgrav short evbits; 1585b7579f77SDag-Erling Smørgrav if(!c) 1586b7579f77SDag-Erling Smørgrav return NULL; 1587b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1588b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1589b7579f77SDag-Erling Smørgrav if(!c->ev) { 1590b7579f77SDag-Erling Smørgrav free(c); 1591b7579f77SDag-Erling Smørgrav return NULL; 1592b7579f77SDag-Erling Smørgrav } 1593b7579f77SDag-Erling Smørgrav c->ev->base = base; 1594b7579f77SDag-Erling Smørgrav c->fd = fd; 1595b7579f77SDag-Erling Smørgrav c->buffer = buffer; 1596b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1597b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1598b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1599b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1600b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 160109a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1602b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1603b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1604b7579f77SDag-Erling Smørgrav c->type = comm_udp; 1605b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1606b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1607b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1608b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1609b7579f77SDag-Erling Smørgrav c->inuse = 0; 1610b7579f77SDag-Erling Smørgrav c->callback = callback; 1611b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1612b7579f77SDag-Erling Smørgrav evbits = EV_READ | EV_PERSIST; 1613b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1614b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c); 1615b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0) { 1616b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event"); 1617b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1618b7579f77SDag-Erling Smørgrav return NULL; 1619b7579f77SDag-Erling Smørgrav } 1620b7579f77SDag-Erling Smørgrav if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) { 1621b7579f77SDag-Erling Smørgrav log_err("could not add udp event"); 1622b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1623b7579f77SDag-Erling Smørgrav return NULL; 1624b7579f77SDag-Erling Smørgrav } 1625b7579f77SDag-Erling Smørgrav return c; 1626b7579f77SDag-Erling Smørgrav } 1627b7579f77SDag-Erling Smørgrav 1628b7579f77SDag-Erling Smørgrav struct comm_point* 1629b7579f77SDag-Erling Smørgrav comm_point_create_udp_ancil(struct comm_base *base, int fd, 163017d15b25SDag-Erling Smørgrav sldns_buffer* buffer, 1631b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1632b7579f77SDag-Erling Smørgrav { 1633b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1634b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1635b7579f77SDag-Erling Smørgrav short evbits; 1636b7579f77SDag-Erling Smørgrav if(!c) 1637b7579f77SDag-Erling Smørgrav return NULL; 1638b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1639b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1640b7579f77SDag-Erling Smørgrav if(!c->ev) { 1641b7579f77SDag-Erling Smørgrav free(c); 1642b7579f77SDag-Erling Smørgrav return NULL; 1643b7579f77SDag-Erling Smørgrav } 1644b7579f77SDag-Erling Smørgrav c->ev->base = base; 1645b7579f77SDag-Erling Smørgrav c->fd = fd; 1646b7579f77SDag-Erling Smørgrav c->buffer = buffer; 1647b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1648b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1649b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1650b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1651b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 165209a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1653b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1654b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1655b7579f77SDag-Erling Smørgrav c->type = comm_udp; 1656b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1657b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1658b7579f77SDag-Erling Smørgrav c->inuse = 0; 1659b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1660b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1661b7579f77SDag-Erling Smørgrav c->callback = callback; 1662b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1663b7579f77SDag-Erling Smørgrav evbits = EV_READ | EV_PERSIST; 1664b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1665b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_ancil_callback, c); 1666b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0) { 1667b7579f77SDag-Erling Smørgrav log_err("could not baseset udp event"); 1668b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1669b7579f77SDag-Erling Smørgrav return NULL; 1670b7579f77SDag-Erling Smørgrav } 1671b7579f77SDag-Erling Smørgrav if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) { 1672b7579f77SDag-Erling Smørgrav log_err("could not add udp event"); 1673b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1674b7579f77SDag-Erling Smørgrav return NULL; 1675b7579f77SDag-Erling Smørgrav } 1676b7579f77SDag-Erling Smørgrav return c; 1677b7579f77SDag-Erling Smørgrav } 1678b7579f77SDag-Erling Smørgrav 1679b7579f77SDag-Erling Smørgrav static struct comm_point* 1680b7579f77SDag-Erling Smørgrav comm_point_create_tcp_handler(struct comm_base *base, 1681b7579f77SDag-Erling Smørgrav struct comm_point* parent, size_t bufsize, 1682b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1683b7579f77SDag-Erling Smørgrav { 1684b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1685b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1686b7579f77SDag-Erling Smørgrav short evbits; 1687b7579f77SDag-Erling Smørgrav if(!c) 1688b7579f77SDag-Erling Smørgrav return NULL; 1689b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1690b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1691b7579f77SDag-Erling Smørgrav if(!c->ev) { 1692b7579f77SDag-Erling Smørgrav free(c); 1693b7579f77SDag-Erling Smørgrav return NULL; 1694b7579f77SDag-Erling Smørgrav } 1695b7579f77SDag-Erling Smørgrav c->ev->base = base; 1696b7579f77SDag-Erling Smørgrav c->fd = -1; 169717d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1698b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1699b7579f77SDag-Erling Smørgrav free(c->ev); 1700b7579f77SDag-Erling Smørgrav free(c); 1701b7579f77SDag-Erling Smørgrav return NULL; 1702b7579f77SDag-Erling Smørgrav } 1703b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof(struct timeval)); 1704b7579f77SDag-Erling Smørgrav if(!c->timeout) { 170517d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 1706b7579f77SDag-Erling Smørgrav free(c->ev); 1707b7579f77SDag-Erling Smørgrav free(c); 1708b7579f77SDag-Erling Smørgrav return NULL; 1709b7579f77SDag-Erling Smørgrav } 1710b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1711b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1712b7579f77SDag-Erling Smørgrav c->tcp_parent = parent; 1713b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 171409a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1715b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1716b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1717b7579f77SDag-Erling Smørgrav c->type = comm_tcp; 1718b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1719b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1720b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1; 1721b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1722b7579f77SDag-Erling Smørgrav c->repinfo.c = c; 1723b7579f77SDag-Erling Smørgrav c->callback = callback; 1724b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1725b7579f77SDag-Erling Smørgrav /* add to parent free list */ 1726b7579f77SDag-Erling Smørgrav c->tcp_free = parent->tcp_free; 1727b7579f77SDag-Erling Smørgrav parent->tcp_free = c; 1728b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1729b7579f77SDag-Erling Smørgrav evbits = EV_PERSIST | EV_READ | EV_TIMEOUT; 1730b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c); 1731b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0) 1732b7579f77SDag-Erling Smørgrav { 1733b7579f77SDag-Erling Smørgrav log_err("could not basetset tcphdl event"); 1734b7579f77SDag-Erling Smørgrav parent->tcp_free = c->tcp_free; 1735b7579f77SDag-Erling Smørgrav free(c->ev); 1736b7579f77SDag-Erling Smørgrav free(c); 1737b7579f77SDag-Erling Smørgrav return NULL; 1738b7579f77SDag-Erling Smørgrav } 1739b7579f77SDag-Erling Smørgrav return c; 1740b7579f77SDag-Erling Smørgrav } 1741b7579f77SDag-Erling Smørgrav 1742b7579f77SDag-Erling Smørgrav struct comm_point* 1743b7579f77SDag-Erling Smørgrav comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize, 1744b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1745b7579f77SDag-Erling Smørgrav { 1746b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1747b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1748b7579f77SDag-Erling Smørgrav short evbits; 1749b7579f77SDag-Erling Smørgrav int i; 1750b7579f77SDag-Erling Smørgrav /* first allocate the TCP accept listener */ 1751b7579f77SDag-Erling Smørgrav if(!c) 1752b7579f77SDag-Erling Smørgrav return NULL; 1753b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1754b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1755b7579f77SDag-Erling Smørgrav if(!c->ev) { 1756b7579f77SDag-Erling Smørgrav free(c); 1757b7579f77SDag-Erling Smørgrav return NULL; 1758b7579f77SDag-Erling Smørgrav } 1759b7579f77SDag-Erling Smørgrav c->ev->base = base; 1760b7579f77SDag-Erling Smørgrav c->fd = fd; 1761b7579f77SDag-Erling Smørgrav c->buffer = NULL; 1762b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1763b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1764b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1765b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1766b7579f77SDag-Erling Smørgrav c->max_tcp_count = num; 176709a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1768b7579f77SDag-Erling Smørgrav c->tcp_handlers = (struct comm_point**)calloc((size_t)num, 1769b7579f77SDag-Erling Smørgrav sizeof(struct comm_point*)); 1770b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers) { 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->tcp_free = NULL; 1776b7579f77SDag-Erling Smørgrav c->type = comm_tcp_accept; 1777b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1778b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1779b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1780b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1781b7579f77SDag-Erling Smørgrav c->callback = NULL; 1782b7579f77SDag-Erling Smørgrav c->cb_arg = NULL; 1783b7579f77SDag-Erling Smørgrav evbits = EV_READ | EV_PERSIST; 1784b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1785b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c); 1786b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1787b7579f77SDag-Erling Smørgrav event_add(&c->ev->ev, c->timeout) != 0 ) 1788b7579f77SDag-Erling Smørgrav { 1789b7579f77SDag-Erling Smørgrav log_err("could not add tcpacc event"); 1790b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1791b7579f77SDag-Erling Smørgrav return NULL; 1792b7579f77SDag-Erling Smørgrav } 1793b7579f77SDag-Erling Smørgrav 1794b7579f77SDag-Erling Smørgrav /* now prealloc the tcp handlers */ 1795b7579f77SDag-Erling Smørgrav for(i=0; i<num; i++) { 1796b7579f77SDag-Erling Smørgrav c->tcp_handlers[i] = comm_point_create_tcp_handler(base, 1797b7579f77SDag-Erling Smørgrav c, bufsize, callback, callback_arg); 1798b7579f77SDag-Erling Smørgrav if(!c->tcp_handlers[i]) { 1799b7579f77SDag-Erling Smørgrav comm_point_delete(c); 1800b7579f77SDag-Erling Smørgrav return NULL; 1801b7579f77SDag-Erling Smørgrav } 1802b7579f77SDag-Erling Smørgrav } 1803b7579f77SDag-Erling Smørgrav 1804b7579f77SDag-Erling Smørgrav return c; 1805b7579f77SDag-Erling Smørgrav } 1806b7579f77SDag-Erling Smørgrav 1807b7579f77SDag-Erling Smørgrav struct comm_point* 1808b7579f77SDag-Erling Smørgrav comm_point_create_tcp_out(struct comm_base *base, size_t bufsize, 1809b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1810b7579f77SDag-Erling Smørgrav { 1811b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1812b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1813b7579f77SDag-Erling Smørgrav short evbits; 1814b7579f77SDag-Erling Smørgrav if(!c) 1815b7579f77SDag-Erling Smørgrav return NULL; 1816b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1817b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1818b7579f77SDag-Erling Smørgrav if(!c->ev) { 1819b7579f77SDag-Erling Smørgrav free(c); 1820b7579f77SDag-Erling Smørgrav return NULL; 1821b7579f77SDag-Erling Smørgrav } 1822b7579f77SDag-Erling Smørgrav c->ev->base = base; 1823b7579f77SDag-Erling Smørgrav c->fd = -1; 182417d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1825b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1826b7579f77SDag-Erling Smørgrav free(c->ev); 1827b7579f77SDag-Erling Smørgrav free(c); 1828b7579f77SDag-Erling Smørgrav return NULL; 1829b7579f77SDag-Erling Smørgrav } 1830b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1831b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1832b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1833b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1834b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 183509a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1836b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1837b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1838b7579f77SDag-Erling Smørgrav c->type = comm_tcp; 1839b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1840b7579f77SDag-Erling Smørgrav c->do_not_close = 0; 1841b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 1; 1842b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 1; 1843b7579f77SDag-Erling Smørgrav c->repinfo.c = c; 1844b7579f77SDag-Erling Smørgrav c->callback = callback; 1845b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1846b7579f77SDag-Erling Smørgrav evbits = EV_PERSIST | EV_WRITE; 1847b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c); 1848b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0) 1849b7579f77SDag-Erling Smørgrav { 1850b7579f77SDag-Erling Smørgrav log_err("could not basetset tcpout event"); 185117d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 1852b7579f77SDag-Erling Smørgrav free(c->ev); 1853b7579f77SDag-Erling Smørgrav free(c); 1854b7579f77SDag-Erling Smørgrav return NULL; 1855b7579f77SDag-Erling Smørgrav } 1856b7579f77SDag-Erling Smørgrav 1857b7579f77SDag-Erling Smørgrav return c; 1858b7579f77SDag-Erling Smørgrav } 1859b7579f77SDag-Erling Smørgrav 1860b7579f77SDag-Erling Smørgrav struct comm_point* 1861b7579f77SDag-Erling Smørgrav comm_point_create_local(struct comm_base *base, int fd, size_t bufsize, 1862b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1863b7579f77SDag-Erling Smørgrav { 1864b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1865b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1866b7579f77SDag-Erling Smørgrav short evbits; 1867b7579f77SDag-Erling Smørgrav if(!c) 1868b7579f77SDag-Erling Smørgrav return NULL; 1869b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1870b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1871b7579f77SDag-Erling Smørgrav if(!c->ev) { 1872b7579f77SDag-Erling Smørgrav free(c); 1873b7579f77SDag-Erling Smørgrav return NULL; 1874b7579f77SDag-Erling Smørgrav } 1875b7579f77SDag-Erling Smørgrav c->ev->base = base; 1876b7579f77SDag-Erling Smørgrav c->fd = fd; 187717d15b25SDag-Erling Smørgrav c->buffer = sldns_buffer_new(bufsize); 1878b7579f77SDag-Erling Smørgrav if(!c->buffer) { 1879b7579f77SDag-Erling Smørgrav free(c->ev); 1880b7579f77SDag-Erling Smørgrav free(c); 1881b7579f77SDag-Erling Smørgrav return NULL; 1882b7579f77SDag-Erling Smørgrav } 1883b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1884b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 1; 1885b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1886b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1887b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 188809a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1889b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1890b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1891b7579f77SDag-Erling Smørgrav c->type = comm_local; 1892b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1893b7579f77SDag-Erling Smørgrav c->do_not_close = 1; 1894b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1895b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1896b7579f77SDag-Erling Smørgrav c->callback = callback; 1897b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1898b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1899b7579f77SDag-Erling Smørgrav evbits = EV_PERSIST | EV_READ; 1900b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_local_handle_callback, 1901b7579f77SDag-Erling Smørgrav c); 1902b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1903b7579f77SDag-Erling Smørgrav event_add(&c->ev->ev, c->timeout) != 0 ) 1904b7579f77SDag-Erling Smørgrav { 1905b7579f77SDag-Erling Smørgrav log_err("could not add localhdl event"); 1906b7579f77SDag-Erling Smørgrav free(c->ev); 1907b7579f77SDag-Erling Smørgrav free(c); 1908b7579f77SDag-Erling Smørgrav return NULL; 1909b7579f77SDag-Erling Smørgrav } 1910b7579f77SDag-Erling Smørgrav return c; 1911b7579f77SDag-Erling Smørgrav } 1912b7579f77SDag-Erling Smørgrav 1913b7579f77SDag-Erling Smørgrav struct comm_point* 1914b7579f77SDag-Erling Smørgrav comm_point_create_raw(struct comm_base* base, int fd, int writing, 1915b7579f77SDag-Erling Smørgrav comm_point_callback_t* callback, void* callback_arg) 1916b7579f77SDag-Erling Smørgrav { 1917b7579f77SDag-Erling Smørgrav struct comm_point* c = (struct comm_point*)calloc(1, 1918b7579f77SDag-Erling Smørgrav sizeof(struct comm_point)); 1919b7579f77SDag-Erling Smørgrav short evbits; 1920b7579f77SDag-Erling Smørgrav if(!c) 1921b7579f77SDag-Erling Smørgrav return NULL; 1922b7579f77SDag-Erling Smørgrav c->ev = (struct internal_event*)calloc(1, 1923b7579f77SDag-Erling Smørgrav sizeof(struct internal_event)); 1924b7579f77SDag-Erling Smørgrav if(!c->ev) { 1925b7579f77SDag-Erling Smørgrav free(c); 1926b7579f77SDag-Erling Smørgrav return NULL; 1927b7579f77SDag-Erling Smørgrav } 1928b7579f77SDag-Erling Smørgrav c->ev->base = base; 1929b7579f77SDag-Erling Smørgrav c->fd = fd; 1930b7579f77SDag-Erling Smørgrav c->buffer = NULL; 1931b7579f77SDag-Erling Smørgrav c->timeout = NULL; 1932b7579f77SDag-Erling Smørgrav c->tcp_is_reading = 0; 1933b7579f77SDag-Erling Smørgrav c->tcp_byte_count = 0; 1934b7579f77SDag-Erling Smørgrav c->tcp_parent = NULL; 1935b7579f77SDag-Erling Smørgrav c->max_tcp_count = 0; 193609a3aaf3SDag-Erling Smørgrav c->cur_tcp_count = 0; 1937b7579f77SDag-Erling Smørgrav c->tcp_handlers = NULL; 1938b7579f77SDag-Erling Smørgrav c->tcp_free = NULL; 1939b7579f77SDag-Erling Smørgrav c->type = comm_raw; 1940b7579f77SDag-Erling Smørgrav c->tcp_do_close = 0; 1941b7579f77SDag-Erling Smørgrav c->do_not_close = 1; 1942b7579f77SDag-Erling Smørgrav c->tcp_do_toggle_rw = 0; 1943b7579f77SDag-Erling Smørgrav c->tcp_check_nb_connect = 0; 1944b7579f77SDag-Erling Smørgrav c->callback = callback; 1945b7579f77SDag-Erling Smørgrav c->cb_arg = callback_arg; 1946b7579f77SDag-Erling Smørgrav /* libevent stuff */ 1947b7579f77SDag-Erling Smørgrav if(writing) 1948b7579f77SDag-Erling Smørgrav evbits = EV_PERSIST | EV_WRITE; 1949b7579f77SDag-Erling Smørgrav else evbits = EV_PERSIST | EV_READ; 1950b7579f77SDag-Erling Smørgrav event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback, 1951b7579f77SDag-Erling Smørgrav c); 1952b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &c->ev->ev) != 0 || 1953b7579f77SDag-Erling Smørgrav event_add(&c->ev->ev, c->timeout) != 0 ) 1954b7579f77SDag-Erling Smørgrav { 1955b7579f77SDag-Erling Smørgrav log_err("could not add rawhdl event"); 1956b7579f77SDag-Erling Smørgrav free(c->ev); 1957b7579f77SDag-Erling Smørgrav free(c); 1958b7579f77SDag-Erling Smørgrav return NULL; 1959b7579f77SDag-Erling Smørgrav } 1960b7579f77SDag-Erling Smørgrav return c; 1961b7579f77SDag-Erling Smørgrav } 1962b7579f77SDag-Erling Smørgrav 1963b7579f77SDag-Erling Smørgrav void 1964b7579f77SDag-Erling Smørgrav comm_point_close(struct comm_point* c) 1965b7579f77SDag-Erling Smørgrav { 1966b7579f77SDag-Erling Smørgrav if(!c) 1967b7579f77SDag-Erling Smørgrav return; 1968b7579f77SDag-Erling Smørgrav if(c->fd != -1) 1969b7579f77SDag-Erling Smørgrav if(event_del(&c->ev->ev) != 0) { 1970b7579f77SDag-Erling Smørgrav log_err("could not event_del on close"); 1971b7579f77SDag-Erling Smørgrav } 1972b7579f77SDag-Erling Smørgrav /* close fd after removing from event lists, or epoll.. is messed up */ 1973b7579f77SDag-Erling Smørgrav if(c->fd != -1 && !c->do_not_close) { 1974b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "close fd %d", c->fd); 1975b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 1976b7579f77SDag-Erling Smørgrav close(c->fd); 1977b7579f77SDag-Erling Smørgrav #else 1978b7579f77SDag-Erling Smørgrav closesocket(c->fd); 1979b7579f77SDag-Erling Smørgrav #endif 1980b7579f77SDag-Erling Smørgrav } 1981b7579f77SDag-Erling Smørgrav c->fd = -1; 1982b7579f77SDag-Erling Smørgrav } 1983b7579f77SDag-Erling Smørgrav 1984b7579f77SDag-Erling Smørgrav void 1985b7579f77SDag-Erling Smørgrav comm_point_delete(struct comm_point* c) 1986b7579f77SDag-Erling Smørgrav { 1987b7579f77SDag-Erling Smørgrav if(!c) 1988b7579f77SDag-Erling Smørgrav return; 1989b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp && c->ssl) { 19908ed2b524SDag-Erling Smørgrav #ifdef HAVE_SSL 1991b7579f77SDag-Erling Smørgrav SSL_shutdown(c->ssl); 1992b7579f77SDag-Erling Smørgrav SSL_free(c->ssl); 19938ed2b524SDag-Erling Smørgrav #endif 1994b7579f77SDag-Erling Smørgrav } 1995b7579f77SDag-Erling Smørgrav comm_point_close(c); 1996b7579f77SDag-Erling Smørgrav if(c->tcp_handlers) { 1997b7579f77SDag-Erling Smørgrav int i; 1998b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++) 1999b7579f77SDag-Erling Smørgrav comm_point_delete(c->tcp_handlers[i]); 2000b7579f77SDag-Erling Smørgrav free(c->tcp_handlers); 2001b7579f77SDag-Erling Smørgrav } 2002b7579f77SDag-Erling Smørgrav free(c->timeout); 2003b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local) 200417d15b25SDag-Erling Smørgrav sldns_buffer_free(c->buffer); 2005b7579f77SDag-Erling Smørgrav free(c->ev); 2006b7579f77SDag-Erling Smørgrav free(c); 2007b7579f77SDag-Erling Smørgrav } 2008b7579f77SDag-Erling Smørgrav 2009b7579f77SDag-Erling Smørgrav void 2010b7579f77SDag-Erling Smørgrav comm_point_send_reply(struct comm_reply *repinfo) 2011b7579f77SDag-Erling Smørgrav { 2012b7579f77SDag-Erling Smørgrav log_assert(repinfo && repinfo->c); 2013b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp) { 2014b7579f77SDag-Erling Smørgrav if(repinfo->srctype) 2015b7579f77SDag-Erling Smørgrav comm_point_send_udp_msg_if(repinfo->c, 2016b7579f77SDag-Erling Smørgrav repinfo->c->buffer, (struct sockaddr*)&repinfo->addr, 2017b7579f77SDag-Erling Smørgrav repinfo->addrlen, repinfo); 2018b7579f77SDag-Erling Smørgrav else 2019b7579f77SDag-Erling Smørgrav comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer, 2020b7579f77SDag-Erling Smørgrav (struct sockaddr*)&repinfo->addr, repinfo->addrlen); 2021ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2022ff825849SDag-Erling Smørgrav if(repinfo->c->dtenv != NULL && 2023ff825849SDag-Erling Smørgrav repinfo->c->dtenv->log_client_response_messages) 2024ff825849SDag-Erling Smørgrav dt_msg_send_client_response(repinfo->c->dtenv, 2025ff825849SDag-Erling Smørgrav &repinfo->addr, repinfo->c->type, repinfo->c->buffer); 2026ff825849SDag-Erling Smørgrav #endif 2027b7579f77SDag-Erling Smørgrav } else { 2028ff825849SDag-Erling Smørgrav #ifdef USE_DNSTAP 2029ff825849SDag-Erling Smørgrav if(repinfo->c->tcp_parent->dtenv != NULL && 2030ff825849SDag-Erling Smørgrav repinfo->c->tcp_parent->dtenv->log_client_response_messages) 2031ff825849SDag-Erling Smørgrav dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv, 2032ff825849SDag-Erling Smørgrav &repinfo->addr, repinfo->c->type, repinfo->c->buffer); 2033ff825849SDag-Erling Smørgrav #endif 2034b7579f77SDag-Erling Smørgrav comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT); 2035b7579f77SDag-Erling Smørgrav } 2036b7579f77SDag-Erling Smørgrav } 2037b7579f77SDag-Erling Smørgrav 2038b7579f77SDag-Erling Smørgrav void 2039b7579f77SDag-Erling Smørgrav comm_point_drop_reply(struct comm_reply* repinfo) 2040b7579f77SDag-Erling Smørgrav { 2041b7579f77SDag-Erling Smørgrav if(!repinfo) 2042b7579f77SDag-Erling Smørgrav return; 2043b7579f77SDag-Erling Smørgrav log_assert(repinfo && repinfo->c); 2044b7579f77SDag-Erling Smørgrav log_assert(repinfo->c->type != comm_tcp_accept); 2045b7579f77SDag-Erling Smørgrav if(repinfo->c->type == comm_udp) 2046b7579f77SDag-Erling Smørgrav return; 2047b7579f77SDag-Erling Smørgrav reclaim_tcp_handler(repinfo->c); 2048b7579f77SDag-Erling Smørgrav } 2049b7579f77SDag-Erling Smørgrav 2050b7579f77SDag-Erling Smørgrav void 2051b7579f77SDag-Erling Smørgrav comm_point_stop_listening(struct comm_point* c) 2052b7579f77SDag-Erling Smørgrav { 2053b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point stop listening %d", c->fd); 2054b7579f77SDag-Erling Smørgrav if(event_del(&c->ev->ev) != 0) { 2055b7579f77SDag-Erling Smørgrav log_err("event_del error to stoplisten"); 2056b7579f77SDag-Erling Smørgrav } 2057b7579f77SDag-Erling Smørgrav } 2058b7579f77SDag-Erling Smørgrav 2059b7579f77SDag-Erling Smørgrav void 2060b7579f77SDag-Erling Smørgrav comm_point_start_listening(struct comm_point* c, int newfd, int sec) 2061b7579f77SDag-Erling Smørgrav { 2062b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point start listening %d", 2063b7579f77SDag-Erling Smørgrav c->fd==-1?newfd:c->fd); 2064b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept && !c->tcp_free) { 2065b7579f77SDag-Erling Smørgrav /* no use to start listening no free slots. */ 2066b7579f77SDag-Erling Smørgrav return; 2067b7579f77SDag-Erling Smørgrav } 2068b7579f77SDag-Erling Smørgrav if(sec != -1 && sec != 0) { 2069b7579f77SDag-Erling Smørgrav if(!c->timeout) { 2070b7579f77SDag-Erling Smørgrav c->timeout = (struct timeval*)malloc(sizeof( 2071b7579f77SDag-Erling Smørgrav struct timeval)); 2072b7579f77SDag-Erling Smørgrav if(!c->timeout) { 2073b7579f77SDag-Erling Smørgrav log_err("cpsl: malloc failed. No net read."); 2074b7579f77SDag-Erling Smørgrav return; 2075b7579f77SDag-Erling Smørgrav } 2076b7579f77SDag-Erling Smørgrav } 2077b7579f77SDag-Erling Smørgrav c->ev->ev.ev_events |= EV_TIMEOUT; 2078b7579f77SDag-Erling Smørgrav #ifndef S_SPLINT_S /* splint fails on struct timeval. */ 2079b7579f77SDag-Erling Smørgrav c->timeout->tv_sec = sec; 2080b7579f77SDag-Erling Smørgrav c->timeout->tv_usec = 0; 2081b7579f77SDag-Erling Smørgrav #endif /* S_SPLINT_S */ 2082b7579f77SDag-Erling Smørgrav } 2083b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp) { 2084b7579f77SDag-Erling Smørgrav c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE); 2085b7579f77SDag-Erling Smørgrav if(c->tcp_is_reading) 2086b7579f77SDag-Erling Smørgrav c->ev->ev.ev_events |= EV_READ; 2087b7579f77SDag-Erling Smørgrav else c->ev->ev.ev_events |= EV_WRITE; 2088b7579f77SDag-Erling Smørgrav } 2089b7579f77SDag-Erling Smørgrav if(newfd != -1) { 2090b7579f77SDag-Erling Smørgrav if(c->fd != -1) { 2091b7579f77SDag-Erling Smørgrav #ifndef USE_WINSOCK 2092b7579f77SDag-Erling Smørgrav close(c->fd); 2093b7579f77SDag-Erling Smørgrav #else 2094b7579f77SDag-Erling Smørgrav closesocket(c->fd); 2095b7579f77SDag-Erling Smørgrav #endif 2096b7579f77SDag-Erling Smørgrav } 2097b7579f77SDag-Erling Smørgrav c->fd = newfd; 2098b7579f77SDag-Erling Smørgrav c->ev->ev.ev_fd = c->fd; 2099b7579f77SDag-Erling Smørgrav } 2100b7579f77SDag-Erling Smørgrav if(event_add(&c->ev->ev, sec==0?NULL:c->timeout) != 0) { 2101b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cpsl."); 2102b7579f77SDag-Erling Smørgrav } 2103b7579f77SDag-Erling Smørgrav } 2104b7579f77SDag-Erling Smørgrav 2105b7579f77SDag-Erling Smørgrav void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr) 2106b7579f77SDag-Erling Smørgrav { 2107b7579f77SDag-Erling Smørgrav verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr); 2108b7579f77SDag-Erling Smørgrav if(event_del(&c->ev->ev) != 0) { 2109b7579f77SDag-Erling Smørgrav log_err("event_del error to cplf"); 2110b7579f77SDag-Erling Smørgrav } 2111b7579f77SDag-Erling Smørgrav c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE); 2112b7579f77SDag-Erling Smørgrav if(rd) c->ev->ev.ev_events |= EV_READ; 2113b7579f77SDag-Erling Smørgrav if(wr) c->ev->ev.ev_events |= EV_WRITE; 2114b7579f77SDag-Erling Smørgrav if(event_add(&c->ev->ev, c->timeout) != 0) { 2115b7579f77SDag-Erling Smørgrav log_err("event_add failed. in cplf."); 2116b7579f77SDag-Erling Smørgrav } 2117b7579f77SDag-Erling Smørgrav } 2118b7579f77SDag-Erling Smørgrav 2119b7579f77SDag-Erling Smørgrav size_t comm_point_get_mem(struct comm_point* c) 2120b7579f77SDag-Erling Smørgrav { 2121b7579f77SDag-Erling Smørgrav size_t s; 2122b7579f77SDag-Erling Smørgrav if(!c) 2123b7579f77SDag-Erling Smørgrav return 0; 2124b7579f77SDag-Erling Smørgrav s = sizeof(*c) + sizeof(*c->ev); 2125b7579f77SDag-Erling Smørgrav if(c->timeout) 2126b7579f77SDag-Erling Smørgrav s += sizeof(*c->timeout); 2127b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp || c->type == comm_local) 212817d15b25SDag-Erling Smørgrav s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer); 2129b7579f77SDag-Erling Smørgrav if(c->type == comm_tcp_accept) { 2130b7579f77SDag-Erling Smørgrav int i; 2131b7579f77SDag-Erling Smørgrav for(i=0; i<c->max_tcp_count; i++) 2132b7579f77SDag-Erling Smørgrav s += comm_point_get_mem(c->tcp_handlers[i]); 2133b7579f77SDag-Erling Smørgrav } 2134b7579f77SDag-Erling Smørgrav return s; 2135b7579f77SDag-Erling Smørgrav } 2136b7579f77SDag-Erling Smørgrav 2137b7579f77SDag-Erling Smørgrav struct comm_timer* 2138b7579f77SDag-Erling Smørgrav comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg) 2139b7579f77SDag-Erling Smørgrav { 2140b7579f77SDag-Erling Smørgrav struct comm_timer *tm = (struct comm_timer*)calloc(1, 2141b7579f77SDag-Erling Smørgrav sizeof(struct comm_timer)); 2142b7579f77SDag-Erling Smørgrav if(!tm) 2143b7579f77SDag-Erling Smørgrav return NULL; 2144b7579f77SDag-Erling Smørgrav tm->ev_timer = (struct internal_timer*)calloc(1, 2145b7579f77SDag-Erling Smørgrav sizeof(struct internal_timer)); 2146b7579f77SDag-Erling Smørgrav if(!tm->ev_timer) { 2147b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2148b7579f77SDag-Erling Smørgrav free(tm); 2149b7579f77SDag-Erling Smørgrav return NULL; 2150b7579f77SDag-Erling Smørgrav } 2151b7579f77SDag-Erling Smørgrav tm->ev_timer->base = base; 2152b7579f77SDag-Erling Smørgrav tm->callback = cb; 2153b7579f77SDag-Erling Smørgrav tm->cb_arg = cb_arg; 2154b7579f77SDag-Erling Smørgrav event_set(&tm->ev_timer->ev, -1, EV_TIMEOUT, 2155b7579f77SDag-Erling Smørgrav comm_timer_callback, tm); 2156b7579f77SDag-Erling Smørgrav if(event_base_set(base->eb->base, &tm->ev_timer->ev) != 0) { 2157b7579f77SDag-Erling Smørgrav log_err("timer_create: event_base_set failed."); 2158b7579f77SDag-Erling Smørgrav free(tm->ev_timer); 2159b7579f77SDag-Erling Smørgrav free(tm); 2160b7579f77SDag-Erling Smørgrav return NULL; 2161b7579f77SDag-Erling Smørgrav } 2162b7579f77SDag-Erling Smørgrav return tm; 2163b7579f77SDag-Erling Smørgrav } 2164b7579f77SDag-Erling Smørgrav 2165b7579f77SDag-Erling Smørgrav void 2166b7579f77SDag-Erling Smørgrav comm_timer_disable(struct comm_timer* timer) 2167b7579f77SDag-Erling Smørgrav { 2168b7579f77SDag-Erling Smørgrav if(!timer) 2169b7579f77SDag-Erling Smørgrav return; 2170b7579f77SDag-Erling Smørgrav evtimer_del(&timer->ev_timer->ev); 2171b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 0; 2172b7579f77SDag-Erling Smørgrav } 2173b7579f77SDag-Erling Smørgrav 2174b7579f77SDag-Erling Smørgrav void 2175b7579f77SDag-Erling Smørgrav comm_timer_set(struct comm_timer* timer, struct timeval* tv) 2176b7579f77SDag-Erling Smørgrav { 2177b7579f77SDag-Erling Smørgrav log_assert(tv); 2178b7579f77SDag-Erling Smørgrav if(timer->ev_timer->enabled) 2179b7579f77SDag-Erling Smørgrav comm_timer_disable(timer); 2180b7579f77SDag-Erling Smørgrav event_set(&timer->ev_timer->ev, -1, EV_TIMEOUT, 2181b7579f77SDag-Erling Smørgrav comm_timer_callback, timer); 2182b7579f77SDag-Erling Smørgrav if(event_base_set(timer->ev_timer->base->eb->base, 2183b7579f77SDag-Erling Smørgrav &timer->ev_timer->ev) != 0) 2184b7579f77SDag-Erling Smørgrav log_err("comm_timer_set: set_base failed."); 2185b7579f77SDag-Erling Smørgrav if(evtimer_add(&timer->ev_timer->ev, tv) != 0) 2186b7579f77SDag-Erling Smørgrav log_err("comm_timer_set: evtimer_add failed."); 2187b7579f77SDag-Erling Smørgrav timer->ev_timer->enabled = 1; 2188b7579f77SDag-Erling Smørgrav } 2189b7579f77SDag-Erling Smørgrav 2190b7579f77SDag-Erling Smørgrav void 2191b7579f77SDag-Erling Smørgrav comm_timer_delete(struct comm_timer* timer) 2192b7579f77SDag-Erling Smørgrav { 2193b7579f77SDag-Erling Smørgrav if(!timer) 2194b7579f77SDag-Erling Smørgrav return; 2195b7579f77SDag-Erling Smørgrav comm_timer_disable(timer); 2196b7579f77SDag-Erling Smørgrav free(timer->ev_timer); 2197b7579f77SDag-Erling Smørgrav free(timer); 2198b7579f77SDag-Erling Smørgrav } 2199b7579f77SDag-Erling Smørgrav 2200b7579f77SDag-Erling Smørgrav void 2201b7579f77SDag-Erling Smørgrav comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg) 2202b7579f77SDag-Erling Smørgrav { 2203b7579f77SDag-Erling Smørgrav struct comm_timer* tm = (struct comm_timer*)arg; 2204b7579f77SDag-Erling Smørgrav if(!(event&EV_TIMEOUT)) 2205b7579f77SDag-Erling Smørgrav return; 2206b7579f77SDag-Erling Smørgrav comm_base_now(tm->ev_timer->base); 2207b7579f77SDag-Erling Smørgrav tm->ev_timer->enabled = 0; 2208b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_timer(tm->callback)); 2209b7579f77SDag-Erling Smørgrav (*tm->callback)(tm->cb_arg); 2210b7579f77SDag-Erling Smørgrav } 2211b7579f77SDag-Erling Smørgrav 2212b7579f77SDag-Erling Smørgrav int 2213b7579f77SDag-Erling Smørgrav comm_timer_is_set(struct comm_timer* timer) 2214b7579f77SDag-Erling Smørgrav { 2215b7579f77SDag-Erling Smørgrav return (int)timer->ev_timer->enabled; 2216b7579f77SDag-Erling Smørgrav } 2217b7579f77SDag-Erling Smørgrav 2218b7579f77SDag-Erling Smørgrav size_t 2219b7579f77SDag-Erling Smørgrav comm_timer_get_mem(struct comm_timer* timer) 2220b7579f77SDag-Erling Smørgrav { 2221b7579f77SDag-Erling Smørgrav return sizeof(*timer) + sizeof(struct internal_timer); 2222b7579f77SDag-Erling Smørgrav } 2223b7579f77SDag-Erling Smørgrav 2224b7579f77SDag-Erling Smørgrav struct comm_signal* 2225b7579f77SDag-Erling Smørgrav comm_signal_create(struct comm_base* base, 2226b7579f77SDag-Erling Smørgrav void (*callback)(int, void*), void* cb_arg) 2227b7579f77SDag-Erling Smørgrav { 2228b7579f77SDag-Erling Smørgrav struct comm_signal* com = (struct comm_signal*)malloc( 2229b7579f77SDag-Erling Smørgrav sizeof(struct comm_signal)); 2230b7579f77SDag-Erling Smørgrav if(!com) { 2231b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2232b7579f77SDag-Erling Smørgrav return NULL; 2233b7579f77SDag-Erling Smørgrav } 2234b7579f77SDag-Erling Smørgrav com->base = base; 2235b7579f77SDag-Erling Smørgrav com->callback = callback; 2236b7579f77SDag-Erling Smørgrav com->cb_arg = cb_arg; 2237b7579f77SDag-Erling Smørgrav com->ev_signal = NULL; 2238b7579f77SDag-Erling Smørgrav return com; 2239b7579f77SDag-Erling Smørgrav } 2240b7579f77SDag-Erling Smørgrav 2241b7579f77SDag-Erling Smørgrav void 2242b7579f77SDag-Erling Smørgrav comm_signal_callback(int sig, short event, void* arg) 2243b7579f77SDag-Erling Smørgrav { 2244b7579f77SDag-Erling Smørgrav struct comm_signal* comsig = (struct comm_signal*)arg; 2245b7579f77SDag-Erling Smørgrav if(!(event & EV_SIGNAL)) 2246b7579f77SDag-Erling Smørgrav return; 2247b7579f77SDag-Erling Smørgrav comm_base_now(comsig->base); 2248b7579f77SDag-Erling Smørgrav fptr_ok(fptr_whitelist_comm_signal(comsig->callback)); 2249b7579f77SDag-Erling Smørgrav (*comsig->callback)(sig, comsig->cb_arg); 2250b7579f77SDag-Erling Smørgrav } 2251b7579f77SDag-Erling Smørgrav 2252b7579f77SDag-Erling Smørgrav int 2253b7579f77SDag-Erling Smørgrav comm_signal_bind(struct comm_signal* comsig, int sig) 2254b7579f77SDag-Erling Smørgrav { 2255b7579f77SDag-Erling Smørgrav struct internal_signal* entry = (struct internal_signal*)calloc(1, 2256b7579f77SDag-Erling Smørgrav sizeof(struct internal_signal)); 2257b7579f77SDag-Erling Smørgrav if(!entry) { 2258b7579f77SDag-Erling Smørgrav log_err("malloc failed"); 2259b7579f77SDag-Erling Smørgrav return 0; 2260b7579f77SDag-Erling Smørgrav } 2261b7579f77SDag-Erling Smørgrav log_assert(comsig); 2262b7579f77SDag-Erling Smørgrav /* add signal event */ 2263b7579f77SDag-Erling Smørgrav signal_set(&entry->ev, sig, comm_signal_callback, comsig); 2264b7579f77SDag-Erling Smørgrav if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) { 2265b7579f77SDag-Erling Smørgrav log_err("Could not set signal base"); 2266b7579f77SDag-Erling Smørgrav free(entry); 2267b7579f77SDag-Erling Smørgrav return 0; 2268b7579f77SDag-Erling Smørgrav } 2269b7579f77SDag-Erling Smørgrav if(signal_add(&entry->ev, NULL) != 0) { 2270b7579f77SDag-Erling Smørgrav log_err("Could not add signal handler"); 2271b7579f77SDag-Erling Smørgrav free(entry); 2272b7579f77SDag-Erling Smørgrav return 0; 2273b7579f77SDag-Erling Smørgrav } 2274b7579f77SDag-Erling Smørgrav /* link into list */ 2275b7579f77SDag-Erling Smørgrav entry->next = comsig->ev_signal; 2276b7579f77SDag-Erling Smørgrav comsig->ev_signal = entry; 2277b7579f77SDag-Erling Smørgrav return 1; 2278b7579f77SDag-Erling Smørgrav } 2279b7579f77SDag-Erling Smørgrav 2280b7579f77SDag-Erling Smørgrav void 2281b7579f77SDag-Erling Smørgrav comm_signal_delete(struct comm_signal* comsig) 2282b7579f77SDag-Erling Smørgrav { 2283b7579f77SDag-Erling Smørgrav struct internal_signal* p, *np; 2284b7579f77SDag-Erling Smørgrav if(!comsig) 2285b7579f77SDag-Erling Smørgrav return; 2286b7579f77SDag-Erling Smørgrav p=comsig->ev_signal; 2287b7579f77SDag-Erling Smørgrav while(p) { 2288b7579f77SDag-Erling Smørgrav np = p->next; 2289b7579f77SDag-Erling Smørgrav signal_del(&p->ev); 2290b7579f77SDag-Erling Smørgrav free(p); 2291b7579f77SDag-Erling Smørgrav p = np; 2292b7579f77SDag-Erling Smørgrav } 2293b7579f77SDag-Erling Smørgrav free(comsig); 2294b7579f77SDag-Erling Smørgrav } 2295