/** * Fork child that connects via GnuTLS-CLI to our @a port. Allows us to * talk to our port over a socket in @a sp without having to worry * about TLS. * * @param location where the socket is returned * @return -1 on error, otherwise PID of TLS child process */ static pid_t gnutlscli_connect (int *sock, uint16_t port) { pid_t chld; int sp[2]; char destination[30]; if (0 != socketpair (AF_UNIX, SOCK_STREAM, 0, sp)) return -1; chld = fork (); if (0 != chld) { *sock = sp[1]; MHD_socket_close_chk_ (sp[0]); return chld; } MHD_socket_close_chk_ (sp[1]); (void) close (0); (void) close (1); dup2 (sp[0], 0); dup2 (sp[0], 1); MHD_socket_close_chk_ (sp[0]); if (TLS_CLI_GNUTLS == use_tls_tool) { snprintf (destination, sizeof(destination), "%u", (unsigned int) port); execlp ("gnutls-cli", "gnutls-cli", "--insecure", "-p", destination, "localhost", (char *) NULL); } else if (TLS_CLI_OPENSSL == use_tls_tool) { snprintf (destination, sizeof(destination), "localhost:%u", (unsigned int) port); execlp ("openssl", "openssl", "s_client", "-connect", destination, "-verify", "0", (char *) NULL); } _exit (1); }
static int test_tls_session_time_out (gnutls_session_t session, int port) { int ret; MHD_socket sd; struct sockaddr_in sa; sd = socket (AF_INET, SOCK_STREAM, 0); if (sd == MHD_INVALID_SOCKET) { 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 (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_chk_ (sd); return -1; } ret = gnutls_handshake (session); if (ret < 0) { fprintf (stderr, "Handshake failed\n"); MHD_socket_close_chk_ (sd); return -1; } (void)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_chk_ (sd); return -1; } MHD_socket_close_chk_ (sd); return 0; }
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_ERROR_LOG, 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_chk_(fd); return "MHD_get_fdset() failed"; } tv.tv_sec = 0; tv.tv_usec = 1000; if (-1 == MHD_SYS_select_ (max + 1, &rs, &ws, &es, &tv)) { if (EINTR != errno) abort (); } MHD_run (d); } fd = MHD_quiesce_daemon (d); if (MHD_INVALID_SOCKET == fd) { MHD_stop_daemon (d); return "MHD_quiesce_daemon() failed in ServeOneRequest()"; } MHD_stop_daemon (d); return done ? NULL : "Requests was not served by ServeOneRequest()"; }
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_ERROR_LOG, 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) && (NULL != multi) ) { 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; if (-1 == select (maxposixs + 1, &rs, &ws, &es, &tv)) { if (EINTR != errno) abort (); } curl_multi_perform (multi, &running); if (0 == running) { msg = curl_multi_info_read (multi, &running); if (NULL == msg) 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 (0 == i) { /* 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 (NULL != multi) { curl_multi_remove_handle (multi, c); curl_easy_cleanup (c); curl_multi_cleanup (multi); } MHD_stop_daemon (d); MHD_socket_close_chk_ (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_ERROR_LOG | MHD_USE_ITC | 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_ERROR_LOG | MHD_USE_ITC | 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_chk_(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_chk_(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_chk_(fd); return 2; } curl_easy_cleanup (c); MHD_stop_daemon (d); MHD_socket_close_chk_(fd); return 0; }
int main (int argc, char *const *argv) { int i; time_t start_t, end_t; int result = 0; MHD_THRD_RTRN_TYPE_ (MHD_THRD_CALL_SPEC_ *test_func)(void* data); #ifdef MHD_WINSOCK_SOCKETS WORD ver_req; WSADATA wsa_data; int err; #endif /* MHD_WINSOCK_SOCKETS */ bool test_poll; test_poll = has_in_name(argv[0], "_poll"); if (!test_poll) test_func = &select_thread; else { #ifndef HAVE_POLL return 77; #else /* ! HAVE_POLL */ test_func = &poll_thread; #endif /* ! HAVE_POLL */ } #ifdef MHD_WINSOCK_SOCKETS ver_req = MAKEWORD(2, 2); err = WSAStartup(ver_req, &wsa_data); if (err != 0 || MAKEWORD(2, 2) != wsa_data.wVersion) { printf("WSAStartup() failed\n"); WSACleanup(); return 99; } #endif /* MHD_WINSOCK_SOCKETS */ /* try several times to ensure that accidental incoming connection * didn't interfere with test results */ for (i = 0; i < 5 && result == 0; i++) { MHD_thread_handle_ sel_thrd; /* fprintf(stdout, "Creating, binding and listening socket...\n"); */ MHD_socket listen_socket = start_socket_listen (AF_INET); if (MHD_INVALID_SOCKET == listen_socket) return 99; check_err = !0; /* fprintf (stdout, "Starting select() thread...\n"); */ #if defined(MHD_USE_POSIX_THREADS) if (0 != pthread_create (&sel_thrd, NULL, test_func, &listen_socket)) { MHD_socket_close_chk_ (listen_socket); fprintf (stderr, "Can't start thread\n"); return 99; } #elif defined(MHD_USE_W32_THREADS) sel_thrd = (HANDLE)_beginthreadex (NULL, 0, test_func, &listen_socket, 0, NULL); if (0 == (sel_thrd)) { MHD_socket_close_chk_ (listen_socket); fprintf (stderr, "Can't start select() thread\n"); return 99; } #else #error No threading lib available #endif /* fprintf (stdout, "Waiting...\n"); */ local_sleep(1); /* make sure that select() is started */ /* fprintf (stdout, "Shutting down socket...\n"); */ start_t = time (NULL); shutdown (listen_socket, SHUT_RDWR); /* fprintf (stdout, "Waiting for thread to finish...\n"); */ if (!MHD_join_thread_(sel_thrd)) { MHD_socket_close_chk_(listen_socket); fprintf (stderr, "Can't join select() thread\n"); return 99; } if (check_err) { MHD_socket_close_chk_(listen_socket); fprintf (stderr, "Error in waiting thread\n"); return 99; } end_t = time (NULL); /* fprintf (stdout, "Thread finished.\n"); */ MHD_socket_close_chk_(listen_socket); if (start_t == (time_t)-1 || end_t == (time_t)-1) { MHD_socket_close_chk_(listen_socket); fprintf (stderr, "Can't get current time\n"); return 99; } if (end_t - start_t > 3) result++; } #ifdef MHD_WINSOCK_SOCKETS WSACleanup(); #endif /* MHD_WINSOCK_SOCKETS */ return result; }
static MHD_socket start_socket_listen(int domain) { /* Create sockets similarly to daemon.c */ MHD_socket fd; int cloexec_set; struct sockaddr_in sock_addr; socklen_t addrlen; #ifdef MHD_WINSOCK_SOCKETS unsigned long flags = 1; #else /* MHD_POSIX_SOCKETS */ int flags; #endif /* MHD_POSIX_SOCKETS */ #if defined(MHD_POSIX_SOCKETS) && defined(SOCK_CLOEXEC) fd = socket (domain, SOCK_STREAM | SOCK_CLOEXEC, 0); cloexec_set = 1; #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 = 1; #else /* !SOCK_CLOEXEC */ fd = socket (domain, SOCK_STREAM, 0); cloexec_set = 0; #endif /* !SOCK_CLOEXEC */ if ( (MHD_INVALID_SOCKET == fd) && (cloexec_set) ) { fd = socket (domain, SOCK_STREAM, 0); cloexec_set = 0; } if (MHD_INVALID_SOCKET == fd) { fprintf (stderr, "Can't create socket: %u\n", (unsigned)sock_errno); return MHD_INVALID_SOCKET; } if (!cloexec_set) { #ifdef MHD_WINSOCK_SOCKETS if (!SetHandleInformation ((HANDLE)fd, HANDLE_FLAG_INHERIT, 0)) fprintf (stderr, "Failed to make socket non-inheritable: %u\n", (unsigned int)GetLastError ()); #else /* MHD_POSIX_SOCKETS */ flags = fcntl (fd, F_GETFD); if ( ( (-1 == flags) || ( (flags != (flags | FD_CLOEXEC)) && (0 != fcntl (fd, F_SETFD, flags | FD_CLOEXEC)) ) ) ) fprintf (stderr, "Failed to make socket non-inheritable: %s\n", MHD_socket_last_strerr_ ()); #endif /* MHD_POSIX_SOCKETS */ } memset (&sock_addr, 0, sizeof (struct sockaddr_in)); sock_addr.sin_family = AF_INET; sock_addr.sin_port = htons (0); #if HAVE_SOCKADDR_IN_SIN_LEN sock_addr.sin_len = sizeof (struct sockaddr_in); #endif addrlen = sizeof (struct sockaddr_in); if (bind (fd, (const struct sockaddr*) &sock_addr, addrlen) < 0) { fprintf (stderr, "Failed to bind socket: %u\n", (unsigned)sock_errno); MHD_socket_close_chk_ (fd); return MHD_INVALID_SOCKET; } #ifdef MHD_WINSOCK_SOCKETS if (0 != ioctlsocket (fd, FIONBIO, &flags)) { fprintf (stderr, "Failed to make socket non-blocking: %u\n", (unsigned)sock_errno); MHD_socket_close_chk_ (fd); return MHD_INVALID_SOCKET; } #else /* MHD_POSIX_SOCKETS */ flags = fcntl (fd, F_GETFL); if ( ( (-1 == flags) || ( (flags != (flags | O_NONBLOCK)) && (0 != fcntl (fd, F_SETFL, flags | O_NONBLOCK)) ) ) ) { fprintf (stderr, "Failed to make socket non-blocking: %s\n", MHD_socket_last_strerr_ ()); MHD_socket_close_chk_ (fd); return MHD_INVALID_SOCKET; } #endif /* MHD_POSIX_SOCKETS */ if (listen(fd, SOMAXCONN) < 0) { fprintf (stderr, "Failed to listen on socket: %u\n", (unsigned)sock_errno); MHD_socket_close_chk_ (fd); return MHD_INVALID_SOCKET; } return fd; }
/** * Shutdown and destroy an HTTP daemon. * * @param daemon daemon to stop * @ingroup event */ void MHD_daemon_destroy (struct MHD_Daemon *daemon) { MHD_socket fd; daemon->shutdown = true; if (daemon->was_quiesced) fd = MHD_INVALID_SOCKET; /* Do not use FD if daemon was quiesced */ else fd = daemon->listen_socket; /* FIXME: convert from here to microhttpd2-style API! */ if (NULL != daemon->worker_pool) { /* Master daemon with worker pool. */ stop_workers (daemon); } else { mhd_assert (0 == daemon->worker_pool_size); /* Worker daemon or single-thread daemon. */ if (MHD_TM_EXTERNAL_EVENT_LOOP != daemon->threading_mode) { /* Worker daemon or single daemon with internal thread(s). */ /* Separate thread(s) is used for polling sockets. */ if (MHD_ITC_IS_VALID_(daemon->itc)) { if (! MHD_itc_activate_ (daemon->itc, "e")) MHD_PANIC (_("Failed to signal shutdown via inter-thread communication channel")); } else { #ifdef HAVE_LISTEN_SHUTDOWN if (MHD_INVALID_SOCKET != fd) { if (NULL == daemon->master) (void) shutdown (fd, SHUT_RDWR); } else #endif /* HAVE_LISTEN_SHUTDOWN */ mhd_assert (false); /* Should never happen */ } if (! MHD_join_thread_ (daemon->pid.handle)) { MHD_PANIC (_("Failed to join a thread\n")); } /* close_all_connections() was called in daemon thread. */ } else { /* No internal threads are used for polling sockets (external event loop) */ MHD_daemon_close_all_connections_ (daemon); } if (MHD_ITC_IS_VALID_ (daemon->itc)) MHD_itc_destroy_chk_ (daemon->itc); #ifdef EPOLL_SUPPORT if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && (-1 != daemon->epoll_fd) ) MHD_socket_close_chk_ (daemon->epoll_fd); #if defined(HTTPS_SUPPORT) && defined(UPGRADE_SUPPORT) if ( (MHD_ELS_EPOLL == daemon->event_loop_syscall) && (-1 != daemon->epoll_upgrade_fd) ) MHD_socket_close_chk_ (daemon->epoll_upgrade_fd); #endif /* HTTPS_SUPPORT && UPGRADE_SUPPORT */ #endif /* EPOLL_SUPPORT */ MHD_mutex_destroy_chk_ (&daemon->cleanup_connection_mutex); } if (NULL != daemon->master) return; /* Cleanup that should be done only one time in master/single daemon. * Do not perform this cleanup in worker daemons. */ if (MHD_INVALID_SOCKET != fd) MHD_socket_close_chk_ (fd); /* TLS clean up */ #ifdef HTTPS_SUPPORT if (NULL != daemon->tls_api) { #if FIXME_TLS_API if (daemon->have_dhparams) { gnutls_dh_params_deinit (daemon->https_mem_dhparams); daemon->have_dhparams = false; } gnutls_priority_deinit (daemon->priority_cache); if (daemon->x509_cred) gnutls_certificate_free_credentials (daemon->x509_cred); #endif } #endif /* HTTPS_SUPPORT */ #ifdef DAUTH_SUPPORT free (daemon->nnc); MHD_mutex_destroy_chk_ (&daemon->nnc_lock); #endif MHD_mutex_destroy_chk_ (&daemon->per_ip_connection_mutex); free (daemon); }