#include #include #include #include #include #include #include #include #include #if MHD_VERSION < 0x00097000 #define MHD_RESULT_TYPE int #else #define MHD_RESULT_TYPE enum MHD_Result #endif struct connection { struct timespec begin; unsigned count; }; struct request { struct timespec begin; unsigned count; }; static void * worker (void *userdata) { struct MHD_Connection *con = userdata; MHD_resume_connection (con); return NULL; } static void connection_notify(void* cls, struct MHD_Connection* con, void** ctx, enum MHD_ConnectionNotificationCode code) { if (code == MHD_CONNECTION_NOTIFY_STARTED) { struct connection *c = calloc(sizeof(*c), 1); clock_gettime(CLOCK_MONOTONIC, &c->begin); *ctx = c; } else if (code == MHD_CONNECTION_NOTIFY_CLOSED) { struct connection *c = *ctx; struct timespec now, diff; clock_gettime(CLOCK_MONOTONIC, &now); diff.tv_sec = now.tv_sec - c->begin.tv_sec; if ((diff.tv_nsec = now.tv_nsec - c->begin.tv_nsec) < 0) { --diff.tv_sec; diff.tv_nsec += 1000000000; } double secs = (diff.tv_sec * 1000000000 + diff.tv_nsec) / 1000000000.0; printf("close after %.4lf seconds, completed %u requests\n", secs, c->count); free(c); } } static void * started_callback (void*cls, const char *uri, struct MHD_Connection*con) { struct request *c = calloc (sizeof(*c), 1); clock_gettime (CLOCK_MONOTONIC, &c->begin); return c; } static void completed_callback (void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe) { struct request *c = *con_cls; struct timespec now, diff; clock_gettime (CLOCK_MONOTONIC, &now); diff.tv_sec = now.tv_sec - c->begin.tv_sec; if ((diff.tv_nsec = now.tv_nsec - c->begin.tv_nsec) < 0) { --diff.tv_sec; diff.tv_nsec += 1000000000; } double secs = (diff.tv_sec * 1000000000 + diff.tv_nsec) / 1000000000.0; printf ("request done after %.4lf seconds\n", secs); free (c); } static MHD_RESULT_TYPE access_handler (void *cls, struct MHD_Connection *con, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **con_cls) { /* * hackish trick to detect if this is the first or second time the handler * has been called for a request. */ struct request *ic = (struct request*) *con_cls; if (0 == ic->count) { ic->count++; return MHD_YES; } if (1 == ic->count) { ic->count++; MHD_suspend_connection (con); pthread_t t; pthread_create (&t, NULL, &worker, con); pthread_detach (t); return MHD_YES; } { enum MHD_Result res; struct MHD_Response *resp = MHD_create_response_from_buffer (0, NULL, MHD_RESPMEM_PERSISTENT); res = MHD_queue_response (con, 200, resp); MHD_destroy_response (resp); ((struct connection*) MHD_get_connection_info(con, MHD_CONNECTION_INFO_SOCKET_CONTEXT)->socket_context)->count++; return res; } } int main (int argc, const char *argv[]) { int flags = MHD_USE_EPOLL_INTERNAL_THREAD | MHD_USE_ITC | MHD_ALLOW_SUSPEND_RESUME; struct MHD_Daemon *d = MHD_start_daemon (flags, 8080, NULL, NULL, &access_handler, NULL, MHD_OPTION_NOTIFY_COMPLETED, &completed_callback, NULL, MHD_OPTION_URI_LOG_CALLBACK, &started_callback, NULL, MHD_OPTION_NOTIFY_CONNECTION, &connection_notify, NULL, MHD_OPTION_CONNECTION_TIMEOUT, 5u, MHD_OPTION_END); pause (); MHD_stop_daemon (d); return 0; }