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