1275970Scy/* 2275970Scy * Copyright (c) 2009-2012 Niels Provos, Nick Mathewson 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 3. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy */ 26275970Scy 27275970Scy#include "event2/event-config.h" 28275970Scy#include "evconfig-private.h" 29275970Scy 30275970Scy#include <sys/types.h> 31275970Scy 32275970Scy#ifdef _WIN32 33275970Scy#ifndef _WIN32_WINNT 34275970Scy/* Minimum required for InitializeCriticalSectionAndSpinCount */ 35275970Scy#define _WIN32_WINNT 0x0403 36275970Scy#endif 37275970Scy#include <winsock2.h> 38275970Scy#include <ws2tcpip.h> 39275970Scy#include <mswsock.h> 40275970Scy#endif 41275970Scy#include <errno.h> 42275970Scy#ifdef EVENT__HAVE_SYS_SOCKET_H 43275970Scy#include <sys/socket.h> 44275970Scy#endif 45275970Scy#ifdef EVENT__HAVE_FCNTL_H 46275970Scy#include <fcntl.h> 47275970Scy#endif 48275970Scy#ifdef EVENT__HAVE_UNISTD_H 49275970Scy#include <unistd.h> 50275970Scy#endif 51275970Scy 52275970Scy#include "event2/listener.h" 53275970Scy#include "event2/util.h" 54275970Scy#include "event2/event.h" 55275970Scy#include "event2/event_struct.h" 56275970Scy#include "mm-internal.h" 57275970Scy#include "util-internal.h" 58275970Scy#include "log-internal.h" 59275970Scy#include "evthread-internal.h" 60275970Scy#ifdef _WIN32 61275970Scy#include "iocp-internal.h" 62275970Scy#include "defer-internal.h" 63275970Scy#include "event-internal.h" 64275970Scy#endif 65275970Scy 66275970Scystruct evconnlistener_ops { 67275970Scy int (*enable)(struct evconnlistener *); 68275970Scy int (*disable)(struct evconnlistener *); 69275970Scy void (*destroy)(struct evconnlistener *); 70275970Scy void (*shutdown)(struct evconnlistener *); 71275970Scy evutil_socket_t (*getfd)(struct evconnlistener *); 72275970Scy struct event_base *(*getbase)(struct evconnlistener *); 73275970Scy}; 74275970Scy 75275970Scystruct evconnlistener { 76275970Scy const struct evconnlistener_ops *ops; 77275970Scy void *lock; 78275970Scy evconnlistener_cb cb; 79275970Scy evconnlistener_errorcb errorcb; 80275970Scy void *user_data; 81275970Scy unsigned flags; 82275970Scy short refcnt; 83275970Scy int accept4_flags; 84275970Scy unsigned enabled : 1; 85275970Scy}; 86275970Scy 87275970Scystruct evconnlistener_event { 88275970Scy struct evconnlistener base; 89275970Scy struct event listener; 90275970Scy}; 91275970Scy 92275970Scy#ifdef _WIN32 93275970Scystruct evconnlistener_iocp { 94275970Scy struct evconnlistener base; 95275970Scy evutil_socket_t fd; 96275970Scy struct event_base *event_base; 97275970Scy struct event_iocp_port *port; 98275970Scy short n_accepting; 99275970Scy unsigned shutting_down : 1; 100275970Scy unsigned event_added : 1; 101275970Scy struct accepting_socket **accepting; 102275970Scy}; 103275970Scy#endif 104275970Scy 105275970Scy#define LOCK(listener) EVLOCK_LOCK((listener)->lock, 0) 106275970Scy#define UNLOCK(listener) EVLOCK_UNLOCK((listener)->lock, 0) 107275970Scy 108275970Scystruct evconnlistener * 109275970Scyevconnlistener_new_async(struct event_base *base, 110275970Scy evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, 111275970Scy evutil_socket_t fd); /* XXXX export this? */ 112275970Scy 113275970Scystatic int event_listener_enable(struct evconnlistener *); 114275970Scystatic int event_listener_disable(struct evconnlistener *); 115275970Scystatic void event_listener_destroy(struct evconnlistener *); 116275970Scystatic evutil_socket_t event_listener_getfd(struct evconnlistener *); 117275970Scystatic struct event_base *event_listener_getbase(struct evconnlistener *); 118275970Scy 119275970Scy#if 0 120275970Scystatic void 121275970Scylistener_incref_and_lock(struct evconnlistener *listener) 122275970Scy{ 123275970Scy LOCK(listener); 124275970Scy ++listener->refcnt; 125275970Scy} 126275970Scy#endif 127275970Scy 128275970Scystatic int 129275970Scylistener_decref_and_unlock(struct evconnlistener *listener) 130275970Scy{ 131275970Scy int refcnt = --listener->refcnt; 132275970Scy if (refcnt == 0) { 133275970Scy listener->ops->destroy(listener); 134275970Scy UNLOCK(listener); 135275970Scy EVTHREAD_FREE_LOCK(listener->lock, EVTHREAD_LOCKTYPE_RECURSIVE); 136275970Scy mm_free(listener); 137275970Scy return 1; 138275970Scy } else { 139275970Scy UNLOCK(listener); 140275970Scy return 0; 141275970Scy } 142275970Scy} 143275970Scy 144275970Scystatic const struct evconnlistener_ops evconnlistener_event_ops = { 145275970Scy event_listener_enable, 146275970Scy event_listener_disable, 147275970Scy event_listener_destroy, 148275970Scy NULL, /* shutdown */ 149275970Scy event_listener_getfd, 150275970Scy event_listener_getbase 151275970Scy}; 152275970Scy 153275970Scystatic void listener_read_cb(evutil_socket_t, short, void *); 154275970Scy 155275970Scystruct evconnlistener * 156275970Scyevconnlistener_new(struct event_base *base, 157275970Scy evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, 158275970Scy evutil_socket_t fd) 159275970Scy{ 160275970Scy struct evconnlistener_event *lev; 161275970Scy 162275970Scy#ifdef _WIN32 163275970Scy if (base && event_base_get_iocp_(base)) { 164275970Scy const struct win32_extension_fns *ext = 165275970Scy event_get_win32_extension_fns_(); 166275970Scy if (ext->AcceptEx && ext->GetAcceptExSockaddrs) 167275970Scy return evconnlistener_new_async(base, cb, ptr, flags, 168275970Scy backlog, fd); 169275970Scy } 170275970Scy#endif 171275970Scy 172275970Scy if (backlog > 0) { 173275970Scy if (listen(fd, backlog) < 0) 174275970Scy return NULL; 175275970Scy } else if (backlog < 0) { 176275970Scy if (listen(fd, 128) < 0) 177275970Scy return NULL; 178275970Scy } 179275970Scy 180275970Scy lev = mm_calloc(1, sizeof(struct evconnlistener_event)); 181275970Scy if (!lev) 182275970Scy return NULL; 183275970Scy 184275970Scy lev->base.ops = &evconnlistener_event_ops; 185275970Scy lev->base.cb = cb; 186275970Scy lev->base.user_data = ptr; 187275970Scy lev->base.flags = flags; 188275970Scy lev->base.refcnt = 1; 189275970Scy 190275970Scy lev->base.accept4_flags = 0; 191275970Scy if (!(flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING)) 192275970Scy lev->base.accept4_flags |= EVUTIL_SOCK_NONBLOCK; 193275970Scy if (flags & LEV_OPT_CLOSE_ON_EXEC) 194275970Scy lev->base.accept4_flags |= EVUTIL_SOCK_CLOEXEC; 195275970Scy 196275970Scy if (flags & LEV_OPT_THREADSAFE) { 197275970Scy EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 198275970Scy } 199275970Scy 200275970Scy event_assign(&lev->listener, base, fd, EV_READ|EV_PERSIST, 201275970Scy listener_read_cb, lev); 202275970Scy 203275970Scy if (!(flags & LEV_OPT_DISABLED)) 204275970Scy evconnlistener_enable(&lev->base); 205275970Scy 206275970Scy return &lev->base; 207275970Scy} 208275970Scy 209275970Scystruct evconnlistener * 210275970Scyevconnlistener_new_bind(struct event_base *base, evconnlistener_cb cb, 211275970Scy void *ptr, unsigned flags, int backlog, const struct sockaddr *sa, 212275970Scy int socklen) 213275970Scy{ 214275970Scy struct evconnlistener *listener; 215275970Scy evutil_socket_t fd; 216275970Scy int on = 1; 217275970Scy int family = sa ? sa->sa_family : AF_UNSPEC; 218275970Scy int socktype = SOCK_STREAM | EVUTIL_SOCK_NONBLOCK; 219275970Scy 220275970Scy if (backlog == 0) 221275970Scy return NULL; 222275970Scy 223275970Scy if (flags & LEV_OPT_CLOSE_ON_EXEC) 224275970Scy socktype |= EVUTIL_SOCK_CLOEXEC; 225275970Scy 226275970Scy fd = evutil_socket_(family, socktype, 0); 227275970Scy if (fd == -1) 228275970Scy return NULL; 229275970Scy 230275970Scy if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))<0) 231275970Scy goto err; 232275970Scy 233275970Scy if (flags & LEV_OPT_REUSEABLE) { 234275970Scy if (evutil_make_listen_socket_reuseable(fd) < 0) 235275970Scy goto err; 236275970Scy } 237275970Scy 238285612Sdelphij if (flags & LEV_OPT_REUSEABLE_PORT) { 239285612Sdelphij if (evutil_make_listen_socket_reuseable_port(fd) < 0) 240285612Sdelphij goto err; 241285612Sdelphij } 242285612Sdelphij 243275970Scy if (flags & LEV_OPT_DEFERRED_ACCEPT) { 244275970Scy if (evutil_make_tcp_listen_socket_deferred(fd) < 0) 245275970Scy goto err; 246275970Scy } 247275970Scy 248275970Scy if (sa) { 249275970Scy if (bind(fd, sa, socklen)<0) 250275970Scy goto err; 251275970Scy } 252275970Scy 253275970Scy listener = evconnlistener_new(base, cb, ptr, flags, backlog, fd); 254275970Scy if (!listener) 255275970Scy goto err; 256275970Scy 257275970Scy return listener; 258275970Scyerr: 259275970Scy evutil_closesocket(fd); 260275970Scy return NULL; 261275970Scy} 262275970Scy 263275970Scyvoid 264275970Scyevconnlistener_free(struct evconnlistener *lev) 265275970Scy{ 266275970Scy LOCK(lev); 267275970Scy lev->cb = NULL; 268275970Scy lev->errorcb = NULL; 269275970Scy if (lev->ops->shutdown) 270275970Scy lev->ops->shutdown(lev); 271275970Scy listener_decref_and_unlock(lev); 272275970Scy} 273275970Scy 274275970Scystatic void 275275970Scyevent_listener_destroy(struct evconnlistener *lev) 276275970Scy{ 277275970Scy struct evconnlistener_event *lev_e = 278275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_event, base); 279275970Scy 280275970Scy event_del(&lev_e->listener); 281275970Scy if (lev->flags & LEV_OPT_CLOSE_ON_FREE) 282275970Scy evutil_closesocket(event_get_fd(&lev_e->listener)); 283275970Scy event_debug_unassign(&lev_e->listener); 284275970Scy} 285275970Scy 286275970Scyint 287275970Scyevconnlistener_enable(struct evconnlistener *lev) 288275970Scy{ 289275970Scy int r; 290275970Scy LOCK(lev); 291275970Scy lev->enabled = 1; 292275970Scy if (lev->cb) 293275970Scy r = lev->ops->enable(lev); 294275970Scy else 295275970Scy r = 0; 296275970Scy UNLOCK(lev); 297275970Scy return r; 298275970Scy} 299275970Scy 300275970Scyint 301275970Scyevconnlistener_disable(struct evconnlistener *lev) 302275970Scy{ 303275970Scy int r; 304275970Scy LOCK(lev); 305275970Scy lev->enabled = 0; 306275970Scy r = lev->ops->disable(lev); 307275970Scy UNLOCK(lev); 308275970Scy return r; 309275970Scy} 310275970Scy 311275970Scystatic int 312275970Scyevent_listener_enable(struct evconnlistener *lev) 313275970Scy{ 314275970Scy struct evconnlistener_event *lev_e = 315275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_event, base); 316275970Scy return event_add(&lev_e->listener, NULL); 317275970Scy} 318275970Scy 319275970Scystatic int 320275970Scyevent_listener_disable(struct evconnlistener *lev) 321275970Scy{ 322275970Scy struct evconnlistener_event *lev_e = 323275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_event, base); 324275970Scy return event_del(&lev_e->listener); 325275970Scy} 326275970Scy 327275970Scyevutil_socket_t 328275970Scyevconnlistener_get_fd(struct evconnlistener *lev) 329275970Scy{ 330275970Scy evutil_socket_t fd; 331275970Scy LOCK(lev); 332275970Scy fd = lev->ops->getfd(lev); 333275970Scy UNLOCK(lev); 334275970Scy return fd; 335275970Scy} 336275970Scy 337275970Scystatic evutil_socket_t 338275970Scyevent_listener_getfd(struct evconnlistener *lev) 339275970Scy{ 340275970Scy struct evconnlistener_event *lev_e = 341275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_event, base); 342275970Scy return event_get_fd(&lev_e->listener); 343275970Scy} 344275970Scy 345275970Scystruct event_base * 346275970Scyevconnlistener_get_base(struct evconnlistener *lev) 347275970Scy{ 348275970Scy struct event_base *base; 349275970Scy LOCK(lev); 350275970Scy base = lev->ops->getbase(lev); 351275970Scy UNLOCK(lev); 352275970Scy return base; 353275970Scy} 354275970Scy 355275970Scystatic struct event_base * 356275970Scyevent_listener_getbase(struct evconnlistener *lev) 357275970Scy{ 358275970Scy struct evconnlistener_event *lev_e = 359275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_event, base); 360275970Scy return event_get_base(&lev_e->listener); 361275970Scy} 362275970Scy 363275970Scyvoid 364275970Scyevconnlistener_set_cb(struct evconnlistener *lev, 365275970Scy evconnlistener_cb cb, void *arg) 366275970Scy{ 367275970Scy int enable = 0; 368275970Scy LOCK(lev); 369275970Scy if (lev->enabled && !lev->cb) 370275970Scy enable = 1; 371275970Scy lev->cb = cb; 372275970Scy lev->user_data = arg; 373275970Scy if (enable) 374275970Scy evconnlistener_enable(lev); 375275970Scy UNLOCK(lev); 376275970Scy} 377275970Scy 378275970Scyvoid 379275970Scyevconnlistener_set_error_cb(struct evconnlistener *lev, 380275970Scy evconnlistener_errorcb errorcb) 381275970Scy{ 382275970Scy LOCK(lev); 383275970Scy lev->errorcb = errorcb; 384275970Scy UNLOCK(lev); 385275970Scy} 386275970Scy 387275970Scystatic void 388275970Scylistener_read_cb(evutil_socket_t fd, short what, void *p) 389275970Scy{ 390275970Scy struct evconnlistener *lev = p; 391275970Scy int err; 392275970Scy evconnlistener_cb cb; 393275970Scy evconnlistener_errorcb errorcb; 394275970Scy void *user_data; 395275970Scy LOCK(lev); 396275970Scy while (1) { 397275970Scy struct sockaddr_storage ss; 398275970Scy ev_socklen_t socklen = sizeof(ss); 399275970Scy evutil_socket_t new_fd = evutil_accept4_(fd, (struct sockaddr*)&ss, &socklen, lev->accept4_flags); 400275970Scy if (new_fd < 0) 401275970Scy break; 402275970Scy if (socklen == 0) { 403275970Scy /* This can happen with some older linux kernels in 404275970Scy * response to nmap. */ 405275970Scy evutil_closesocket(new_fd); 406275970Scy continue; 407275970Scy } 408275970Scy 409275970Scy if (lev->cb == NULL) { 410275970Scy evutil_closesocket(new_fd); 411275970Scy UNLOCK(lev); 412275970Scy return; 413275970Scy } 414275970Scy ++lev->refcnt; 415275970Scy cb = lev->cb; 416275970Scy user_data = lev->user_data; 417275970Scy UNLOCK(lev); 418275970Scy cb(lev, new_fd, (struct sockaddr*)&ss, (int)socklen, 419275970Scy user_data); 420275970Scy LOCK(lev); 421275970Scy if (lev->refcnt == 1) { 422275970Scy int freed = listener_decref_and_unlock(lev); 423275970Scy EVUTIL_ASSERT(freed); 424285612Sdelphij 425285612Sdelphij evutil_closesocket(new_fd); 426275970Scy return; 427275970Scy } 428275970Scy --lev->refcnt; 429275970Scy } 430275970Scy err = evutil_socket_geterror(fd); 431275970Scy if (EVUTIL_ERR_ACCEPT_RETRIABLE(err)) { 432275970Scy UNLOCK(lev); 433275970Scy return; 434275970Scy } 435275970Scy if (lev->errorcb != NULL) { 436275970Scy ++lev->refcnt; 437275970Scy errorcb = lev->errorcb; 438275970Scy user_data = lev->user_data; 439275970Scy UNLOCK(lev); 440275970Scy errorcb(lev, user_data); 441275970Scy LOCK(lev); 442275970Scy listener_decref_and_unlock(lev); 443275970Scy } else { 444275970Scy event_sock_warn(fd, "Error from accept() call"); 445275970Scy } 446275970Scy} 447275970Scy 448275970Scy#ifdef _WIN32 449275970Scystruct accepting_socket { 450275970Scy CRITICAL_SECTION lock; 451275970Scy struct event_overlapped overlapped; 452275970Scy SOCKET s; 453275970Scy int error; 454275970Scy struct event_callback deferred; 455275970Scy struct evconnlistener_iocp *lev; 456275970Scy ev_uint8_t buflen; 457275970Scy ev_uint8_t family; 458275970Scy unsigned free_on_cb:1; 459275970Scy char addrbuf[1]; 460275970Scy}; 461275970Scy 462275970Scystatic void accepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, 463275970Scy ev_ssize_t n, int ok); 464275970Scystatic void accepted_socket_invoke_user_cb(struct event_callback *cb, void *arg); 465275970Scy 466275970Scystatic void 467275970Scyiocp_listener_event_add(struct evconnlistener_iocp *lev) 468275970Scy{ 469275970Scy if (lev->event_added) 470275970Scy return; 471275970Scy 472275970Scy lev->event_added = 1; 473275970Scy event_base_add_virtual_(lev->event_base); 474275970Scy} 475275970Scy 476275970Scystatic void 477275970Scyiocp_listener_event_del(struct evconnlistener_iocp *lev) 478275970Scy{ 479275970Scy if (!lev->event_added) 480275970Scy return; 481275970Scy 482275970Scy lev->event_added = 0; 483275970Scy event_base_del_virtual_(lev->event_base); 484275970Scy} 485275970Scy 486275970Scystatic struct accepting_socket * 487275970Scynew_accepting_socket(struct evconnlistener_iocp *lev, int family) 488275970Scy{ 489275970Scy struct accepting_socket *res; 490275970Scy int addrlen; 491275970Scy int buflen; 492275970Scy 493275970Scy if (family == AF_INET) 494275970Scy addrlen = sizeof(struct sockaddr_in); 495275970Scy else if (family == AF_INET6) 496275970Scy addrlen = sizeof(struct sockaddr_in6); 497275970Scy else 498275970Scy return NULL; 499275970Scy buflen = (addrlen+16)*2; 500275970Scy 501275970Scy res = mm_calloc(1,sizeof(struct accepting_socket)-1+buflen); 502275970Scy if (!res) 503275970Scy return NULL; 504275970Scy 505275970Scy event_overlapped_init_(&res->overlapped, accepted_socket_cb); 506275970Scy res->s = INVALID_SOCKET; 507275970Scy res->lev = lev; 508275970Scy res->buflen = buflen; 509275970Scy res->family = family; 510275970Scy 511275970Scy event_deferred_cb_init_(&res->deferred, 512275970Scy event_base_get_npriorities(lev->event_base) / 2, 513275970Scy accepted_socket_invoke_user_cb, res); 514275970Scy 515275970Scy InitializeCriticalSectionAndSpinCount(&res->lock, 1000); 516275970Scy 517275970Scy return res; 518275970Scy} 519275970Scy 520275970Scystatic void 521275970Scyfree_and_unlock_accepting_socket(struct accepting_socket *as) 522275970Scy{ 523275970Scy /* requires lock. */ 524275970Scy if (as->s != INVALID_SOCKET) 525275970Scy closesocket(as->s); 526275970Scy 527275970Scy LeaveCriticalSection(&as->lock); 528275970Scy DeleteCriticalSection(&as->lock); 529275970Scy mm_free(as); 530275970Scy} 531275970Scy 532275970Scystatic int 533275970Scystart_accepting(struct accepting_socket *as) 534275970Scy{ 535275970Scy /* requires lock */ 536275970Scy const struct win32_extension_fns *ext = event_get_win32_extension_fns_(); 537275970Scy DWORD pending = 0; 538275970Scy SOCKET s = socket(as->family, SOCK_STREAM, 0); 539275970Scy int error = 0; 540275970Scy 541275970Scy if (!as->lev->base.enabled) 542275970Scy return 0; 543275970Scy 544275970Scy if (s == INVALID_SOCKET) { 545275970Scy error = WSAGetLastError(); 546275970Scy goto report_err; 547275970Scy } 548275970Scy 549275970Scy /* XXXX It turns out we need to do this again later. Does this call 550275970Scy * have any effect? */ 551275970Scy setsockopt(s, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 552275970Scy (char *)&as->lev->fd, sizeof(&as->lev->fd)); 553275970Scy 554275970Scy if (!(as->lev->base.flags & LEV_OPT_LEAVE_SOCKETS_BLOCKING)) 555275970Scy evutil_make_socket_nonblocking(s); 556275970Scy 557275970Scy if (event_iocp_port_associate_(as->lev->port, s, 1) < 0) { 558275970Scy closesocket(s); 559275970Scy return -1; 560275970Scy } 561275970Scy 562275970Scy as->s = s; 563275970Scy 564275970Scy if (ext->AcceptEx(as->lev->fd, s, as->addrbuf, 0, 565275970Scy as->buflen/2, as->buflen/2, &pending, &as->overlapped.overlapped)) 566275970Scy { 567275970Scy /* Immediate success! */ 568275970Scy accepted_socket_cb(&as->overlapped, 1, 0, 1); 569275970Scy } else { 570275970Scy error = WSAGetLastError(); 571275970Scy if (error != ERROR_IO_PENDING) { 572275970Scy goto report_err; 573275970Scy } 574275970Scy } 575275970Scy 576275970Scy return 0; 577275970Scy 578275970Scyreport_err: 579275970Scy as->error = error; 580275970Scy event_deferred_cb_schedule_( 581275970Scy as->lev->event_base, 582275970Scy &as->deferred); 583275970Scy return 0; 584275970Scy} 585275970Scy 586275970Scystatic void 587275970Scystop_accepting(struct accepting_socket *as) 588275970Scy{ 589275970Scy /* requires lock. */ 590275970Scy SOCKET s = as->s; 591275970Scy as->s = INVALID_SOCKET; 592275970Scy closesocket(s); 593275970Scy} 594275970Scy 595275970Scystatic void 596275970Scyaccepted_socket_invoke_user_cb(struct event_callback *dcb, void *arg) 597275970Scy{ 598275970Scy struct accepting_socket *as = arg; 599275970Scy 600275970Scy struct sockaddr *sa_local=NULL, *sa_remote=NULL; 601275970Scy int socklen_local=0, socklen_remote=0; 602275970Scy const struct win32_extension_fns *ext = event_get_win32_extension_fns_(); 603275970Scy struct evconnlistener *lev = &as->lev->base; 604275970Scy evutil_socket_t sock=-1; 605275970Scy void *data; 606275970Scy evconnlistener_cb cb=NULL; 607275970Scy evconnlistener_errorcb errorcb=NULL; 608275970Scy int error; 609275970Scy 610275970Scy EVUTIL_ASSERT(ext->GetAcceptExSockaddrs); 611275970Scy 612275970Scy LOCK(lev); 613275970Scy EnterCriticalSection(&as->lock); 614275970Scy if (as->free_on_cb) { 615275970Scy free_and_unlock_accepting_socket(as); 616275970Scy listener_decref_and_unlock(lev); 617275970Scy return; 618275970Scy } 619275970Scy 620275970Scy ++lev->refcnt; 621275970Scy 622275970Scy error = as->error; 623275970Scy if (error) { 624275970Scy as->error = 0; 625275970Scy errorcb = lev->errorcb; 626275970Scy } else { 627275970Scy ext->GetAcceptExSockaddrs( 628275970Scy as->addrbuf, 0, as->buflen/2, as->buflen/2, 629275970Scy &sa_local, &socklen_local, &sa_remote, 630275970Scy &socklen_remote); 631275970Scy sock = as->s; 632275970Scy cb = lev->cb; 633275970Scy as->s = INVALID_SOCKET; 634275970Scy 635275970Scy /* We need to call this so getsockname, getpeername, and 636275970Scy * shutdown work correctly on the accepted socket. */ 637275970Scy /* XXXX handle error? */ 638275970Scy setsockopt(sock, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT, 639275970Scy (char *)&as->lev->fd, sizeof(&as->lev->fd)); 640275970Scy } 641275970Scy data = lev->user_data; 642275970Scy 643275970Scy LeaveCriticalSection(&as->lock); 644275970Scy UNLOCK(lev); 645275970Scy 646275970Scy if (errorcb) { 647275970Scy WSASetLastError(error); 648275970Scy errorcb(lev, data); 649275970Scy } else if (cb) { 650275970Scy cb(lev, sock, sa_remote, socklen_remote, data); 651275970Scy } 652275970Scy 653275970Scy LOCK(lev); 654275970Scy if (listener_decref_and_unlock(lev)) 655275970Scy return; 656275970Scy 657275970Scy EnterCriticalSection(&as->lock); 658275970Scy start_accepting(as); 659275970Scy LeaveCriticalSection(&as->lock); 660275970Scy} 661275970Scy 662275970Scystatic void 663275970Scyaccepted_socket_cb(struct event_overlapped *o, ev_uintptr_t key, ev_ssize_t n, int ok) 664275970Scy{ 665275970Scy struct accepting_socket *as = 666275970Scy EVUTIL_UPCAST(o, struct accepting_socket, overlapped); 667275970Scy 668275970Scy LOCK(&as->lev->base); 669275970Scy EnterCriticalSection(&as->lock); 670275970Scy if (ok) { 671275970Scy /* XXXX Don't do this if some EV_MT flag is set. */ 672275970Scy event_deferred_cb_schedule_( 673275970Scy as->lev->event_base, 674275970Scy &as->deferred); 675275970Scy LeaveCriticalSection(&as->lock); 676275970Scy } else if (as->free_on_cb) { 677275970Scy struct evconnlistener *lev = &as->lev->base; 678275970Scy free_and_unlock_accepting_socket(as); 679275970Scy listener_decref_and_unlock(lev); 680275970Scy return; 681275970Scy } else if (as->s == INVALID_SOCKET) { 682275970Scy /* This is okay; we were disabled by iocp_listener_disable. */ 683275970Scy LeaveCriticalSection(&as->lock); 684275970Scy } else { 685275970Scy /* Some error on accept that we couldn't actually handle. */ 686275970Scy BOOL ok; 687275970Scy DWORD transfer = 0, flags=0; 688275970Scy event_sock_warn(as->s, "Unexpected error on AcceptEx"); 689275970Scy ok = WSAGetOverlappedResult(as->s, &o->overlapped, 690275970Scy &transfer, FALSE, &flags); 691275970Scy if (ok) { 692275970Scy /* well, that was confusing! */ 693275970Scy as->error = 1; 694275970Scy } else { 695275970Scy as->error = WSAGetLastError(); 696275970Scy } 697275970Scy event_deferred_cb_schedule_( 698275970Scy as->lev->event_base, 699275970Scy &as->deferred); 700275970Scy LeaveCriticalSection(&as->lock); 701275970Scy } 702275970Scy UNLOCK(&as->lev->base); 703275970Scy} 704275970Scy 705275970Scystatic int 706275970Scyiocp_listener_enable(struct evconnlistener *lev) 707275970Scy{ 708275970Scy int i; 709275970Scy struct evconnlistener_iocp *lev_iocp = 710275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base); 711275970Scy 712275970Scy LOCK(lev); 713275970Scy iocp_listener_event_add(lev_iocp); 714275970Scy for (i = 0; i < lev_iocp->n_accepting; ++i) { 715275970Scy struct accepting_socket *as = lev_iocp->accepting[i]; 716275970Scy if (!as) 717275970Scy continue; 718275970Scy EnterCriticalSection(&as->lock); 719275970Scy if (!as->free_on_cb && as->s == INVALID_SOCKET) 720275970Scy start_accepting(as); 721275970Scy LeaveCriticalSection(&as->lock); 722275970Scy } 723275970Scy UNLOCK(lev); 724275970Scy return 0; 725275970Scy} 726275970Scy 727275970Scystatic int 728275970Scyiocp_listener_disable_impl(struct evconnlistener *lev, int shutdown) 729275970Scy{ 730275970Scy int i; 731275970Scy struct evconnlistener_iocp *lev_iocp = 732275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base); 733275970Scy 734275970Scy LOCK(lev); 735275970Scy iocp_listener_event_del(lev_iocp); 736275970Scy for (i = 0; i < lev_iocp->n_accepting; ++i) { 737275970Scy struct accepting_socket *as = lev_iocp->accepting[i]; 738275970Scy if (!as) 739275970Scy continue; 740275970Scy EnterCriticalSection(&as->lock); 741275970Scy if (!as->free_on_cb && as->s != INVALID_SOCKET) { 742275970Scy if (shutdown) 743275970Scy as->free_on_cb = 1; 744275970Scy stop_accepting(as); 745275970Scy } 746275970Scy LeaveCriticalSection(&as->lock); 747275970Scy } 748275970Scy 749275970Scy if (shutdown && lev->flags & LEV_OPT_CLOSE_ON_FREE) 750275970Scy evutil_closesocket(lev_iocp->fd); 751275970Scy 752275970Scy UNLOCK(lev); 753275970Scy return 0; 754275970Scy} 755275970Scy 756275970Scystatic int 757275970Scyiocp_listener_disable(struct evconnlistener *lev) 758275970Scy{ 759275970Scy return iocp_listener_disable_impl(lev,0); 760275970Scy} 761275970Scy 762275970Scystatic void 763275970Scyiocp_listener_destroy(struct evconnlistener *lev) 764275970Scy{ 765275970Scy struct evconnlistener_iocp *lev_iocp = 766275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base); 767275970Scy 768275970Scy if (! lev_iocp->shutting_down) { 769275970Scy lev_iocp->shutting_down = 1; 770275970Scy iocp_listener_disable_impl(lev,1); 771275970Scy } 772275970Scy 773275970Scy} 774275970Scy 775275970Scystatic evutil_socket_t 776275970Scyiocp_listener_getfd(struct evconnlistener *lev) 777275970Scy{ 778275970Scy struct evconnlistener_iocp *lev_iocp = 779275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base); 780275970Scy return lev_iocp->fd; 781275970Scy} 782275970Scystatic struct event_base * 783275970Scyiocp_listener_getbase(struct evconnlistener *lev) 784275970Scy{ 785275970Scy struct evconnlistener_iocp *lev_iocp = 786275970Scy EVUTIL_UPCAST(lev, struct evconnlistener_iocp, base); 787275970Scy return lev_iocp->event_base; 788275970Scy} 789275970Scy 790275970Scystatic const struct evconnlistener_ops evconnlistener_iocp_ops = { 791275970Scy iocp_listener_enable, 792275970Scy iocp_listener_disable, 793275970Scy iocp_listener_destroy, 794275970Scy iocp_listener_destroy, /* shutdown */ 795275970Scy iocp_listener_getfd, 796275970Scy iocp_listener_getbase 797275970Scy}; 798275970Scy 799275970Scy/* XXX define some way to override this. */ 800275970Scy#define N_SOCKETS_PER_LISTENER 4 801275970Scy 802275970Scystruct evconnlistener * 803275970Scyevconnlistener_new_async(struct event_base *base, 804275970Scy evconnlistener_cb cb, void *ptr, unsigned flags, int backlog, 805275970Scy evutil_socket_t fd) 806275970Scy{ 807275970Scy struct sockaddr_storage ss; 808275970Scy int socklen = sizeof(ss); 809275970Scy struct evconnlistener_iocp *lev; 810275970Scy int i; 811275970Scy 812275970Scy flags |= LEV_OPT_THREADSAFE; 813275970Scy 814275970Scy if (!base || !event_base_get_iocp_(base)) 815275970Scy goto err; 816275970Scy 817275970Scy /* XXXX duplicate code */ 818275970Scy if (backlog > 0) { 819275970Scy if (listen(fd, backlog) < 0) 820275970Scy goto err; 821275970Scy } else if (backlog < 0) { 822275970Scy if (listen(fd, 128) < 0) 823275970Scy goto err; 824275970Scy } 825275970Scy if (getsockname(fd, (struct sockaddr*)&ss, &socklen)) { 826275970Scy event_sock_warn(fd, "getsockname"); 827275970Scy goto err; 828275970Scy } 829275970Scy lev = mm_calloc(1, sizeof(struct evconnlistener_iocp)); 830275970Scy if (!lev) { 831275970Scy event_warn("calloc"); 832275970Scy goto err; 833275970Scy } 834275970Scy lev->base.ops = &evconnlistener_iocp_ops; 835275970Scy lev->base.cb = cb; 836275970Scy lev->base.user_data = ptr; 837275970Scy lev->base.flags = flags; 838275970Scy lev->base.refcnt = 1; 839275970Scy lev->base.enabled = 1; 840275970Scy 841275970Scy lev->port = event_base_get_iocp_(base); 842275970Scy lev->fd = fd; 843275970Scy lev->event_base = base; 844275970Scy 845275970Scy 846275970Scy if (event_iocp_port_associate_(lev->port, fd, 1) < 0) 847275970Scy goto err_free_lev; 848275970Scy 849275970Scy EVTHREAD_ALLOC_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 850275970Scy 851275970Scy lev->n_accepting = N_SOCKETS_PER_LISTENER; 852275970Scy lev->accepting = mm_calloc(lev->n_accepting, 853275970Scy sizeof(struct accepting_socket *)); 854275970Scy if (!lev->accepting) { 855275970Scy event_warn("calloc"); 856275970Scy goto err_delete_lock; 857275970Scy } 858275970Scy for (i = 0; i < lev->n_accepting; ++i) { 859275970Scy lev->accepting[i] = new_accepting_socket(lev, ss.ss_family); 860275970Scy if (!lev->accepting[i]) { 861275970Scy event_warnx("Couldn't create accepting socket"); 862275970Scy goto err_free_accepting; 863275970Scy } 864275970Scy if (cb && start_accepting(lev->accepting[i]) < 0) { 865275970Scy event_warnx("Couldn't start accepting on socket"); 866275970Scy EnterCriticalSection(&lev->accepting[i]->lock); 867275970Scy free_and_unlock_accepting_socket(lev->accepting[i]); 868275970Scy goto err_free_accepting; 869275970Scy } 870275970Scy ++lev->base.refcnt; 871275970Scy } 872275970Scy 873275970Scy iocp_listener_event_add(lev); 874275970Scy 875275970Scy return &lev->base; 876275970Scy 877275970Scyerr_free_accepting: 878275970Scy mm_free(lev->accepting); 879275970Scy /* XXXX free the other elements. */ 880275970Scyerr_delete_lock: 881275970Scy EVTHREAD_FREE_LOCK(lev->base.lock, EVTHREAD_LOCKTYPE_RECURSIVE); 882275970Scyerr_free_lev: 883275970Scy mm_free(lev); 884275970Scyerr: 885275970Scy /* Don't close the fd, it is caller's responsibility. */ 886275970Scy return NULL; 887275970Scy} 888275970Scy 889275970Scy#endif 890