2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2013 Tatsuhiro Tsujikawa
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:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
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.
26 # define errx(exitcode, format, args...) \
28 warnx(format, ##args); \
31 # define warn(format, args...) warnx(format ": %s", ##args, strerror(errno))
32 # define warnx(format, args...) fprintf(stderr, format "\n", ##args)
37 #endif /* HAVE_CONFIG_H */
39 #include <sys/types.h>
40 #ifdef HAVE_SYS_SOCKET_H
41 # include <sys/socket.h>
42 #endif /* HAVE_SYS_SOCKET_H */
45 #endif /* HAVE_NETDB_H */
49 #endif /* HAVE_UNISTD_H */
53 #endif /* HAVE_FCNTL_H */
55 #ifdef HAVE_NETINET_IN_H
56 # include <netinet/in.h>
57 #endif /* HAVE_NETINET_IN_H */
58 #include <netinet/tcp.h>
65 #include <openssl/ssl.h>
66 #include <openssl/err.h>
67 #include <openssl/conf.h>
70 #include <event2/event.h>
71 #include <event2/bufferevent_ssl.h>
72 #include <event2/listener.h>
74 #include <nghttp2/nghttp2.h>
76 #define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
78 #define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
80 #define MAKE_NV(NAME, VALUE) \
82 (uint8_t *)NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
83 NGHTTP2_NV_FLAG_NONE \
87 typedef struct app_context app_context;
89 typedef struct http2_stream_data {
90 struct http2_stream_data *prev, *next;
96 typedef struct http2_session_data {
97 struct http2_stream_data root;
98 struct bufferevent *bev;
100 nghttp2_session *session;
102 } http2_session_data;
106 struct event_base *evbase;
109 static unsigned char next_proto_list[256];
110 static size_t next_proto_list_len;
112 #ifndef OPENSSL_NO_NEXTPROTONEG
113 static int next_proto_cb(SSL *ssl, const unsigned char **data,
114 unsigned int *len, void *arg) {
118 *data = next_proto_list;
119 *len = (unsigned int)next_proto_list_len;
120 return SSL_TLSEXT_ERR_OK;
122 #endif /* !OPENSSL_NO_NEXTPROTONEG */
124 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
125 static 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) {
132 rv = nghttp2_select_next_protocol((unsigned char **)out, outlen, in, inlen);
135 return SSL_TLSEXT_ERR_NOACK;
138 return SSL_TLSEXT_ERR_OK;
140 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
142 /* Create SSL_CTX. */
143 static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
147 ssl_ctx = SSL_CTX_new(SSLv23_server_method());
149 errx(1, "Could not create SSL/TLS context: %s",
150 ERR_error_string(ERR_get_error(), NULL));
152 SSL_CTX_set_options(ssl_ctx,
153 SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
154 SSL_OP_NO_COMPRESSION |
155 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
157 ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
159 errx(1, "EC_KEY_new_by_curv_name failed: %s",
160 ERR_error_string(ERR_get_error(), NULL));
162 SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
165 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
166 errx(1, "Could not read private key file %s", key_file);
168 if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
169 errx(1, "Could not read certificate file %s", cert_file);
172 next_proto_list[0] = NGHTTP2_PROTO_VERSION_ID_LEN;
173 memcpy(&next_proto_list[1], NGHTTP2_PROTO_VERSION_ID,
174 NGHTTP2_PROTO_VERSION_ID_LEN);
175 next_proto_list_len = 1 + NGHTTP2_PROTO_VERSION_ID_LEN;
177 #ifndef OPENSSL_NO_NEXTPROTONEG
178 SSL_CTX_set_next_protos_advertised_cb(ssl_ctx, next_proto_cb, NULL);
179 #endif /* !OPENSSL_NO_NEXTPROTONEG */
181 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
182 SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, NULL);
183 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
188 /* Create SSL object */
189 static SSL *create_ssl(SSL_CTX *ssl_ctx) {
191 ssl = SSL_new(ssl_ctx);
193 errx(1, "Could not create SSL/TLS session object: %s",
194 ERR_error_string(ERR_get_error(), NULL));
199 static void add_stream(http2_session_data *session_data,
200 http2_stream_data *stream_data) {
201 stream_data->next = session_data->root.next;
202 session_data->root.next = stream_data;
203 stream_data->prev = &session_data->root;
204 if (stream_data->next) {
205 stream_data->next->prev = stream_data;
209 static void remove_stream(http2_session_data *session_data,
210 http2_stream_data *stream_data) {
213 stream_data->prev->next = stream_data->next;
214 if (stream_data->next) {
215 stream_data->next->prev = stream_data->prev;
219 static http2_stream_data *
220 create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) {
221 http2_stream_data *stream_data;
222 stream_data = malloc(sizeof(http2_stream_data));
223 memset(stream_data, 0, sizeof(http2_stream_data));
224 stream_data->stream_id = stream_id;
225 stream_data->fd = -1;
227 add_stream(session_data, stream_data);
231 static void delete_http2_stream_data(http2_stream_data *stream_data) {
232 if (stream_data->fd != -1) {
233 close(stream_data->fd);
235 free(stream_data->request_path);
239 static http2_session_data *create_http2_session_data(app_context *app_ctx,
241 struct sockaddr *addr,
244 http2_session_data *session_data;
246 char host[NI_MAXHOST];
249 ssl = create_ssl(app_ctx->ssl_ctx);
250 session_data = malloc(sizeof(http2_session_data));
251 memset(session_data, 0, sizeof(http2_session_data));
252 session_data->app_ctx = app_ctx;
253 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
254 session_data->bev = bufferevent_openssl_socket_new(
255 app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
256 BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
257 bufferevent_enable(session_data->bev, EV_READ | EV_WRITE);
258 rv = getnameinfo(addr, (socklen_t)addrlen, host, sizeof(host), NULL, 0,
261 session_data->client_addr = strdup("(unknown)");
263 session_data->client_addr = strdup(host);
269 static void delete_http2_session_data(http2_session_data *session_data) {
270 http2_stream_data *stream_data;
271 SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
272 fprintf(stderr, "%s disconnected\n", session_data->client_addr);
276 bufferevent_free(session_data->bev);
277 nghttp2_session_del(session_data->session);
278 for (stream_data = session_data->root.next; stream_data;) {
279 http2_stream_data *next = stream_data->next;
280 delete_http2_stream_data(stream_data);
283 free(session_data->client_addr);
287 /* Serialize the frame and send (or buffer) the data to
289 static int session_send(http2_session_data *session_data) {
291 rv = nghttp2_session_send(session_data->session);
293 warnx("Fatal error: %s", nghttp2_strerror(rv));
299 /* Read the data in the bufferevent and feed them into nghttp2 library
300 function. Invocation of nghttp2_session_mem_recv() may make
301 additional pending frames, so call session_send() at the end of the
303 static int session_recv(http2_session_data *session_data) {
305 struct evbuffer *input = bufferevent_get_input(session_data->bev);
306 size_t datalen = evbuffer_get_length(input);
307 unsigned char *data = evbuffer_pullup(input, -1);
309 readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
311 warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
314 if (evbuffer_drain(input, (size_t)readlen) != 0) {
315 warnx("Fatal error: evbuffer_drain failed");
318 if (session_send(session_data) != 0) {
324 static ssize_t send_callback(nghttp2_session *session, const uint8_t *data,
325 size_t length, int flags, void *user_data) {
326 http2_session_data *session_data = (http2_session_data *)user_data;
327 struct bufferevent *bev = session_data->bev;
331 /* Avoid excessive buffering in server side. */
332 if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
333 OUTPUT_WOULDBLOCK_THRESHOLD) {
334 return NGHTTP2_ERR_WOULDBLOCK;
336 bufferevent_write(bev, data, length);
337 return (ssize_t)length;
340 /* Returns nonzero if the string |s| ends with the substring |sub| */
341 static int ends_with(const char *s, const char *sub) {
342 size_t slen = strlen(s);
343 size_t sublen = strlen(sub);
347 return memcmp(s + slen - sublen, sub, sublen) == 0;
350 /* Returns int value of hex string character |c| */
351 static uint8_t hex_to_uint(uint8_t c) {
352 if ('0' <= c && c <= '9') {
353 return (uint8_t)(c - '0');
355 if ('A' <= c && c <= 'F') {
356 return (uint8_t)(c - 'A' + 10);
358 if ('a' <= c && c <= 'f') {
359 return (uint8_t)(c - 'a' + 10);
364 /* Decodes percent-encoded byte string |value| with length |valuelen|
365 and returns the decoded byte string in allocated buffer. The return
366 value is NULL terminated. The caller must free the returned
368 static char *percent_decode(const uint8_t *value, size_t valuelen) {
371 res = malloc(valuelen + 1);
374 for (i = 0, j = 0; i < valuelen - 2;) {
375 if (value[i] != '%' || !isxdigit(value[i + 1]) ||
376 !isxdigit(value[i + 2])) {
377 res[j++] = (char)value[i++];
381 (char)((hex_to_uint(value[i + 1]) << 4) + hex_to_uint(value[i + 2]));
384 memcpy(&res[j], &value[i], 2);
387 memcpy(res, value, valuelen);
388 res[valuelen] = '\0';
393 static ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
394 uint8_t *buf, size_t length,
395 uint32_t *data_flags,
396 nghttp2_data_source *source,
404 while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
407 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
410 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
415 static int send_response(nghttp2_session *session, int32_t stream_id,
416 nghttp2_nv *nva, size_t nvlen, int fd) {
418 nghttp2_data_provider data_prd;
419 data_prd.source.fd = fd;
420 data_prd.read_callback = file_read_callback;
422 rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
424 warnx("Fatal error: %s", nghttp2_strerror(rv));
430 static const char ERROR_HTML[] = "<html><head><title>404</title></head>"
431 "<body><h1>404 Not Found</h1></body></html>";
433 static int error_reply(nghttp2_session *session,
434 http2_stream_data *stream_data) {
438 nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")};
442 warn("Could not create pipe");
443 rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
444 stream_data->stream_id,
445 NGHTTP2_INTERNAL_ERROR);
447 warnx("Fatal error: %s", nghttp2_strerror(rv));
453 writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1);
456 if (writelen != sizeof(ERROR_HTML) - 1) {
461 stream_data->fd = pipefd[0];
463 if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
471 /* nghttp2_on_header_callback: Called when nghttp2 library emits
472 single header name/value pair. */
473 static int on_header_callback(nghttp2_session *session,
474 const nghttp2_frame *frame, const uint8_t *name,
475 size_t namelen, const uint8_t *value,
476 size_t valuelen, uint8_t flags, void *user_data) {
477 http2_stream_data *stream_data;
478 const char PATH[] = ":path";
482 switch (frame->hd.type) {
483 case NGHTTP2_HEADERS:
484 if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
488 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
489 if (!stream_data || stream_data->request_path) {
492 if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
494 for (j = 0; j < valuelen && value[j] != '?'; ++j)
496 stream_data->request_path = percent_decode(value, j);
503 static int on_begin_headers_callback(nghttp2_session *session,
504 const nghttp2_frame *frame,
506 http2_session_data *session_data = (http2_session_data *)user_data;
507 http2_stream_data *stream_data;
509 if (frame->hd.type != NGHTTP2_HEADERS ||
510 frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
513 stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
514 nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
519 /* Minimum check for directory traversal. Returns nonzero if it is
521 static int check_path(const char *path) {
522 /* We don't like '\' in url. */
523 return path[0] && path[0] == '/' && strchr(path, '\\') == NULL &&
524 strstr(path, "/../") == NULL && strstr(path, "/./") == NULL &&
525 !ends_with(path, "/..") && !ends_with(path, "/.");
528 static int on_request_recv(nghttp2_session *session,
529 http2_session_data *session_data,
530 http2_stream_data *stream_data) {
532 nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")};
535 if (!stream_data->request_path) {
536 if (error_reply(session, stream_data) != 0) {
537 return NGHTTP2_ERR_CALLBACK_FAILURE;
541 fprintf(stderr, "%s GET %s\n", session_data->client_addr,
542 stream_data->request_path);
543 if (!check_path(stream_data->request_path)) {
544 if (error_reply(session, stream_data) != 0) {
545 return NGHTTP2_ERR_CALLBACK_FAILURE;
549 for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path)
551 fd = open(rel_path, O_RDONLY);
553 if (error_reply(session, stream_data) != 0) {
554 return NGHTTP2_ERR_CALLBACK_FAILURE;
558 stream_data->fd = fd;
560 if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) !=
563 return NGHTTP2_ERR_CALLBACK_FAILURE;
568 static int on_frame_recv_callback(nghttp2_session *session,
569 const nghttp2_frame *frame, void *user_data) {
570 http2_session_data *session_data = (http2_session_data *)user_data;
571 http2_stream_data *stream_data;
572 switch (frame->hd.type) {
574 case NGHTTP2_HEADERS:
575 /* Check that the client request has finished */
576 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
578 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
579 /* For DATA and HEADERS frame, this callback may be called after
580 on_stream_close_callback. Check that stream still alive. */
584 return on_request_recv(session, session_data, stream_data);
593 static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
594 uint32_t error_code, void *user_data) {
595 http2_session_data *session_data = (http2_session_data *)user_data;
596 http2_stream_data *stream_data;
599 stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
603 remove_stream(session_data, stream_data);
604 delete_http2_stream_data(stream_data);
608 static void initialize_nghttp2_session(http2_session_data *session_data) {
609 nghttp2_session_callbacks *callbacks;
611 nghttp2_session_callbacks_new(&callbacks);
613 nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
615 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
616 on_frame_recv_callback);
618 nghttp2_session_callbacks_set_on_stream_close_callback(
619 callbacks, on_stream_close_callback);
621 nghttp2_session_callbacks_set_on_header_callback(callbacks,
624 nghttp2_session_callbacks_set_on_begin_headers_callback(
625 callbacks, on_begin_headers_callback);
627 nghttp2_session_server_new(&session_data->session, callbacks, session_data);
629 nghttp2_session_callbacks_del(callbacks);
632 /* Send HTTP/2 client connection header, which includes 24 bytes
633 magic octets and SETTINGS frame */
634 static int send_server_connection_header(http2_session_data *session_data) {
635 nghttp2_settings_entry iv[1] = {
636 {NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
639 rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
642 warnx("Fatal error: %s", nghttp2_strerror(rv));
648 /* readcb for bufferevent after client connection header was
650 static void readcb(struct bufferevent *bev, void *ptr) {
651 http2_session_data *session_data = (http2_session_data *)ptr;
654 if (session_recv(session_data) != 0) {
655 delete_http2_session_data(session_data);
660 /* writecb for bufferevent. To greaceful shutdown after sending or
661 receiving GOAWAY, we check the some conditions on the nghttp2
662 library and output buffer of bufferevent. If it indicates we have
663 no business to this session, tear down the connection. If the
664 connection is not going to shutdown, we call session_send() to
665 process pending data in the output buffer. This is necessary
666 because we have a threshold on the buffer size to avoid too much
667 buffering. See send_callback(). */
668 static void writecb(struct bufferevent *bev, void *ptr) {
669 http2_session_data *session_data = (http2_session_data *)ptr;
670 if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
673 if (nghttp2_session_want_read(session_data->session) == 0 &&
674 nghttp2_session_want_write(session_data->session) == 0) {
675 delete_http2_session_data(session_data);
678 if (session_send(session_data) != 0) {
679 delete_http2_session_data(session_data);
684 /* eventcb for bufferevent */
685 static void eventcb(struct bufferevent *bev, short events, void *ptr) {
686 http2_session_data *session_data = (http2_session_data *)ptr;
687 if (events & BEV_EVENT_CONNECTED) {
688 const unsigned char *alpn = NULL;
689 unsigned int alpnlen = 0;
693 fprintf(stderr, "%s connected\n", session_data->client_addr);
695 ssl = bufferevent_openssl_get_ssl(session_data->bev);
697 #ifndef OPENSSL_NO_NEXTPROTONEG
698 SSL_get0_next_proto_negotiated(ssl, &alpn, &alpnlen);
699 #endif /* !OPENSSL_NO_NEXTPROTONEG */
700 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
702 SSL_get0_alpn_selected(ssl, &alpn, &alpnlen);
704 #endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
706 if (alpn == NULL || alpnlen != 2 || memcmp("h2", alpn, 2) != 0) {
707 fprintf(stderr, "%s h2 is not negotiated\n", session_data->client_addr);
708 delete_http2_session_data(session_data);
712 initialize_nghttp2_session(session_data);
714 if (send_server_connection_header(session_data) != 0 ||
715 session_send(session_data) != 0) {
716 delete_http2_session_data(session_data);
722 if (events & BEV_EVENT_EOF) {
723 fprintf(stderr, "%s EOF\n", session_data->client_addr);
724 } else if (events & BEV_EVENT_ERROR) {
725 fprintf(stderr, "%s network error\n", session_data->client_addr);
726 } else if (events & BEV_EVENT_TIMEOUT) {
727 fprintf(stderr, "%s timeout\n", session_data->client_addr);
729 delete_http2_session_data(session_data);
732 /* callback for evconnlistener */
733 static void acceptcb(struct evconnlistener *listener, int fd,
734 struct sockaddr *addr, int addrlen, void *arg) {
735 app_context *app_ctx = (app_context *)arg;
736 http2_session_data *session_data;
739 session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
741 bufferevent_setcb(session_data->bev, readcb, writecb, eventcb, session_data);
744 static void start_listen(struct event_base *evbase, const char *service,
745 app_context *app_ctx) {
747 struct addrinfo hints;
748 struct addrinfo *res, *rp;
750 memset(&hints, 0, sizeof(hints));
751 hints.ai_family = AF_UNSPEC;
752 hints.ai_socktype = SOCK_STREAM;
753 hints.ai_flags = AI_PASSIVE;
755 hints.ai_flags |= AI_ADDRCONFIG;
756 #endif /* AI_ADDRCONFIG */
758 rv = getaddrinfo(NULL, service, &hints, &res);
760 errx(1, "Could not resolve server address");
762 for (rp = res; rp; rp = rp->ai_next) {
763 struct evconnlistener *listener;
764 listener = evconnlistener_new_bind(
765 evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
766 16, rp->ai_addr, (int)rp->ai_addrlen);
773 errx(1, "Could not start listener");
776 static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx,
777 struct event_base *evbase) {
778 memset(app_ctx, 0, sizeof(app_context));
779 app_ctx->ssl_ctx = ssl_ctx;
780 app_ctx->evbase = evbase;
783 static void run(const char *service, const char *key_file,
784 const char *cert_file) {
787 struct event_base *evbase;
789 ssl_ctx = create_ssl_ctx(key_file, cert_file);
790 evbase = event_base_new();
791 initialize_app_context(&app_ctx, ssl_ctx, evbase);
792 start_listen(evbase, service, &app_ctx);
794 event_base_loop(evbase, 0);
796 event_base_free(evbase);
797 SSL_CTX_free(ssl_ctx);
800 int main(int argc, char **argv) {
801 struct sigaction act;
804 fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n");
808 memset(&act, 0, sizeof(struct sigaction));
809 act.sa_handler = SIG_IGN;
810 sigaction(SIGPIPE, &act, NULL);
812 SSL_load_error_strings();
815 run(argv[1], argv[2], argv[3]);