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