static int test_tls_session_time_out (gnutls_session_t session) { int ret; MHD_socket sd; struct sockaddr_in sa; sd = socket (AF_INET, SOCK_STREAM, 0); if (sd == -1) { fprintf (stderr, "Failed to create socket: %s\n", strerror (errno)); return -1; } memset (&sa, '\0', sizeof (struct sockaddr_in)); sa.sin_family = AF_INET; sa.sin_port = htons (DEAMON_TEST_PORT); sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) (intptr_t) sd); ret = connect (sd, (struct sockaddr *) &sa, sizeof (struct sockaddr_in)); if (ret < 0) { fprintf (stderr, "Error: %s\n", MHD_E_FAILED_TO_CONNECT); MHD_socket_close_ (sd); return -1; } ret = gnutls_handshake (session); if (ret < 0) { fprintf (stderr, "Handshake failed\n"); MHD_socket_close_ (sd); return -1; } sleep (TIME_OUT + 1); /* check that server has closed the connection */ /* TODO better RST trigger */ if (send (sd, "", 1, 0) == 0) { fprintf (stderr, "Connection failed to time-out\n"); MHD_socket_close_ (sd); return -1; } MHD_socket_close_ (sd); return 0; }
/* * Connects to the host |host| and port |port|. This function returns * the file descriptor of the client socket. */ static int connect_to(const char *host, uint16_t port) { struct addrinfo hints; int fd = -1; int rv; char service[NI_MAXSERV]; struct addrinfo *res, *rp; snprintf(service, sizeof(service), "%u", port); memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; rv = getaddrinfo(host, service, &hints, &res); if(rv != 0) { dief("getaddrinfo", gai_strerror(rv)); } for(rp = res; rp; rp = rp->ai_next) { fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if(fd == -1) { continue; } while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 && errno == EINTR); if(rv == 0) { break; } MHD_socket_close_(fd); fd = -1; dief("connect", strerror(errno)); } freeaddrinfo(res); return fd; }
static void * ServeOneRequest(void *param) { struct MHD_Daemon *d; fd_set rs; fd_set ws; fd_set es; MHD_socket fd, max; time_t start; struct timeval tv; int done = 0; fd = (MHD_socket) (intptr_t) param; d = MHD_start_daemon (MHD_USE_DEBUG, 1082, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_LISTEN_SOCKET, fd, MHD_OPTION_NOTIFY_COMPLETED, &request_completed, &done, MHD_OPTION_END); if (d == NULL) return "MHD_start_daemon() failed"; start = time (NULL); while ((time (NULL) - start < 5) && done == 0) { max = 0; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max)) { MHD_stop_daemon (d); MHD_socket_close_(fd); return "MHD_get_fdset() failed"; } tv.tv_sec = 0; tv.tv_usec = 1000; MHD_SYS_select_ (max + 1, &rs, &ws, &es, &tv); MHD_run (d); } MHD_stop_daemon (d); MHD_socket_close_(fd); return NULL; }
static int testStopRace (int poll_flag) { struct sockaddr_in sin; MHD_socket fd; struct MHD_Daemon *d; d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag, 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_CONNECTION_TIMEOUT, 5, MHD_OPTION_END); if (d == NULL) return 16; fd = socket (PF_INET, SOCK_STREAM, 0); if (fd == MHD_INVALID_SOCKET) { fprintf(stderr, "socket error\n"); return 256; } memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(1081); sin.sin_addr.s_addr = htonl(0x7f000001); if (connect (fd, (struct sockaddr *)(&sin), sizeof(sin)) < 0) { fprintf(stderr, "connect error\n"); MHD_socket_close_ (fd); return 512; } /* printf("Waiting\n"); */ /* Let the thread get going. */ usleep(500000); /* printf("Stopping daemon\n"); */ MHD_stop_daemon (d); MHD_socket_close_ (fd); /* printf("good\n"); */ return 0; }
/** * Close socket and release allocated resourced * @param s the socket to close * @return zero on succeed, -1 otherwise */ static int wr_close(wr_socket s) { int ret = (MHD_socket_close_(s->fd)) ? 0 : -1; #ifdef HTTPS_SUPPORT if (wr_tls == s->t) { gnutls_deinit (s->tls_s); gnutls_certificate_free_credentials (s->tls_crd); } #endif /* HTTPS_SUPPORT */ free(s); return ret; }
/** * Create wr_socket with TLS TCP underlying socket * @return created socket on success, WR_BAD otherwise */ static wr_socket wr_create_tls_sckt(void) { #ifdef HTTPS_SUPPORT wr_socket s = (wr_socket)malloc(sizeof(struct wr_socket_strc)); if (WR_BAD == s) return WR_BAD; s->t = wr_tls; s->tls_connected = 0; s->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (MHD_INVALID_SOCKET != s->fd) { if (GNUTLS_E_SUCCESS == gnutls_init (&(s->tls_s), GNUTLS_CLIENT)) { if (GNUTLS_E_SUCCESS == gnutls_set_default_priority (s->tls_s)) { if (GNUTLS_E_SUCCESS == gnutls_certificate_allocate_credentials (&(s->tls_crd))) { if (GNUTLS_E_SUCCESS == gnutls_credentials_set (s->tls_s, GNUTLS_CRD_CERTIFICATE, s->tls_crd)) { #if GNUTLS_VERSION_NUMBER+0 >= 0x030109 gnutls_transport_set_int (s->tls_s, (int)(s->fd)); #else /* GnuTLS before 3.1.9 */ gnutls_transport_set_ptr (s->tls_s, (gnutls_transport_ptr_t)(intptr_t)(s->fd)); #endif /* GnuTLS before 3.1.9 */ return s; } gnutls_certificate_free_credentials (s->tls_crd); } } gnutls_deinit (s->tls_s); } (void)MHD_socket_close_ (s->fd); } free(s); #endif /* HTTPS_SUPPORT */ return WR_BAD; }
/** * Test daemon response to TLS client hello requests containing extensions * * @param session * @param exten_t - the type of extension being appended to client hello request * @param ext_count - the number of consecutive extension replicas inserted into request * @param ext_length - the length of each appended extension * @return 0 on successful test completion, -1 otherwise */ static int test_hello_extension (gnutls_session_t session, extensions_t exten_t, int ext_count, int ext_length) { int i, ret = 0, pos = 0; MHD_socket sd; int exten_data_len, ciphersuite_len, datalen; struct sockaddr_in sa; char url[255]; opaque *data = NULL; uint8_t session_id_len = 0; opaque rnd[TLS_RANDOM_SIZE]; opaque extdata[MAX_EXT_DATA_LENGTH]; /* single, null compression */ unsigned char comp[] = { 0x01, 0x00 }; struct CBC cbc; sd = -1; memset (&cbc, 0, sizeof (struct CBC)); if (NULL == (cbc.buf = malloc (sizeof (char) * 256))) { fprintf (stderr, MHD_E_MEM); ret = -1; goto cleanup; } cbc.size = 256; sd = socket (AF_INET, SOCK_STREAM, 0); if (sd == -1) { fprintf(stderr, "Failed to create socket: %s\n", strerror(errno)); free (cbc.buf); return -1; } memset (&sa, '\0', sizeof (struct sockaddr_in)); sa.sin_family = AF_INET; sa.sin_port = htons (DEAMON_TEST_PORT); sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); enum MHD_GNUTLS_Protocol hver; /* init hash functions */ session->internals.handshake_mac_handle_md5 = MHD_gtls_hash_init (MHD_GNUTLS_MAC_MD5); session->internals.handshake_mac_handle_sha = MHD_gtls_hash_init (MHD_GNUTLS_MAC_SHA1); /* version = 2 , random = [4 for unix time + 28 for random bytes] */ datalen = 2 /* version */ + TLS_RANDOM_SIZE + (session_id_len + 1); data = MHD_gnutls_malloc (datalen); if (data == NULL) { free (cbc.buf); return -1; } hver = MHD_gtls_version_max (session); data[pos++] = MHD_gtls_version_get_major (hver); data[pos++] = MHD_gtls_version_get_minor (hver); /* Set the version we advertise as maximum (RSA uses it). */ set_adv_version (session, MHD_gtls_version_get_major (hver), MHD_gtls_version_get_minor (hver)); session->security_parameters.version = hver; session->security_parameters.timestamp = time (NULL); /* generate session client random */ memset (session->security_parameters.client_random, 0, TLS_RANDOM_SIZE); gnutls_write_uint32 (time (NULL), rnd); if (GC_OK != MHD_gc_nonce ((char *) &rnd[4], TLS_RANDOM_SIZE - 4)) abort (); memcpy (session->security_parameters.client_random, rnd, TLS_RANDOM_SIZE); memcpy (&data[pos], rnd, TLS_RANDOM_SIZE); pos += TLS_RANDOM_SIZE; /* Copy the Session ID */ data[pos++] = session_id_len; /* * len = ciphersuite data + 2 bytes ciphersuite length \ * 1 byte compression length + 1 byte compression data + \ * 2 bytes extension length, extensions data */ ciphersuite_len = MHD__gnutls_copy_ciphersuites (session, extdata, sizeof (extdata)); exten_data_len = ext_count * (2 + 2 + ext_length); datalen += ciphersuite_len + 2 + 2 + exten_data_len; data = MHD_gtls_realloc_fast (data, datalen); memcpy (&data[pos], extdata, sizeof (ciphersuite_len)); pos += ciphersuite_len; /* set compression */ memcpy (&data[pos], comp, sizeof (comp)); pos += 2; /* set extensions length = 2 type bytes + 2 length bytes + extension length */ gnutls_write_uint16 (exten_data_len, &data[pos]); pos += 2; for (i = 0; i < ext_count; ++i) { /* write extension type */ gnutls_write_uint16 (exten_t, &data[pos]); pos += 2; gnutls_write_uint16 (ext_length, &data[pos]); pos += 2; /* we might want to generate random data here */ memset (&data[pos], 0, ext_length); pos += ext_length; } if (connect (sd, &sa, sizeof (struct sockaddr_in)) < 0) { fprintf (stderr, "%s\n", MHD_E_FAILED_TO_CONNECT); ret = -1; goto cleanup; } gnutls_transport_set_ptr (session, (MHD_gnutls_transport_ptr_t) (long) sd); if (gen_test_file_url (url, DEAMON_TEST_PORT)) { ret = -1; goto cleanup; } /* this should crash the server */ ret = gnutls_send_handshake (session, data, datalen, GNUTLS_HANDSHAKE_CLIENT_HELLO); /* advance to STATE2 */ session->internals.handshake_state = STATE2; ret = gnutls_handshake (session); ret = gnutls_bye (session, GNUTLS_SHUT_WR); gnutls_free (data); /* make sure daemon is still functioning */ if (CURLE_OK != send_curl_req (url, &cbc, "AES128-SHA", MHD_GNUTLS_PROTOCOL_TLS1_2)) { ret = -1; goto cleanup; } cleanup: if (-1 != sd) MHD_socket_close_ (sd); gnutls_free (cbc.buf); return ret; }
static int testExternalGet () { struct MHD_Daemon *d; CURL *c; char buf[2048]; struct CBC cbc; CURLM *multi; CURLMcode mret; fd_set rs; fd_set ws; fd_set es; MHD_socket maxsock; #ifdef MHD_WINSOCK_SOCKETS int maxposixs; /* Max socket number unused on W32 */ #else /* MHD_POSIX_SOCKETS */ #define maxposixs maxsock #endif /* MHD_POSIX_SOCKETS */ int running; struct CURLMsg *msg; time_t start; struct timeval tv; int i; MHD_socket fd; multi = NULL; cbc.buf = buf; cbc.size = 2048; cbc.pos = 0; d = MHD_start_daemon (MHD_USE_DEBUG, 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); if (d == NULL) return 256; c = setupCURL(&cbc); multi = curl_multi_init (); if (multi == NULL) { curl_easy_cleanup (c); MHD_stop_daemon (d); return 512; } mret = curl_multi_add_handle (multi, c); if (mret != CURLM_OK) { curl_multi_cleanup (multi); curl_easy_cleanup (c); MHD_stop_daemon (d); return 1024; } for (i = 0; i < 2; i++) { start = time (NULL); while ((time (NULL) - start < 5) && (multi != NULL)) { maxsock = MHD_INVALID_SOCKET; maxposixs = -1; FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); curl_multi_perform (multi, &running); mret = curl_multi_fdset (multi, &rs, &ws, &es, &maxposixs); if (mret != CURLM_OK) { curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2048; } if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &maxsock)) { curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); curl_easy_cleanup (c); MHD_stop_daemon (d); return 4096; } tv.tv_sec = 0; tv.tv_usec = 1000; select (maxposixs + 1, &rs, &ws, &es, &tv); curl_multi_perform (multi, &running); if (running == 0) { msg = curl_multi_info_read (multi, &running); if (msg == NULL) break; if (msg->msg == CURLMSG_DONE) { if (i == 0 && msg->data.result != CURLE_OK) printf ("%s failed at %s:%d: `%s'\n", "curl_multi_perform", __FILE__, __LINE__, curl_easy_strerror (msg->data.result)); else if (i == 1 && msg->data.result == CURLE_OK) printf ("%s should have failed at %s:%d\n", "curl_multi_perform", __FILE__, __LINE__); curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); curl_easy_cleanup (c); c = NULL; multi = NULL; } } MHD_run (d); } if (i == 0) { /* quiesce the daemon on the 1st iteration, so the 2nd should fail */ fd = MHD_quiesce_daemon(d); if (MHD_INVALID_SOCKET == fd) { fprintf (stderr, "MHD_quiesce_daemon failed.\n"); curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; } c = setupCURL (&cbc); multi = curl_multi_init (); mret = curl_multi_add_handle (multi, c); if (mret != CURLM_OK) { curl_multi_remove_handle (multi, c); curl_multi_cleanup (multi); curl_easy_cleanup (c); MHD_stop_daemon (d); return 32768; } } } if (multi != NULL) { curl_multi_remove_handle (multi, c); curl_easy_cleanup (c); curl_multi_cleanup (multi); } MHD_stop_daemon (d); MHD_socket_close_ (fd); if (cbc.pos != strlen ("/hello_world")) return 8192; if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) return 16384; return 0; }
static int testGet (int type, int pool_count, int poll_flag) { struct MHD_Daemon *d; CURL *c; char buf[2048]; struct CBC cbc; CURLcode errornum; MHD_socket fd; pthread_t thrd; const char *thrdRet; cbc.buf = buf; cbc.size = 2048; cbc.pos = 0; if (pool_count > 0) { d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag, 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_THREAD_POOL_SIZE, pool_count, MHD_OPTION_END); } else { d = MHD_start_daemon (type | MHD_USE_DEBUG | MHD_USE_PIPE_FOR_SHUTDOWN | poll_flag, 11080, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END); } if (d == NULL) return 1; c = setupCURL(&cbc); if (CURLE_OK != (errornum = curl_easy_perform (c))) { fprintf (stderr, "curl_easy_perform failed: `%s'\n", curl_easy_strerror (errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; } if (cbc.pos != strlen ("/hello_world")) { curl_easy_cleanup (c); MHD_stop_daemon (d); return 4; } if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) { curl_easy_cleanup (c); MHD_stop_daemon (d); return 8; } fd = MHD_quiesce_daemon (d); if (MHD_INVALID_SOCKET == fd) { fprintf (stderr, "MHD_quiesce_daemon failed.\n"); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; } if (0 != pthread_create(&thrd, NULL, &ServeOneRequest, (void*)(intptr_t) fd)) { fprintf (stderr, "pthread_create failed\n"); curl_easy_cleanup (c); MHD_stop_daemon (d); return 16; } cbc.pos = 0; if (CURLE_OK != (errornum = curl_easy_perform (c))) { fprintf (stderr, "curl_easy_perform failed: `%s'\n", curl_easy_strerror (errornum)); curl_easy_cleanup (c); MHD_stop_daemon (d); return 2; } if (0 != pthread_join(thrd, (void**)&thrdRet)) { fprintf (stderr, "pthread_join failed\n"); curl_easy_cleanup (c); MHD_stop_daemon (d); return 16; } if (NULL != thrdRet) { fprintf (stderr, "ServeOneRequest() error: %s\n", thrdRet); curl_easy_cleanup (c); MHD_stop_daemon (d); return 16; } if (cbc.pos != strlen ("/hello_world")) { fprintf(stderr, "%s\n", cbc.buf); curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_(fd); return 4; } if (0 != strncmp ("/hello_world", cbc.buf, strlen ("/hello_world"))) { fprintf(stderr, "%s\n", cbc.buf); curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_(fd); return 8; } /* at this point, the forked server quit, and the new * server has quiesced, so new requests should fail */ if (CURLE_OK == (errornum = curl_easy_perform (c))) { fprintf (stderr, "curl_easy_perform should fail\n"); curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_(fd); return 2; } curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_(fd); return 0; }
/** * Create a listen socket, with noninheritable flag if possible. * * @param use_ipv6 if set to non-zero IPv6 is used * @return created socket or MHD_INVALID_SOCKET in case of errors */ MHD_socket MHD_socket_create_listen_ (int use_ipv6) { int domain; MHD_socket fd; int cloexec_set; #if defined(OSX) && defined(SOL_SOCKET) && defined(SO_NOSIGPIPE) static const int on_val = 1; #endif #ifdef HAVE_INET6 domain = (use_ipv6) ? PF_INET6 : PF_INET; #else /* ! HAVE_INET6 */ if (use_ipv6) return MHD_INVALID_SOCKET; domain = PF_INET; #endif /* ! HAVE_INET6 */ #if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC) fd = socket (domain, SOCK_STREAM | SOCK_CLOEXEC, 0); cloexec_set = !0; #elif defined(MHD_WINSOCK_SOCKETS) && defined (WSA_FLAG_NO_HANDLE_INHERIT) fd = WSASocketW (domain, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_NO_HANDLE_INHERIT); cloexec_set = !0; #else /* !SOCK_CLOEXEC */ fd = MHD_INVALID_SOCKET; #endif /* !SOCK_CLOEXEC */ if (MHD_INVALID_SOCKET == fd) { fd = socket (domain, SOCK_STREAM, 0); cloexec_set = 0; } if (MHD_INVALID_SOCKET == fd) return MHD_INVALID_SOCKET; #if defined(OSX) && defined(SOL_SOCKET) && defined(SO_NOSIGPIPE) if(0 != setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &on_val, sizeof (on_val))) { int err = MHD_socket_get_error_ (); MHD_socket_close_ (fd); MHD_socket_fset_error_ (err); return MHD_INVALID_SOCKET; } #endif if (! cloexec_set) (void) MHD_socket_noninheritable_ (fd); return fd; }
/* * Fetches the resource denoted by |uri|. */ static void fetch_uri(const struct URI *uri) { spdylay_session_callbacks callbacks; int fd; struct Request req; struct Connection connection; int rv; nfds_t npollfds = 1; struct pollfd pollfds[1]; uint16_t spdy_proto_version = 3; request_init(&req, uri); setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ fd = connect_to(req.host, req.port); if (-1 == fd) abort (); connection.fd = fd; connection.want_io = IO_NONE; /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version); rv = spdylay_session_client_new(&connection.session, spdy_proto_version, &callbacks, &connection); if(rv != 0) { diec("spdylay_session_client_new", rv); } /* Submit the HTTP request to the outbound queue. */ submit_request(&connection, &req); pollfds[0].fd = fd; ctl_poll(pollfds, &connection); /* Event loop */ while(spdylay_session_want_read(connection.session) || spdylay_session_want_write(connection.session)) { int nfds = poll(pollfds, npollfds, -1); if(nfds == -1) { dief("poll", strerror(errno)); } if(pollfds[0].revents & (POLLIN | POLLOUT)) { exec_io(&connection); } if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { die("Connection error"); } ctl_poll(pollfds, &connection); } /* Resource cleanup */ spdylay_session_del(connection.session); shutdown(fd, SHUT_WR); MHD_socket_close_(fd); request_free(&req); }
/* * Fetches the resource denoted by |uri|. */ static void fetch_uri(const struct URI *uri) { spdylay_session_callbacks callbacks; int fd; SSL_CTX *ssl_ctx; SSL *ssl; struct Request req; struct Connection connection; int rv; nfds_t npollfds = 1; struct pollfd pollfds[1]; uint16_t spdy_proto_version; request_init(&req, uri); setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ fd = connect_to(req.host, req.port); if (-1 == fd) abort (); ssl_ctx = SSL_CTX_new(SSLv23_client_method()); if(ssl_ctx == NULL) { dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL)); } init_ssl_ctx(ssl_ctx, &spdy_proto_version); ssl = SSL_new(ssl_ctx); if(ssl == NULL) { dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); } /* To simplify the program, we perform SSL/TLS handshake in blocking I/O. */ ssl_handshake(ssl, fd); connection.ssl = ssl; connection.want_io = IO_NONE; /* Here make file descriptor non-block */ make_non_block(fd); set_tcp_nodelay(fd); spdylay_printf("[INFO] SPDY protocol version = %d\n", spdy_proto_version); rv = spdylay_session_client_new(&connection.session, spdy_proto_version, &callbacks, &connection); if(rv != 0) { diec("spdylay_session_client_new", rv); } /* Submit the HTTP request to the outbound queue. */ submit_request(&connection, &req); pollfds[0].fd = fd; ctl_poll(pollfds, &connection); /* Event loop */ while(spdylay_session_want_read(connection.session) || spdylay_session_want_write(connection.session)) { int nfds = poll(pollfds, npollfds, -1); if(nfds == -1) { dief("poll", strerror(errno)); } if(pollfds[0].revents & (POLLIN | POLLOUT)) { exec_io(&connection); } if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) { die("Connection error"); } ctl_poll(pollfds, &connection); } /* Resource cleanup */ spdylay_session_del(connection.session); SSL_shutdown(ssl); SSL_free(ssl); SSL_CTX_free(ssl_ctx); shutdown(fd, SHUT_WR); MHD_socket_close_ (fd); request_free(&req); }
/* * Fetches the resource denoted by |uri|. */ struct SPDY_Connection * spdy_connect(const struct URI *uri, uint16_t port, bool is_tls) { spdylay_session_callbacks callbacks; int fd; SSL *ssl=NULL; struct SPDY_Connection * connection = NULL; int rv; spdy_setup_spdylay_callbacks(&callbacks); /* Establish connection and setup SSL */ PRINT_INFO2("connecting to %s:%i", uri->host, port); fd = spdy_socket_connect_to(uri->host, port); if(fd == -1) { PRINT_INFO("Could not open file descriptor"); return NULL; } if(is_tls) { ssl = SSL_new(glob_opt.ssl_ctx); if(ssl == NULL) { spdy_dief("SSL_new", ERR_error_string(ERR_get_error(), NULL)); } //TODO non-blocking /* To simplify the program, we perform SSL/TLS handshake in blocking I/O. */ glob_opt.spdy_proto_version = 0; rv = spdy_ssl_handshake(ssl, fd); if(rv <= 0 || (glob_opt.spdy_proto_version != 3 && glob_opt.spdy_proto_version != 2)) { PRINT_INFO("Closing SSL"); //no spdy on the other side goto free_and_fail; } } else { glob_opt.spdy_proto_version = 3; } if(NULL == (connection = au_malloc(sizeof(struct SPDY_Connection)))) goto free_and_fail; connection->is_tls = is_tls; connection->ssl = ssl; connection->want_io = IO_NONE; if(NULL == (connection->host = strdup(uri->host))) goto free_and_fail; /* Here make file descriptor non-block */ spdy_socket_make_non_block(fd); spdy_socket_set_tcp_nodelay(fd); PRINT_INFO2("[INFO] SPDY protocol version = %d\n", glob_opt.spdy_proto_version); rv = spdylay_session_client_new(&(connection->session), glob_opt.spdy_proto_version, &callbacks, connection); if(rv != 0) { spdy_diec("spdylay_session_client_new", rv); } connection->fd = fd; return connection; //for GOTO free_and_fail: if(NULL != connection) { free(connection->host); free(connection); } if(is_tls) SSL_shutdown(ssl); MHD_socket_close_ (fd); if(is_tls) SSL_free(ssl); return NULL; }