1 /* $NetBSD: bufferevent_sock.c,v 1.1.1.3 2017/01/31 21:14:52 christos Exp $ */ 2 /* 3 * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 4 * Copyright (c) 2002-2006 Niels Provos <provos@citi.umich.edu> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "event2/event-config.h" 31 #include <sys/cdefs.h> 32 __RCSID("$NetBSD: bufferevent_sock.c,v 1.1.1.3 2017/01/31 21:14:52 christos Exp $"); 33 #include "evconfig-private.h" 34 35 #include <sys/types.h> 36 37 #ifdef EVENT__HAVE_SYS_TIME_H 38 #include <sys/time.h> 39 #endif 40 41 #include <errno.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #ifdef EVENT__HAVE_STDARG_H 46 #include <stdarg.h> 47 #endif 48 #ifdef EVENT__HAVE_UNISTD_H 49 #include <unistd.h> 50 #endif 51 52 #ifdef _WIN32 53 #include <winsock2.h> 54 #include <ws2tcpip.h> 55 #endif 56 57 #ifdef EVENT__HAVE_SYS_SOCKET_H 58 #include <sys/socket.h> 59 #endif 60 #ifdef EVENT__HAVE_NETINET_IN_H 61 #include <netinet/in.h> 62 #endif 63 #ifdef EVENT__HAVE_NETINET_IN6_H 64 #include <netinet/in6.h> 65 #endif 66 67 #include "event2/util.h" 68 #include "event2/bufferevent.h" 69 #include "event2/buffer.h" 70 #include "event2/bufferevent_struct.h" 71 #include "event2/bufferevent_compat.h" 72 #include "event2/event.h" 73 #include "log-internal.h" 74 #include "mm-internal.h" 75 #include "bufferevent-internal.h" 76 #include "util-internal.h" 77 #ifdef _WIN32 78 #include "iocp-internal.h" 79 #endif 80 81 /* prototypes */ 82 static int be_socket_enable(struct bufferevent *, short); 83 static int be_socket_disable(struct bufferevent *, short); 84 static void be_socket_destruct(struct bufferevent *); 85 static int be_socket_flush(struct bufferevent *, short, enum bufferevent_flush_mode); 86 static int be_socket_ctrl(struct bufferevent *, enum bufferevent_ctrl_op, union bufferevent_ctrl_data *); 87 88 static void be_socket_setfd(struct bufferevent *, evutil_socket_t); 89 90 const struct bufferevent_ops bufferevent_ops_socket = { 91 "socket", 92 evutil_offsetof(struct bufferevent_private, bev), 93 be_socket_enable, 94 be_socket_disable, 95 NULL, /* unlink */ 96 be_socket_destruct, 97 bufferevent_generic_adj_existing_timeouts_, 98 be_socket_flush, 99 be_socket_ctrl, 100 }; 101 102 const struct sockaddr* 103 bufferevent_socket_get_conn_address_(struct bufferevent *bev) 104 { 105 struct bufferevent_private *bev_p = 106 EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 107 108 return (struct sockaddr *)&bev_p->conn_address; 109 } 110 static void 111 bufferevent_socket_set_conn_address_fd(struct bufferevent_private *bev_p, int fd) 112 { 113 socklen_t len = sizeof(bev_p->conn_address); 114 115 struct sockaddr *addr = (struct sockaddr *)&bev_p->conn_address; 116 if (addr->sa_family != AF_UNSPEC) 117 getpeername(fd, addr, &len); 118 } 119 static void 120 bufferevent_socket_set_conn_address(struct bufferevent_private *bev_p, 121 struct sockaddr *addr, size_t addrlen) 122 { 123 EVUTIL_ASSERT(addrlen <= sizeof(bev_p->conn_address)); 124 memcpy(&bev_p->conn_address, addr, addrlen); 125 } 126 127 static void 128 bufferevent_socket_outbuf_cb(struct evbuffer *buf, 129 const struct evbuffer_cb_info *cbinfo, 130 void *arg) 131 { 132 struct bufferevent *bufev = arg; 133 struct bufferevent_private *bufev_p = 134 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 135 136 if (cbinfo->n_added && 137 (bufev->enabled & EV_WRITE) && 138 !event_pending(&bufev->ev_write, EV_WRITE, NULL) && 139 !bufev_p->write_suspended) { 140 /* Somebody added data to the buffer, and we would like to 141 * write, and we were not writing. So, start writing. */ 142 if (bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) { 143 /* Should we log this? */ 144 } 145 } 146 } 147 148 static void 149 bufferevent_readcb(evutil_socket_t fd, short event, void *arg) 150 { 151 struct bufferevent *bufev = arg; 152 struct bufferevent_private *bufev_p = 153 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 154 struct evbuffer *input; 155 int res = 0; 156 short what = BEV_EVENT_READING; 157 ev_ssize_t howmuch = -1, readmax=-1; 158 159 bufferevent_incref_and_lock_(bufev); 160 161 if (event == EV_TIMEOUT) { 162 /* Note that we only check for event==EV_TIMEOUT. If 163 * event==EV_TIMEOUT|EV_READ, we can safely ignore the 164 * timeout, since a read has occurred */ 165 what |= BEV_EVENT_TIMEOUT; 166 goto error; 167 } 168 169 input = bufev->input; 170 171 /* 172 * If we have a high watermark configured then we don't want to 173 * read more data than would make us reach the watermark. 174 */ 175 if (bufev->wm_read.high != 0) { 176 howmuch = bufev->wm_read.high - evbuffer_get_length(input); 177 /* we somehow lowered the watermark, stop reading */ 178 if (howmuch <= 0) { 179 bufferevent_wm_suspend_read(bufev); 180 goto done; 181 } 182 } 183 readmax = bufferevent_get_read_max_(bufev_p); 184 if (howmuch < 0 || howmuch > readmax) /* The use of -1 for "unlimited" 185 * uglifies this code. XXXX */ 186 howmuch = readmax; 187 if (bufev_p->read_suspended) 188 goto done; 189 190 evbuffer_unfreeze(input, 0); 191 res = evbuffer_read(input, fd, (int)howmuch); /* XXXX evbuffer_read would do better to take and return ev_ssize_t */ 192 evbuffer_freeze(input, 0); 193 194 if (res == -1) { 195 int err = evutil_socket_geterror(fd); 196 if (EVUTIL_ERR_RW_RETRIABLE(err)) 197 goto reschedule; 198 if (EVUTIL_ERR_CONNECT_REFUSED(err)) { 199 bufev_p->connection_refused = 1; 200 goto done; 201 } 202 /* error case */ 203 what |= BEV_EVENT_ERROR; 204 } else if (res == 0) { 205 /* eof case */ 206 what |= BEV_EVENT_EOF; 207 } 208 209 if (res <= 0) 210 goto error; 211 212 bufferevent_decrement_read_buckets_(bufev_p, res); 213 214 /* Invoke the user callback - must always be called last */ 215 bufferevent_trigger_nolock_(bufev, EV_READ, 0); 216 217 goto done; 218 219 reschedule: 220 goto done; 221 222 error: 223 bufferevent_disable(bufev, EV_READ); 224 bufferevent_run_eventcb_(bufev, what, 0); 225 226 done: 227 bufferevent_decref_and_unlock_(bufev); 228 } 229 230 static void 231 bufferevent_writecb(evutil_socket_t fd, short event, void *arg) 232 { 233 struct bufferevent *bufev = arg; 234 struct bufferevent_private *bufev_p = 235 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 236 int res = 0; 237 short what = BEV_EVENT_WRITING; 238 int connected = 0; 239 ev_ssize_t atmost = -1; 240 241 bufferevent_incref_and_lock_(bufev); 242 243 if (event == EV_TIMEOUT) { 244 /* Note that we only check for event==EV_TIMEOUT. If 245 * event==EV_TIMEOUT|EV_WRITE, we can safely ignore the 246 * timeout, since a read has occurred */ 247 what |= BEV_EVENT_TIMEOUT; 248 goto error; 249 } 250 if (bufev_p->connecting) { 251 int c = evutil_socket_finished_connecting_(fd); 252 /* we need to fake the error if the connection was refused 253 * immediately - usually connection to localhost on BSD */ 254 if (bufev_p->connection_refused) { 255 bufev_p->connection_refused = 0; 256 c = -1; 257 } 258 259 if (c == 0) 260 goto done; 261 262 bufev_p->connecting = 0; 263 if (c < 0) { 264 event_del(&bufev->ev_write); 265 event_del(&bufev->ev_read); 266 bufferevent_run_eventcb_(bufev, BEV_EVENT_ERROR, 0); 267 goto done; 268 } else { 269 connected = 1; 270 bufferevent_socket_set_conn_address_fd(bufev_p, fd); 271 #ifdef _WIN32 272 if (BEV_IS_ASYNC(bufev)) { 273 event_del(&bufev->ev_write); 274 bufferevent_async_set_connected_(bufev); 275 bufferevent_run_eventcb_(bufev, 276 BEV_EVENT_CONNECTED, 0); 277 goto done; 278 } 279 #endif 280 bufferevent_run_eventcb_(bufev, 281 BEV_EVENT_CONNECTED, 0); 282 if (!(bufev->enabled & EV_WRITE) || 283 bufev_p->write_suspended) { 284 event_del(&bufev->ev_write); 285 goto done; 286 } 287 } 288 } 289 290 atmost = bufferevent_get_write_max_(bufev_p); 291 292 if (bufev_p->write_suspended) 293 goto done; 294 295 if (evbuffer_get_length(bufev->output)) { 296 evbuffer_unfreeze(bufev->output, 1); 297 res = evbuffer_write_atmost(bufev->output, fd, atmost); 298 evbuffer_freeze(bufev->output, 1); 299 if (res == -1) { 300 int err = evutil_socket_geterror(fd); 301 if (EVUTIL_ERR_RW_RETRIABLE(err)) 302 goto reschedule; 303 what |= BEV_EVENT_ERROR; 304 } else if (res == 0) { 305 /* eof case 306 XXXX Actually, a 0 on write doesn't indicate 307 an EOF. An ECONNRESET might be more typical. 308 */ 309 what |= BEV_EVENT_EOF; 310 } 311 if (res <= 0) 312 goto error; 313 314 bufferevent_decrement_write_buckets_(bufev_p, res); 315 } 316 317 if (evbuffer_get_length(bufev->output) == 0) { 318 event_del(&bufev->ev_write); 319 } 320 321 /* 322 * Invoke the user callback if our buffer is drained or below the 323 * low watermark. 324 */ 325 if (res || !connected) { 326 bufferevent_trigger_nolock_(bufev, EV_WRITE, 0); 327 } 328 329 goto done; 330 331 reschedule: 332 if (evbuffer_get_length(bufev->output) == 0) { 333 event_del(&bufev->ev_write); 334 } 335 goto done; 336 337 error: 338 bufferevent_disable(bufev, EV_WRITE); 339 bufferevent_run_eventcb_(bufev, what, 0); 340 341 done: 342 bufferevent_decref_and_unlock_(bufev); 343 } 344 345 struct bufferevent * 346 bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, 347 int options) 348 { 349 struct bufferevent_private *bufev_p; 350 struct bufferevent *bufev; 351 352 #ifdef _WIN32 353 if (base && event_base_get_iocp_(base)) 354 return bufferevent_async_new_(base, fd, options); 355 #endif 356 357 if ((bufev_p = mm_calloc(1, sizeof(struct bufferevent_private)))== NULL) 358 return NULL; 359 360 if (bufferevent_init_common_(bufev_p, base, &bufferevent_ops_socket, 361 options) < 0) { 362 mm_free(bufev_p); 363 return NULL; 364 } 365 bufev = &bufev_p->bev; 366 evbuffer_set_flags(bufev->output, EVBUFFER_FLAG_DRAINS_TO_FD); 367 368 event_assign(&bufev->ev_read, bufev->ev_base, fd, 369 EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); 370 event_assign(&bufev->ev_write, bufev->ev_base, fd, 371 EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); 372 373 evbuffer_add_cb(bufev->output, bufferevent_socket_outbuf_cb, bufev); 374 375 evbuffer_freeze(bufev->input, 0); 376 evbuffer_freeze(bufev->output, 1); 377 378 return bufev; 379 } 380 381 int 382 bufferevent_socket_connect(struct bufferevent *bev, 383 const struct sockaddr *sa, int socklen) 384 { 385 struct bufferevent_private *bufev_p = 386 EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 387 388 evutil_socket_t fd; 389 int r = 0; 390 int result=-1; 391 int ownfd = 0; 392 393 bufferevent_incref_and_lock_(bev); 394 395 if (!bufev_p) 396 goto done; 397 398 fd = bufferevent_getfd(bev); 399 if (fd < 0) { 400 if (!sa) 401 goto done; 402 fd = evutil_socket_(sa->sa_family, 403 SOCK_STREAM|EVUTIL_SOCK_NONBLOCK, 0); 404 if (fd < 0) 405 goto done; 406 ownfd = 1; 407 } 408 if (sa) { 409 #ifdef _WIN32 410 if (bufferevent_async_can_connect_(bev)) { 411 bufferevent_setfd(bev, fd); 412 r = bufferevent_async_connect_(bev, fd, sa, socklen); 413 if (r < 0) 414 goto freesock; 415 bufev_p->connecting = 1; 416 result = 0; 417 goto done; 418 } else 419 #endif 420 r = evutil_socket_connect_(&fd, sa, socklen); 421 if (r < 0) 422 goto freesock; 423 } 424 #ifdef _WIN32 425 /* ConnectEx() isn't always around, even when IOCP is enabled. 426 * Here, we borrow the socket object's write handler to fall back 427 * on a non-blocking connect() when ConnectEx() is unavailable. */ 428 if (BEV_IS_ASYNC(bev)) { 429 event_assign(&bev->ev_write, bev->ev_base, fd, 430 EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bev); 431 } 432 #endif 433 bufferevent_setfd(bev, fd); 434 if (r == 0) { 435 if (! be_socket_enable(bev, EV_WRITE)) { 436 bufev_p->connecting = 1; 437 result = 0; 438 goto done; 439 } 440 } else if (r == 1) { 441 /* The connect succeeded already. How very BSD of it. */ 442 result = 0; 443 bufev_p->connecting = 1; 444 bufferevent_trigger_nolock_(bev, EV_WRITE, BEV_OPT_DEFER_CALLBACKS); 445 } else { 446 /* The connect failed already. How very BSD of it. */ 447 result = 0; 448 bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, BEV_OPT_DEFER_CALLBACKS); 449 bufferevent_disable(bev, EV_WRITE|EV_READ); 450 } 451 452 goto done; 453 454 freesock: 455 bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); 456 if (ownfd) 457 evutil_closesocket(fd); 458 /* do something about the error? */ 459 done: 460 bufferevent_decref_and_unlock_(bev); 461 return result; 462 } 463 464 static void 465 bufferevent_connect_getaddrinfo_cb(int result, struct evutil_addrinfo *ai, 466 void *arg) 467 { 468 struct bufferevent *bev = arg; 469 struct bufferevent_private *bev_p = 470 EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 471 int r; 472 BEV_LOCK(bev); 473 474 bufferevent_unsuspend_write_(bev, BEV_SUSPEND_LOOKUP); 475 bufferevent_unsuspend_read_(bev, BEV_SUSPEND_LOOKUP); 476 477 bev_p->dns_request = NULL; 478 479 if (result == EVUTIL_EAI_CANCEL) { 480 bev_p->dns_error = result; 481 bufferevent_decref_and_unlock_(bev); 482 return; 483 } 484 if (result != 0) { 485 bev_p->dns_error = result; 486 bufferevent_run_eventcb_(bev, BEV_EVENT_ERROR, 0); 487 bufferevent_decref_and_unlock_(bev); 488 if (ai) 489 evutil_freeaddrinfo(ai); 490 return; 491 } 492 493 /* XXX use the other addrinfos? */ 494 /* XXX use this return value */ 495 bufferevent_socket_set_conn_address(bev_p, ai->ai_addr, (int)ai->ai_addrlen); 496 r = bufferevent_socket_connect(bev, ai->ai_addr, (int)ai->ai_addrlen); 497 (void)r; 498 bufferevent_decref_and_unlock_(bev); 499 evutil_freeaddrinfo(ai); 500 } 501 502 int 503 bufferevent_socket_connect_hostname(struct bufferevent *bev, 504 struct evdns_base *evdns_base, int family, const char *hostname, int port) 505 { 506 char portbuf[10]; 507 struct evutil_addrinfo hint; 508 struct bufferevent_private *bev_p = 509 EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 510 511 if (family != AF_INET && family != AF_INET6 && family != AF_UNSPEC) 512 return -1; 513 if (port < 1 || port > 65535) 514 return -1; 515 516 memset(&hint, 0, sizeof(hint)); 517 hint.ai_family = family; 518 hint.ai_protocol = IPPROTO_TCP; 519 hint.ai_socktype = SOCK_STREAM; 520 521 evutil_snprintf(portbuf, sizeof(portbuf), "%d", port); 522 523 BEV_LOCK(bev); 524 bev_p->dns_error = 0; 525 526 bufferevent_suspend_write_(bev, BEV_SUSPEND_LOOKUP); 527 bufferevent_suspend_read_(bev, BEV_SUSPEND_LOOKUP); 528 529 bufferevent_incref_(bev); 530 bev_p->dns_request = evutil_getaddrinfo_async_(evdns_base, hostname, 531 portbuf, &hint, bufferevent_connect_getaddrinfo_cb, bev); 532 BEV_UNLOCK(bev); 533 534 return 0; 535 } 536 537 int 538 bufferevent_socket_get_dns_error(struct bufferevent *bev) 539 { 540 int rv; 541 struct bufferevent_private *bev_p = 542 EVUTIL_UPCAST(bev, struct bufferevent_private, bev); 543 544 BEV_LOCK(bev); 545 rv = bev_p->dns_error; 546 BEV_UNLOCK(bev); 547 548 return rv; 549 } 550 551 /* 552 * Create a new buffered event object. 553 * 554 * The read callback is invoked whenever we read new data. 555 * The write callback is invoked whenever the output buffer is drained. 556 * The error callback is invoked on a write/read error or on EOF. 557 * 558 * Both read and write callbacks maybe NULL. The error callback is not 559 * allowed to be NULL and have to be provided always. 560 */ 561 562 struct bufferevent * 563 bufferevent_new(evutil_socket_t fd, 564 bufferevent_data_cb readcb, bufferevent_data_cb writecb, 565 bufferevent_event_cb eventcb, void *cbarg) 566 { 567 struct bufferevent *bufev; 568 569 if (!(bufev = bufferevent_socket_new(NULL, fd, 0))) 570 return NULL; 571 572 bufferevent_setcb(bufev, readcb, writecb, eventcb, cbarg); 573 574 return bufev; 575 } 576 577 578 static int 579 be_socket_enable(struct bufferevent *bufev, short event) 580 { 581 if (event & EV_READ && 582 bufferevent_add_event_(&bufev->ev_read, &bufev->timeout_read) == -1) 583 return -1; 584 if (event & EV_WRITE && 585 bufferevent_add_event_(&bufev->ev_write, &bufev->timeout_write) == -1) 586 return -1; 587 return 0; 588 } 589 590 static int 591 be_socket_disable(struct bufferevent *bufev, short event) 592 { 593 struct bufferevent_private *bufev_p = 594 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 595 if (event & EV_READ) { 596 if (event_del(&bufev->ev_read) == -1) 597 return -1; 598 } 599 /* Don't actually disable the write if we are trying to connect. */ 600 if ((event & EV_WRITE) && ! bufev_p->connecting) { 601 if (event_del(&bufev->ev_write) == -1) 602 return -1; 603 } 604 return 0; 605 } 606 607 static void 608 be_socket_destruct(struct bufferevent *bufev) 609 { 610 struct bufferevent_private *bufev_p = 611 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 612 evutil_socket_t fd; 613 EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); 614 615 fd = event_get_fd(&bufev->ev_read); 616 617 if ((bufev_p->options & BEV_OPT_CLOSE_ON_FREE) && fd >= 0) 618 EVUTIL_CLOSESOCKET(fd); 619 620 evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); 621 } 622 623 static int 624 be_socket_flush(struct bufferevent *bev, short iotype, 625 enum bufferevent_flush_mode mode) 626 { 627 return 0; 628 } 629 630 631 static void 632 be_socket_setfd(struct bufferevent *bufev, evutil_socket_t fd) 633 { 634 struct bufferevent_private *bufev_p = 635 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 636 637 BEV_LOCK(bufev); 638 EVUTIL_ASSERT(bufev->be_ops == &bufferevent_ops_socket); 639 640 event_del(&bufev->ev_read); 641 event_del(&bufev->ev_write); 642 643 evbuffer_unfreeze(bufev->input, 0); 644 evbuffer_unfreeze(bufev->output, 1); 645 646 event_assign(&bufev->ev_read, bufev->ev_base, fd, 647 EV_READ|EV_PERSIST|EV_FINALIZE, bufferevent_readcb, bufev); 648 event_assign(&bufev->ev_write, bufev->ev_base, fd, 649 EV_WRITE|EV_PERSIST|EV_FINALIZE, bufferevent_writecb, bufev); 650 651 if (fd >= 0) 652 bufferevent_enable(bufev, bufev->enabled); 653 654 evutil_getaddrinfo_cancel_async_(bufev_p->dns_request); 655 656 BEV_UNLOCK(bufev); 657 } 658 659 /* XXXX Should non-socket bufferevents support this? */ 660 int 661 bufferevent_priority_set(struct bufferevent *bufev, int priority) 662 { 663 int r = -1; 664 struct bufferevent_private *bufev_p = 665 EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); 666 667 BEV_LOCK(bufev); 668 if (bufev->be_ops != &bufferevent_ops_socket) 669 goto done; 670 671 if (event_priority_set(&bufev->ev_read, priority) == -1) 672 goto done; 673 if (event_priority_set(&bufev->ev_write, priority) == -1) 674 goto done; 675 676 event_deferred_cb_set_priority_(&bufev_p->deferred, priority); 677 678 r = 0; 679 done: 680 BEV_UNLOCK(bufev); 681 return r; 682 } 683 684 /* XXXX Should non-socket bufferevents support this? */ 685 int 686 bufferevent_base_set(struct event_base *base, struct bufferevent *bufev) 687 { 688 int res = -1; 689 690 BEV_LOCK(bufev); 691 if (bufev->be_ops != &bufferevent_ops_socket) 692 goto done; 693 694 bufev->ev_base = base; 695 696 res = event_base_set(base, &bufev->ev_read); 697 if (res == -1) 698 goto done; 699 700 res = event_base_set(base, &bufev->ev_write); 701 done: 702 BEV_UNLOCK(bufev); 703 return res; 704 } 705 706 static int 707 be_socket_ctrl(struct bufferevent *bev, enum bufferevent_ctrl_op op, 708 union bufferevent_ctrl_data *data) 709 { 710 switch (op) { 711 case BEV_CTRL_SET_FD: 712 be_socket_setfd(bev, data->fd); 713 return 0; 714 case BEV_CTRL_GET_FD: 715 data->fd = event_get_fd(&bev->ev_read); 716 return 0; 717 case BEV_CTRL_GET_UNDERLYING: 718 case BEV_CTRL_CANCEL_ALL: 719 default: 720 return -1; 721 } 722 } 723