1/* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2013 Tatsuhiro Tsujikawa 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25#ifdef __sgi 26# define errx(exitcode, format, args...) \ 27 { \ 28 warnx(format, ##args); \ 29 exit(exitcode); \ 30 } 31# define warn(format, args...) warnx(format ": %s", ##args, strerror(errno)) 32# define warnx(format, args...) fprintf(stderr, format "\n", ##args) 33#endif 34 35#ifdef HAVE_CONFIG_H 36# include <config.h> 37#endif /* HAVE_CONFIG_H */ 38 39#include <sys/types.h> 40#ifdef HAVE_SYS_SOCKET_H 41# include <sys/socket.h> 42#endif /* HAVE_SYS_SOCKET_H */ 43#ifdef HAVE_NETDB_H 44# include <netdb.h> 45#endif /* HAVE_NETDB_H */ 46#include <signal.h> 47#ifdef HAVE_UNISTD_H 48# include <unistd.h> 49#endif /* HAVE_UNISTD_H */ 50#include <sys/stat.h> 51#ifdef HAVE_FCNTL_H 52# include <fcntl.h> 53#endif /* HAVE_FCNTL_H */ 54#include <ctype.h> 55#ifdef HAVE_NETINET_IN_H 56# include <netinet/in.h> 57#endif /* HAVE_NETINET_IN_H */ 58#include <netinet/tcp.h> 59#ifndef __sgi 60# include <err.h> 61#endif 62#include <string.h> 63#include <errno.h> 64 65#include <openssl/ssl.h> 66#include <openssl/err.h> 67#include <openssl/conf.h> 68 69#include <event.h> 70#include <event2/event.h> 71#include <event2/bufferevent_ssl.h> 72#include <event2/listener.h> 73 74#include <nghttp2/nghttp2.h> 75 76#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16) 77 78#define ARRLEN(x) (sizeof(x) / sizeof(x[0])) 79 80#define MAKE_NV(NAME, VALUE) \ 81 { \ 82 (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \ 83 NGHTTP2_NV_FLAG_NONE \ 84 } 85 86struct app_context; 87typedef struct app_context app_context; 88 89typedef struct http2_stream_data { 90 struct http2_stream_data *prev, *next; 91 char *request_path; 92 int32_t stream_id; 93 int fd; 94} http2_stream_data; 95 96typedef struct http2_session_data { 97 struct http2_stream_data root; 98 struct bufferevent *bev; 99 app_context *app_ctx; 100 nghttp2_session *session; 101 char *client_addr; 102} http2_session_data; 103 104struct app_context { 105 SSL_CTX *ssl_ctx; 106 struct event_base *evbase; 107}; 108 109static unsigned char next_proto_list[256]; 110static size_t next_proto_list_len; 111 112#ifndef OPENSSL_NO_NEXTPROTONEG 113static int next_proto_cb(SSL *ssl, const unsigned char **data, 114 unsigned int *len, void *arg) { 115 (void)ssl; 116 (void)arg; 117 118 *data = next_proto_list; 119 *len = (unsigned int)next_proto_list_len; 120 return SSL_TLSEXT_ERR_OK; 121} 122#endif /* !OPENSSL_NO_NEXTPROTONEG */ 123 124#if OPENSSL_VERSION_NUMBER >= 0x10002000L 125static int alpn_select_proto_cb(SSL *ssl, const unsigned char **out, 126 unsigned char *outlen, const unsigned char *in, 127 unsigned int inlen, void *arg) { 128 int rv; 129 (void)ssl; 130 (void)arg; 131 132 rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen); 133 134 if (rv != 1) { 135 return SSL_TLSEXT_ERR_NOACK; 136 } 137 138 return SSL_TLSEXT_ERR_OK; 139} 140#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ 141 142/* Create SSL_CTX. */ 143static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) { 144 SSL_CTX *ssl_ctx; 145 146 ssl_ctx = SSL_CTX_new(TLS_server_method()); 147 if (!ssl_ctx) { 148 errx(1, "Could not create SSL/TLS context: %s", 149 ERR_error_string(ERR_get_error(), NULL)); 150 } 151 SSL_CTX_set_options(ssl_ctx, 152 SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | 153 SSL_OP_NO_COMPRESSION | 154 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION); 155#if OPENSSL_VERSION_NUMBER >= 0x30000000L 156 if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) { 157 errx(1, "SSL_CTX_set1_curves_list failed: %s", 158 ERR_error_string(ERR_get_error(), NULL)); 159 } 160#else /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ 161 { 162 EC_KEY *ecdh; 163 ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 164 if (!ecdh) { 165 errx(1, "EC_KEY_new_by_curv_name failed: %s", 166 ERR_error_string(ERR_get_error(), NULL)); 167 } 168 SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh); 169 EC_KEY_free(ecdh); 170 } 171#endif /* !(OPENSSL_VERSION_NUMBER >= 0x30000000L) */ 172 173 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) { 174 errx(1, "Could not read private key file %s", key_file); 175 } 176 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) { 177 errx(1, "Could not read certificate file %s", cert_file); 178 } 179 180 next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN; 181 memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID, 182 NGHTTP2_PROTO_VERSION_ID_LEN); 183 next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN; 184 185#ifndef OPENSSL_NO_NEXTPROTONEG 186 SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL); 187#endif /* !OPENSSL_NO_NEXTPROTONEG */ 188 189#if OPENSSL_VERSION_NUMBER >= 0x10002000L 190 SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL); 191#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ 192 193 return ssl_ctx; 194} 195 196/* Create SSL object */ 197static SSL *create_ssl(SSL_CTX *ssl_ctx) { 198 SSL *ssl; 199 ssl = SSL_new(ssl_ctx); 200 if (!ssl) { 201 errx(1, "Could not create SSL/TLS session object: %s", 202 ERR_error_string(ERR_get_error(), NULL)); 203 } 204 return ssl; 205} 206 207static void add_stream(http2_session_data *session_data, 208 http2_stream_data *stream_data) { 209 stream_data->next = session_data->root.next; 210 session_data->root.next = stream_data; 211 stream_data->prev = &session_data->root; 212 if (stream_data->next) { 213 stream_data->next->prev = stream_data; 214 } 215} 216 217static void remove_stream(http2_session_data *session_data, 218 http2_stream_data *stream_data) { 219 (void)session_data; 220 221 stream_data->prev->next = stream_data->next; 222 if (stream_data->next) { 223 stream_data->next->prev = stream_data->prev; 224 } 225} 226 227static http2_stream_data * 228create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) { 229 http2_stream_data *stream_data; 230 stream_data = malloc(sizeof(http2_stream_data)); 231 memset(stream_data, 0, sizeof(http2_stream_data)); 232 stream_data->stream_id = stream_id; 233 stream_data->fd = -1; 234 235 add_stream(session_data, stream_data); 236 return stream_data; 237} 238 239static void delete_http2_stream_data(http2_stream_data *stream_data) { 240 if (stream_data->fd != -1) { 241 close(stream_data->fd); 242 } 243 free(stream_data->request_path); 244 free(stream_data); 245} 246 247static http2_session_data *create_http2_session_data(app_context *app_ctx, 248 int fd, 249 struct sockaddr *addr, 250 int addrlen) { 251 int rv; 252 http2_session_data *session_data; 253 SSL *ssl; 254 char host[NI_MAXHOST]; 255 int val = 1; 256 257 ssl = create_ssl(app_ctx->ssl_ctx); 258 session_data = malloc(sizeof(http2_session_data)); 259 memset(session_data, 0, sizeof(http2_session_data)); 260 session_data->app_ctx = app_ctx; 261 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val)); 262 session_data->bev = bufferevent_openssl_socket_new( 263 app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING, 264 BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS); 265 bufferevent_enable(session_data->bev, EV_READ | EV_WRITE); 266 rv = getnameinfo(addr, (socklen_t)addrlen, host, sizeof(host), NULL, 0, 267 NI_NUMERICHOST); 268 if (rv != 0) { 269 session_data->client_addr = strdup("(unknown)"); 270 } else { 271 session_data->client_addr = strdup(host); 272 } 273 274 return session_data; 275} 276 277static void delete_http2_session_data(http2_session_data *session_data) { 278 http2_stream_data *stream_data; 279 SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev); 280 fprintf(stderr, "%s disconnected\n", session_data->client_addr); 281 if (ssl) { 282 SSL_shutdown(ssl); 283 } 284 bufferevent_free(session_data->bev); 285 nghttp2_session_del(session_data->session); 286 for (stream_data = session_data->root.next; stream_data;) { 287 http2_stream_data *next = stream_data->next; 288 delete_http2_stream_data(stream_data); 289 stream_data = next; 290 } 291 free(session_data->client_addr); 292 free(session_data); 293} 294 295/* Serialize the frame and send (or buffer) the data to 296 bufferevent. */ 297static int session_send(http2_session_data *session_data) { 298 int rv; 299 rv = nghttp2_session_send(session_data->session); 300 if (rv != 0) { 301 warnx("Fatal error: %s", nghttp2_strerror(rv)); 302 return -1; 303 } 304 return 0; 305} 306 307/* Read the data in the bufferevent and feed them into nghttp2 library 308 function. Invocation of nghttp2_session_mem_recv() may make 309 additional pending frames, so call session_send() at the end of the 310 function. */ 311static int session_recv(http2_session_data *session_data) { 312 ssize_t readlen; 313 struct evbuffer *input = bufferevent_get_input(session_data->bev); 314 size_t datalen = evbuffer_get_length(input); 315 unsigned char *data = evbuffer_pullup(input, -1); 316 317 readlen = nghttp2_session_mem_recv(session_data->session, data, datalen); 318 if (readlen < 0) { 319 warnx("Fatal error: %s", nghttp2_strerror((int)readlen)); 320 return -1; 321 } 322 if (evbuffer_drain(input, (size_t)readlen) != 0) { 323 warnx("Fatal error: evbuffer_drain failed"); 324 return -1; 325 } 326 if (session_send(session_data) != 0) { 327 return -1; 328 } 329 return 0; 330} 331 332static ssize_t send_callback(nghttp2_session *session, const uint8_t *data, 333 size_t length, int flags, void *user_data) { 334 http2_session_data *session_data = (http2_session_data *)user_data; 335 struct bufferevent *bev = session_data->bev; 336 (void)session; 337 (void)flags; 338 339 /* Avoid excessive buffering in server side. */ 340 if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >= 341 OUTPUT_WOULDBLOCK_THRESHOLD) { 342 return NGHTTP2_ERR_WOULDBLOCK; 343 } 344 bufferevent_write(bev, data, length); 345 return (ssize_t)length; 346} 347 348/* Returns nonzero if the string |s| ends with the substring |sub| */ 349static int ends_with(const char *s, const char *sub) { 350 size_t slen = strlen(s); 351 size_t sublen = strlen(sub); 352 if (slen < sublen) { 353 return 0; 354 } 355 return memcmp(s + slen - sublen, sub, sublen) == 0; 356} 357 358/* Returns int value of hex string character |c| */ 359static uint8_t hex_to_uint(uint8_t c) { 360 if ('0' <= c && c <= '9') { 361 return (uint8_t)(c - '0'); 362 } 363 if ('A' <= c && c <= 'F') { 364 return (uint8_t)(c - 'A' + 10); 365 } 366 if ('a' <= c && c <= 'f') { 367 return (uint8_t)(c - 'a' + 10); 368 } 369 return 0; 370} 371 372/* Decodes percent-encoded byte string |value| with length |valuelen| 373 and returns the decoded byte string in allocated buffer. The return 374 value is NULL terminated. The caller must free the returned 375 string. */ 376static char *percent_decode(const uint8_t *value, size_t valuelen) { 377 char *res; 378 379 res = malloc(valuelen + 1); 380 if (valuelen > 3) { 381 size_t i, j; 382 for (i = 0, j = 0; i < valuelen - 2;) { 383 if (value[i] != '%' || !isxdigit(value[i + 1]) || 384 !isxdigit(value[i + 2])) { 385 res[j++] = (char)value[i++]; 386 continue; 387 } 388 res[j++] = 389 (char)((hex_to_uint(value[i + 1]) << 4) + hex_to_uint(value[i + 2])); 390 i += 3; 391 } 392 memcpy(&res[j], &value[i], 2); 393 res[j + 2] = '\0'; 394 } else { 395 memcpy(res, value, valuelen); 396 res[valuelen] = '\0'; 397 } 398 return res; 399} 400 401static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id, 402 uint8_t *buf, size_t length, 403 uint32_t *data_flags, 404 nghttp2_data_source *source, 405 void *user_data) { 406 int fd = source->fd; 407 ssize_t r; 408 (void)session; 409 (void)stream_id; 410 (void)user_data; 411 412 while ((r = read(fd, buf, length)) == -1 && errno == EINTR) 413 ; 414 if (r == -1) { 415 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE; 416 } 417 if (r == 0) { 418 *data_flags |= NGHTTP2_DATA_FLAG_EOF; 419 } 420 return r; 421} 422 423static int send_response(nghttp2_session *session, int32_t stream_id, 424 nghttp2_nv *nva, size_t nvlen, int fd) { 425 int rv; 426 nghttp2_data_provider data_prd; 427 data_prd.source.fd = fd; 428 data_prd.read_callback = file_read_callback; 429 430 rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd); 431 if (rv != 0) { 432 warnx("Fatal error: %s", nghttp2_strerror(rv)); 433 return -1; 434 } 435 return 0; 436} 437 438static const char ERROR_HTML[] = "<html><head><title>404</title></head>" 439 "<body><h1>404 Not Found</h1></body></html>"; 440 441static int error_reply(nghttp2_session *session, 442 http2_stream_data *stream_data) { 443 int rv; 444 ssize_t writelen; 445 int pipefd[2]; 446 nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")}; 447 448 rv = pipe(pipefd); 449 if (rv != 0) { 450 warn("Could not create pipe"); 451 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, 452 stream_data->stream_id, 453 NGHTTP2_INTERNAL_ERROR); 454 if (rv != 0) { 455 warnx("Fatal error: %s", nghttp2_strerror(rv)); 456 return -1; 457 } 458 return 0; 459 } 460 461 writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1); 462 close(pipefd[1]); 463 464 if (writelen != sizeof(ERROR_HTML) - 1) { 465 close(pipefd[0]); 466 return -1; 467 } 468 469 stream_data->fd = pipefd[0]; 470 471 if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), 472 pipefd[0]) != 0) { 473 close(pipefd[0]); 474 return -1; 475 } 476 return 0; 477} 478 479/* nghttp2_on_header_callback: Called when nghttp2 library emits 480 single header name/value pair. */ 481static int on_header_callback(nghttp2_session *session, 482 const nghttp2_frame *frame, const uint8_t *name, 483 size_t namelen, const uint8_t *value, 484 size_t valuelen, uint8_t flags, void *user_data) { 485 http2_stream_data *stream_data; 486 const char PATH[] = ":path"; 487 (void)flags; 488 (void)user_data; 489 490 switch (frame->hd.type) { 491 case NGHTTP2_HEADERS: 492 if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) { 493 break; 494 } 495 stream_data = 496 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); 497 if (!stream_data || stream_data->request_path) { 498 break; 499 } 500 if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) { 501 size_t j; 502 for (j = 0; j < valuelen && value[j] != '?'; ++j) 503 ; 504 stream_data->request_path = percent_decode(value, j); 505 } 506 break; 507 } 508 return 0; 509} 510 511static int on_begin_headers_callback(nghttp2_session *session, 512 const nghttp2_frame *frame, 513 void *user_data) { 514 http2_session_data *session_data = (http2_session_data *)user_data; 515 http2_stream_data *stream_data; 516 517 if (frame->hd.type != NGHTTP2_HEADERS || 518 frame->headers.cat != NGHTTP2_HCAT_REQUEST) { 519 return 0; 520 } 521 stream_data = create_http2_stream_data(session_data, frame->hd.stream_id); 522 nghttp2_session_set_stream_user_data(session, frame->hd.stream_id, 523 stream_data); 524 return 0; 525} 526 527/* Minimum check for directory traversal. Returns nonzero if it is 528 safe. */ 529static int check_path(const char *path) { 530 /* We don't like '\' in url. */ 531 return path[0] && path[0] == '/' && strchr(path, '\\') == NULL && 532 strstr(path, "/../") == NULL && strstr(path, "/./") == NULL && 533 !ends_with(path, "/..") && !ends_with(path, "/."); 534} 535 536static int on_request_recv(nghttp2_session *session, 537 http2_session_data *session_data, 538 http2_stream_data *stream_data) { 539 int fd; 540 nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")}; 541 char *rel_path; 542 543 if (!stream_data->request_path) { 544 if (error_reply(session, stream_data) != 0) { 545 return NGHTTP2_ERR_CALLBACK_FAILURE; 546 } 547 return 0; 548 } 549 fprintf(stderr, "%s GET %s\n", session_data->client_addr, 550 stream_data->request_path); 551 if (!check_path(stream_data->request_path)) { 552 if (error_reply(session, stream_data) != 0) { 553 return NGHTTP2_ERR_CALLBACK_FAILURE; 554 } 555 return 0; 556 } 557 for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path) 558 ; 559 fd = open(rel_path, O_RDONLY); 560 if (fd == -1) { 561 if (error_reply(session, stream_data) != 0) { 562 return NGHTTP2_ERR_CALLBACK_FAILURE; 563 } 564 return 0; 565 } 566 stream_data->fd = fd; 567 568 if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) != 569 0) { 570 close(fd); 571 return NGHTTP2_ERR_CALLBACK_FAILURE; 572 } 573 return 0; 574} 575 576static int on_frame_recv_callback(nghttp2_session *session, 577 const nghttp2_frame *frame, void *user_data) { 578 http2_session_data *session_data = (http2_session_data *)user_data; 579 http2_stream_data *stream_data; 580 switch (frame->hd.type) { 581 case NGHTTP2_DATA: 582 case NGHTTP2_HEADERS: 583 /* Check that the client request has finished */ 584 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) { 585 stream_data = 586 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id); 587 /* For DATA and HEADERS frame, this callback may be called after 588 on_stream_close_callback. Check that stream still alive. */ 589 if (!stream_data) { 590 return 0; 591 } 592 return on_request_recv(session, session_data, stream_data); 593 } 594 break; 595 default: 596 break; 597 } 598 return 0; 599} 600 601static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, 602 uint32_t error_code, void *user_data) { 603 http2_session_data *session_data = (http2_session_data *)user_data; 604 http2_stream_data *stream_data; 605 (void)error_code; 606 607 stream_data = nghttp2_session_get_stream_user_data(session, stream_id); 608 if (!stream_data) { 609 return 0; 610 } 611 remove_stream(session_data, stream_data); 612 delete_http2_stream_data(stream_data); 613 return 0; 614} 615 616static void initialize_nghttp2_session(http2_session_data *session_data) { 617 nghttp2_session_callbacks *callbacks; 618 619 nghttp2_session_callbacks_new(&callbacks); 620 621 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback); 622 623 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks, 624 on_frame_recv_callback); 625 626 nghttp2_session_callbacks_set_on_stream_close_callback( 627 callbacks, on_stream_close_callback); 628 629 nghttp2_session_callbacks_set_on_header_callback(callbacks, 630 on_header_callback); 631 632 nghttp2_session_callbacks_set_on_begin_headers_callback( 633 callbacks, on_begin_headers_callback); 634 635 nghttp2_session_server_new(&session_data->session, callbacks, session_data); 636 637 nghttp2_session_callbacks_del(callbacks); 638} 639 640/* Send HTTP/2 client connection header, which includes 24 bytes 641 magic octets and SETTINGS frame */ 642static int send_server_connection_header(http2_session_data *session_data) { 643 nghttp2_settings_entry iv[1] = { 644 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}}; 645 int rv; 646 647 rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv, 648 ARRLEN(iv)); 649 if (rv != 0) { 650 warnx("Fatal error: %s", nghttp2_strerror(rv)); 651 return -1; 652 } 653 return 0; 654} 655 656/* readcb for bufferevent after client connection header was 657 checked. */ 658static void readcb(struct bufferevent *bev, void *ptr) { 659 http2_session_data *session_data = (http2_session_data *)ptr; 660 (void)bev; 661 662 if (session_recv(session_data) != 0) { 663 delete_http2_session_data(session_data); 664 return; 665 } 666} 667 668/* writecb for bufferevent. To greaceful shutdown after sending or 669 receiving GOAWAY, we check the some conditions on the nghttp2 670 library and output buffer of bufferevent. If it indicates we have 671 no business to this session, tear down the connection. If the 672 connection is not going to shutdown, we call session_send() to 673 process pending data in the output buffer. This is necessary 674 because we have a threshold on the buffer size to avoid too much 675 buffering. See send_callback(). */ 676static void writecb(struct bufferevent *bev, void *ptr) { 677 http2_session_data *session_data = (http2_session_data *)ptr; 678 if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) { 679 return; 680 } 681 if (nghttp2_session_want_read(session_data->session) == 0 && 682 nghttp2_session_want_write(session_data->session) == 0) { 683 delete_http2_session_data(session_data); 684 return; 685 } 686 if (session_send(session_data) != 0) { 687 delete_http2_session_data(session_data); 688 return; 689 } 690} 691 692/* eventcb for bufferevent */ 693static void eventcb(struct bufferevent *bev, short events, void *ptr) { 694 http2_session_data *session_data = (http2_session_data *)ptr; 695 if (events & BEV_EVENT_CONNECTED) { 696 const unsigned char *alpn = NULL; 697 unsigned int alpnlen = 0; 698 SSL *ssl; 699 (void)bev; 700 701 fprintf(stderr, "%s connected\n", session_data->client_addr); 702 703 ssl = bufferevent_openssl_get_ssl(session_data->bev); 704 705#ifndef OPENSSL_NO_NEXTPROTONEG 706 SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen); 707#endif /* !OPENSSL_NO_NEXTPROTONEG */ 708#if OPENSSL_VERSION_NUMBER >= 0x10002000L 709 if (alpn == NULL) { 710 SSL_get0_alpn_selected(ssl, &alpn, &alpnlen); 711 } 712#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ 713 714 if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) { 715 fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr); 716 delete_http2_session_data(session_data); 717 return; 718 } 719 720 initialize_nghttp2_session(session_data); 721 722 if (send_server_connection_header(session_data) != 0 || 723 session_send(session_data) != 0) { 724 delete_http2_session_data(session_data); 725 return; 726 } 727 728 return; 729 } 730 if (events & BEV_EVENT_EOF) { 731 fprintf(stderr, "%s EOF\n", session_data->client_addr); 732 } else if (events & BEV_EVENT_ERROR) { 733 fprintf(stderr, "%s network error\n", session_data->client_addr); 734 } else if (events & BEV_EVENT_TIMEOUT) { 735 fprintf(stderr, "%s timeout\n", session_data->client_addr); 736 } 737 delete_http2_session_data(session_data); 738} 739 740/* callback for evconnlistener */ 741static void acceptcb(struct evconnlistener *listener, int fd, 742 struct sockaddr *addr, int addrlen, void *arg) { 743 app_context *app_ctx = (app_context *)arg; 744 http2_session_data *session_data; 745 (void)listener; 746 747 session_data = create_http2_session_data(app_ctx, fd, addr, addrlen); 748 749 bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data); 750} 751 752static void start_listen(struct event_base *evbase, const char *service, 753 app_context *app_ctx) { 754 int rv; 755 struct addrinfo hints; 756 struct addrinfo *res, *rp; 757 758 memset(&hints, 0, sizeof(hints)); 759 hints.ai_family = AF_UNSPEC; 760 hints.ai_socktype = SOCK_STREAM; 761 hints.ai_flags = AI_PASSIVE; 762#ifdef AI_ADDRCONFIG 763 hints.ai_flags |= AI_ADDRCONFIG; 764#endif /* AI_ADDRCONFIG */ 765 766 rv = getaddrinfo(NULL, service, &hints, &res); 767 if (rv != 0) { 768 errx(1, "Could not resolve server address"); 769 } 770 for (rp = res; rp; rp = rp->ai_next) { 771 struct evconnlistener *listener; 772 listener = evconnlistener_new_bind( 773 evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE, 774 16, rp->ai_addr, (int)rp->ai_addrlen); 775 if (listener) { 776 freeaddrinfo(res); 777 778 return; 779 } 780 } 781 errx(1, "Could not start listener"); 782} 783 784static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx, 785 struct event_base *evbase) { 786 memset(app_ctx, 0, sizeof(app_context)); 787 app_ctx->ssl_ctx = ssl_ctx; 788 app_ctx->evbase = evbase; 789} 790 791static void run(const char *service, const char *key_file, 792 const char *cert_file) { 793 SSL_CTX *ssl_ctx; 794 app_context app_ctx; 795 struct event_base *evbase; 796 797 ssl_ctx = create_ssl_ctx(key_file, cert_file); 798 evbase = event_base_new(); 799 initialize_app_context(&app_ctx, ssl_ctx, evbase); 800 start_listen(evbase, service, &app_ctx); 801 802 event_base_loop(evbase, 0); 803 804 event_base_free(evbase); 805 SSL_CTX_free(ssl_ctx); 806} 807 808int main(int argc, char **argv) { 809 struct sigaction act; 810 811 if (argc < 4) { 812 fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n"); 813 exit(EXIT_FAILURE); 814 } 815 816 memset(&act, 0, sizeof(struct sigaction)); 817 act.sa_handler = SIG_IGN; 818 sigaction(SIGPIPE, &act, NULL); 819 820#if OPENSSL_VERSION_NUMBER >= 0x1010000fL 821 /* No explicit initialization is required. */ 822#elif defined(OPENSSL_IS_BORINGSSL) 823 CRYPTO_library_init(); 824#else /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \ 825 !defined(OPENSSL_IS_BORINGSSL) */ 826 OPENSSL_config(NULL); 827 SSL_load_error_strings(); 828 SSL_library_init(); 829 OpenSSL_add_all_algorithms(); 830#endif /* !(OPENSSL_VERSION_NUMBER >= 0x1010000fL) && \ 831 !defined(OPENSSL_IS_BORINGSSL) */ 832 833 run(argv[1], argv[2], argv[3]); 834 return 0; 835} 836