/* This file is part of libmicrohttpd Copyright (C) 2007-2015 Daniel Pittman and Christian Grothoff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file microhttpd/internal.h * @brief internal shared structures * @author Daniel Pittman * @author Christian Grothoff */ #ifndef INTERNAL_H #define INTERNAL_H #include "platform.h" #include "microhttpd.h" #include "platform_interface.h" #if HTTPS_SUPPORT #include #endif #if EPOLL_SUPPORT #include #endif #if HAVE_NETINET_TCP_H /* for TCP_FASTOPEN */ #include #endif /** * Should we perform additional sanity checks at runtime (on our internal * invariants)? This may lead to aborts, but can be useful for debugging. */ #define EXTRA_CHECKS MHD_NO #define MHD_MAX(a,b) ((a)<(b)) ? (b) : (a) #define MHD_MIN(a,b) ((a)<(b)) ? (a) : (b) /** * Minimum size by which MHD tries to increment read/write buffers. * We usually begin with half the available pool space for the * IO-buffer, but if absolutely needed we additively grow by the * number of bytes given here (up to -- theoretically -- the full pool * space). */ #define MHD_BUF_INC_SIZE 1024 /** * Handler for fatal errors. */ extern MHD_PanicCallback mhd_panic; /** * Closure argument for "mhd_panic". */ extern void *mhd_panic_cls; /* If we have Clang or gcc >= 4.5, use __buildin_unreachable() */ #if defined(__clang__) || (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) #define BUILTIN_NOT_REACHED __builtin_unreachable() #else #define BUILTIN_NOT_REACHED #endif #if HAVE_MESSAGES /** * Trigger 'panic' action based on fatal errors. * * @param msg error message (const char *) */ #define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, msg); BUILTIN_NOT_REACHED; } while (0) #else /** * Trigger 'panic' action based on fatal errors. * * @param msg error message (const char *) */ #define MHD_PANIC(msg) do { mhd_panic (mhd_panic_cls, __FILE__, __LINE__, NULL); BUILTIN_NOT_REACHED; } while (0) #endif /** * State of the socket with respect to epoll (bitmask). */ enum MHD_EpollState { /** * The socket is not involved with a defined state in epoll right * now. */ MHD_EPOLL_STATE_UNREADY = 0, /** * epoll told us that data was ready for reading, and we did * not consume all of it yet. */ MHD_EPOLL_STATE_READ_READY = 1, /** * epoll told us that space was available for writing, and we did * not consume all of it yet. */ MHD_EPOLL_STATE_WRITE_READY = 2, /** * Is this connection currently in the 'eready' EDLL? */ MHD_EPOLL_STATE_IN_EREADY_EDLL = 4, /** * Is this connection currently in the 'epoll' set? */ MHD_EPOLL_STATE_IN_EPOLL_SET = 8, /** * Is this connection currently suspended? */ MHD_EPOLL_STATE_SUSPENDED = 16 }; /** * What is this connection waiting for? */ enum MHD_ConnectionEventLoopInfo { /** * We are waiting to be able to read. */ MHD_EVENT_LOOP_INFO_READ = 0, /** * We are waiting to be able to write. */ MHD_EVENT_LOOP_INFO_WRITE = 1, /** * We are waiting for the application to provide data. */ MHD_EVENT_LOOP_INFO_BLOCK = 2, /** * We are finished and are awaiting cleanup. */ MHD_EVENT_LOOP_INFO_CLEANUP = 3 }; /** * Maximum length of a nonce in digest authentication. 32(MD5 Hex) + * 8(Timestamp Hex) + 1(NULL); hence 41 should suffice, but Opera * (already) takes more (see Mantis #1633), so we've increased the * value to support something longer... */ #define MAX_NONCE_LENGTH 129 /** * A structure representing the internal holder of the * nonce-nc map. */ struct MHD_NonceNc { /** * Nonce counter, a value that increases for each subsequent * request for the same nonce. */ unsigned long int nc; /** * Nonce value: */ char nonce[MAX_NONCE_LENGTH]; }; #if HAVE_MESSAGES /** * fprintf-like helper function for logging debug * messages. */ void MHD_DLOG (const struct MHD_Daemon *daemon, const char *format, ...); #endif /** * Header or cookie in HTTP request or response. */ struct MHD_HTTP_Header { /** * Headers are kept in a linked list. */ struct MHD_HTTP_Header *next; /** * The name of the header (key), without * the colon. */ char *header; /** * The value of the header. */ char *value; /** * Type of the header (where in the HTTP * protocol is this header from). */ enum MHD_ValueKind kind; }; /** * Representation of a response. */ struct MHD_Response { /** * Headers to send for the response. Initially * the linked list is created in inverse order; * the order should be inverted before sending! */ struct MHD_HTTP_Header *first_header; /** * Buffer pointing to data that we are supposed * to send as a response. */ char *data; /** * Closure to give to the content reader @e crc * and content reader free callback @e crfc. */ void *crc_cls; /** * How do we get more data? NULL if we are * given all of the data up front. */ MHD_ContentReaderCallback crc; /** * NULL if data must not be freed, otherwise * either user-specified callback or "&free". */ MHD_ContentReaderFreeCallback crfc; /** * Mutex to synchronize access to @e data, @e size and * @e reference_count. */ MHD_mutex_ mutex; /** * Set to #MHD_SIZE_UNKNOWN if size is not known. */ uint64_t total_size; /** * At what offset in the stream is the * beginning of @e data located? */ uint64_t data_start; /** * Offset to start reading from when using @e fd. */ off_t fd_off; /** * Number of bytes ready in @e data (buffer may be larger * than what is filled with payload). */ size_t data_size; /** * Size of the data buffer @e data. */ size_t data_buffer_size; /** * Reference count for this response. Free * once the counter hits zero. */ unsigned int reference_count; /** * File-descriptor if this response is FD-backed. */ int fd; /** * Flags set for the MHD response. */ enum MHD_ResponseFlags flags; }; /** * States in a state machine for a connection. * * Transitions are any-state to CLOSED, any state to state+1, * FOOTERS_SENT to INIT. CLOSED is the terminal state and * INIT the initial state. * * Note that transitions for *reading* happen only after * the input has been processed; transitions for * *writing* happen after the respective data has been * put into the write buffer (the write does not have * to be completed yet). A transition to CLOSED or INIT * requires the write to be complete. */ enum MHD_CONNECTION_STATE { /** * Connection just started (no headers received). * Waiting for the line with the request type, URL and version. */ MHD_CONNECTION_INIT = 0, /** * 1: We got the URL (and request type and version). Wait for a header line. */ MHD_CONNECTION_URL_RECEIVED = MHD_CONNECTION_INIT + 1, /** * 2: We got part of a multi-line request header. Wait for the rest. */ MHD_CONNECTION_HEADER_PART_RECEIVED = MHD_CONNECTION_URL_RECEIVED + 1, /** * 3: We got the request headers. Process them. */ MHD_CONNECTION_HEADERS_RECEIVED = MHD_CONNECTION_HEADER_PART_RECEIVED + 1, /** * 4: We have processed the request headers. Send 100 continue. */ MHD_CONNECTION_HEADERS_PROCESSED = MHD_CONNECTION_HEADERS_RECEIVED + 1, /** * 5: We have processed the headers and need to send 100 CONTINUE. */ MHD_CONNECTION_CONTINUE_SENDING = MHD_CONNECTION_HEADERS_PROCESSED + 1, /** * 6: We have sent 100 CONTINUE (or do not need to). Read the message body. */ MHD_CONNECTION_CONTINUE_SENT = MHD_CONNECTION_CONTINUE_SENDING + 1, /** * 7: We got the request body. Wait for a line of the footer. */ MHD_CONNECTION_BODY_RECEIVED = MHD_CONNECTION_CONTINUE_SENT + 1, /** * 8: We got part of a line of the footer. Wait for the * rest. */ MHD_CONNECTION_FOOTER_PART_RECEIVED = MHD_CONNECTION_BODY_RECEIVED + 1, /** * 9: We received the entire footer. Wait for a response to be queued * and prepare the response headers. */ MHD_CONNECTION_FOOTERS_RECEIVED = MHD_CONNECTION_FOOTER_PART_RECEIVED + 1, /** * 10: We have prepared the response headers in the writ buffer. * Send the response headers. */ MHD_CONNECTION_HEADERS_SENDING = MHD_CONNECTION_FOOTERS_RECEIVED + 1, /** * 11: We have sent the response headers. Get ready to send the body. */ MHD_CONNECTION_HEADERS_SENT = MHD_CONNECTION_HEADERS_SENDING + 1, /** * 12: We are ready to send a part of a non-chunked body. Send it. */ MHD_CONNECTION_NORMAL_BODY_READY = MHD_CONNECTION_HEADERS_SENT + 1, /** * 13: We are waiting for the client to provide more * data of a non-chunked body. */ MHD_CONNECTION_NORMAL_BODY_UNREADY = MHD_CONNECTION_NORMAL_BODY_READY + 1, /** * 14: We are ready to send a chunk. */ MHD_CONNECTION_CHUNKED_BODY_READY = MHD_CONNECTION_NORMAL_BODY_UNREADY + 1, /** * 15: We are waiting for the client to provide a chunk of the body. */ MHD_CONNECTION_CHUNKED_BODY_UNREADY = MHD_CONNECTION_CHUNKED_BODY_READY + 1, /** * 16: We have sent the response body. Prepare the footers. */ MHD_CONNECTION_BODY_SENT = MHD_CONNECTION_CHUNKED_BODY_UNREADY + 1, /** * 17: We have prepared the response footer. Send it. */ MHD_CONNECTION_FOOTERS_SENDING = MHD_CONNECTION_BODY_SENT + 1, /** * 18: We have sent the response footer. Shutdown or restart. */ MHD_CONNECTION_FOOTERS_SENT = MHD_CONNECTION_FOOTERS_SENDING + 1, /** * 19: This connection is to be closed. */ MHD_CONNECTION_CLOSED = MHD_CONNECTION_FOOTERS_SENT + 1, /** * 20: This connection is finished (only to be freed) */ MHD_CONNECTION_IN_CLEANUP = MHD_CONNECTION_CLOSED + 1, /* * SSL/TLS connection states */ /** * The initial connection state for all secure connectoins * Handshake messages will be processed in this state & while * in the 'MHD_TLS_HELLO_REQUEST' state */ MHD_TLS_CONNECTION_INIT = MHD_CONNECTION_IN_CLEANUP + 1 }; /** * Should all state transitions be printed to stderr? */ #define DEBUG_STATES MHD_NO #if HAVE_MESSAGES #if DEBUG_STATES const char * MHD_state_to_string (enum MHD_CONNECTION_STATE state); #endif #endif /** * Function to receive plaintext data. * * @param conn the connection struct * @param write_to where to write received data * @param max_bytes maximum number of bytes to receive * @return number of bytes written to write_to */ typedef ssize_t (*ReceiveCallback) (struct MHD_Connection *conn, void *write_to, size_t max_bytes); /** * Function to transmit plaintext data. * * @param conn the connection struct * @param read_from where to read data to transmit * @param max_bytes maximum number of bytes to transmit * @return number of bytes transmitted */ typedef ssize_t (*TransmitCallback) (struct MHD_Connection *conn, const void *write_to, size_t max_bytes); /** * State kept for each HTTP request. */ struct MHD_Connection { #if EPOLL_SUPPORT /** * Next pointer for the EDLL listing connections that are epoll-ready. */ struct MHD_Connection *nextE; /** * Previous pointer for the EDLL listing connections that are epoll-ready. */ struct MHD_Connection *prevE; #endif /** * Next pointer for the DLL describing our IO state. */ struct MHD_Connection *next; /** * Previous pointer for the DLL describing our IO state. */ struct MHD_Connection *prev; /** * Next pointer for the XDLL organizing connections by timeout. * This DLL can be either the * 'manual_timeout_head/manual_timeout_tail' or the * 'normal_timeout_head/normal_timeout_tail', depending on whether a * custom timeout is set for the connection. */ struct MHD_Connection *nextX; /** * Previous pointer for the XDLL organizing connections by timeout. */ struct MHD_Connection *prevX; /** * Reference to the MHD_Daemon struct. */ struct MHD_Daemon *daemon; /** * Linked list of parsed headers. */ struct MHD_HTTP_Header *headers_received; /** * Tail of linked list of parsed headers. */ struct MHD_HTTP_Header *headers_received_tail; /** * Response to transmit (initially NULL). */ struct MHD_Response *response; /** * The memory pool is created whenever we first read * from the TCP stream and destroyed at the end of * each request (and re-created for the next request). * In the meantime, this pointer is NULL. The * pool is used for all connection-related data * except for the response (which maybe shared between * connections) and the IP address (which persists * across individual requests). */ struct MemoryPool *pool; /** * We allow the main application to associate some pointer with the * HTTP request, which is passed to each #MHD_AccessHandlerCallback * and some other API calls. Here is where we store it. (MHD does * not know or care what it is). */ void *client_context; /** * We allow the main application to associate some pointer with the * TCP connection (which may span multiple HTTP requests). Here is * where we store it. (MHD does not know or care what it is). * The location is given to the #MHD_NotifyConnectionCallback and * also accessible via #MHD_CONNECTION_INFO_SOCKET_CONTEXT. */ void *socket_context; /** * Request method. Should be GET/POST/etc. Allocated * in pool. */ char *method; /** * Requested URL (everything after "GET" only). Allocated * in pool. */ char *url; /** * HTTP version string (i.e. http/1.1). Allocated * in pool. */ char *version; /** * Buffer for reading requests. Allocated * in pool. Actually one byte larger than * @e read_buffer_size (if non-NULL) to allow for * 0-termination. */ char *read_buffer; /** * Buffer for writing response (headers only). Allocated * in pool. */ char *write_buffer; /** * Last incomplete header line during parsing of headers. * Allocated in pool. Only valid if state is * either #MHD_CONNECTION_HEADER_PART_RECEIVED or * #MHD_CONNECTION_FOOTER_PART_RECEIVED. */ char *last; /** * Position after the colon on the last incomplete header * line during parsing of headers. * Allocated in pool. Only valid if state is * either #MHD_CONNECTION_HEADER_PART_RECEIVED or * #MHD_CONNECTION_FOOTER_PART_RECEIVED. */ char *colon; /** * Foreign address (of length @e addr_len). MALLOCED (not * in pool!). */ struct sockaddr *addr; /** * Thread handle for this connection (if we are using * one thread per connection). */ MHD_thread_handle_ pid; /** * Size of read_buffer (in bytes). This value indicates * how many bytes we're willing to read into the buffer; * the real buffer is one byte longer to allow for * adding zero-termination (when needed). */ size_t read_buffer_size; /** * Position where we currently append data in * read_buffer (last valid position). */ size_t read_buffer_offset; /** * Size of write_buffer (in bytes). */ size_t write_buffer_size; /** * Offset where we are with sending from write_buffer. */ size_t write_buffer_send_offset; /** * Last valid location in write_buffer (where do we * append and up to where is it safe to send?) */ size_t write_buffer_append_offset; /** * How many more bytes of the body do we expect * to read? #MHD_SIZE_UNKNOWN for unknown. */ uint64_t remaining_upload_size; /** * Current write position in the actual response * (excluding headers, content only; should be 0 * while sending headers). */ uint64_t response_write_position; /** * Position in the 100 CONTINUE message that * we need to send when receiving http 1.1 requests. */ size_t continue_message_write_offset; /** * Length of the foreign address. */ socklen_t addr_len; /** * Last time this connection had any activity * (reading or writing). */ time_t last_activity; /** * After how many seconds of inactivity should * this connection time out? Zero for no timeout. */ unsigned int connection_timeout; /** * Did we ever call the "default_handler" on this connection? * (this flag will determine if we call the 'notify_completed' * handler when the connection closes down). */ int client_aware; /** * Socket for this connection. Set to #MHD_INVALID_SOCKET if * this connection has died (daemon should clean * up in that case). */ MHD_socket socket_fd; /** * Has this socket been closed for reading (i.e. other side closed * the connection)? If so, we must completely close the connection * once we are done sending our response (and stop trying to read * from this socket). */ int read_closed; /** * Set to #MHD_YES if the thread has been joined. */ int thread_joined; /** * Are we currently inside the "idle" handler (to avoid recursively invoking it). */ int in_idle; #if EPOLL_SUPPORT /** * What is the state of this socket in relation to epoll? */ enum MHD_EpollState epoll_state; #endif /** * State in the FSM for this connection. */ enum MHD_CONNECTION_STATE state; /** * What is this connection waiting for? */ enum MHD_ConnectionEventLoopInfo event_loop_info; /** * HTTP response code. Only valid if response object * is already set. */ unsigned int responseCode; /** * Set to MHD_YES if the response's content reader * callback failed to provide data the last time * we tried to read from it. In that case, the * write socket should be marked as unready until * the CRC call succeeds. */ int response_unready; /** * Are we receiving with chunked encoding? This will be set to * MHD_YES after we parse the headers and are processing the body * with chunks. After we are done with the body and we are * processing the footers; once the footers are also done, this will * be set to MHD_NO again (before the final call to the handler). */ int have_chunked_upload; /** * If we are receiving with chunked encoding, where are we right * now? Set to 0 if we are waiting to receive the chunk size; * otherwise, this is the size of the current chunk. A value of * zero is also used when we're at the end of the chunks. */ size_t current_chunk_size; /** * If we are receiving with chunked encoding, where are we currently * with respect to the current chunk (at what offset / position)? */ size_t current_chunk_offset; /** * Handler used for processing read connection operations */ int (*read_handler) (struct MHD_Connection *connection); /** * Handler used for processing write connection operations */ int (*write_handler) (struct MHD_Connection *connection); /** * Handler used for processing idle connection operations */ int (*idle_handler) (struct MHD_Connection *connection); /** * Function used for reading HTTP request stream. */ ReceiveCallback recv_cls; /** * Function used for writing HTTP response stream. */ TransmitCallback send_cls; #if HTTPS_SUPPORT /** * State required for HTTPS/SSL/TLS support. */ SSL* tls_session; /** * Memory location to return for protocol session info. */ const char* protocol; /** * Memory location to return for protocol session info. */ const char* cipher; /** * Could it be that we are ready to read due to TLS buffers * even though the socket is not? */ int tls_read_ready; #endif /** * Is the connection suspended? */ int suspended; /** * Is the connection wanting to resume? */ int resuming; }; /** * Signature of function called to log URI accesses. * * @param cls closure * @param uri uri being accessed * @param con connection handle * @return new closure */ typedef void * (*LogCallback)(void * cls, const char * uri, struct MHD_Connection *con); /** * Signature of function called to unescape URIs. See also * #MHD_http_unescape(). * * @param cls closure * @param conn connection handle * @param uri 0-terminated string to unescape (should be updated) * @return length of the resulting string */ typedef size_t (*UnescapeCallback)(void *cls, struct MHD_Connection *conn, char *uri); /** * State kept for each MHD daemon. All connections are kept in two * doubly-linked lists. The first one reflects the state of the * connection in terms of what operations we are waiting for (read, * write, locally blocked, cleanup) whereas the second is about its * timeout state (default or custom). */ struct MHD_Daemon { /** * Callback function for all requests. */ MHD_AccessHandlerCallback default_handler; /** * Closure argument to default_handler. */ void *default_handler_cls; /** * Head of doubly-linked list of our current, active connections. */ struct MHD_Connection *connections_head; /** * Tail of doubly-linked list of our current, active connections. */ struct MHD_Connection *connections_tail; /** * Head of doubly-linked list of our current but suspended connections. */ struct MHD_Connection *suspended_connections_head; /** * Tail of doubly-linked list of our current but suspended connections. */ struct MHD_Connection *suspended_connections_tail; /** * Head of doubly-linked list of connections to clean up. */ struct MHD_Connection *cleanup_head; /** * Tail of doubly-linked list of connections to clean up. */ struct MHD_Connection *cleanup_tail; #if EPOLL_SUPPORT /** * Head of EDLL of connections ready for processing (in epoll mode). */ struct MHD_Connection *eready_head; /** * Tail of EDLL of connections ready for processing (in epoll mode) */ struct MHD_Connection *eready_tail; #endif /** * Head of the XDLL of ALL connections with a default ('normal') * timeout, sorted by timeout (earliest at the tail, most recently * used connection at the head). MHD can just look at the tail of * this list to determine the timeout for all of its elements; * whenever there is an event of a connection, the connection is * moved back to the tail of the list. * * All connections by default start in this list; if a custom * timeout that does not match 'connection_timeout' is set, they * are moved to the 'manual_timeout_head'-XDLL. */ struct MHD_Connection *normal_timeout_head; /** * Tail of the XDLL of ALL connections with a default timeout, * sorted by timeout (earliest timeout at the tail). */ struct MHD_Connection *normal_timeout_tail; /** * Head of the XDLL of ALL connections with a non-default/custom * timeout, unsorted. MHD will do a O(n) scan over this list to * determine the current timeout. */ struct MHD_Connection *manual_timeout_head; /** * Tail of the XDLL of ALL connections with a non-default/custom * timeout, unsorted. */ struct MHD_Connection *manual_timeout_tail; /** * Function to call to check if we should accept or reject an * incoming request. May be NULL. */ MHD_AcceptPolicyCallback apc; /** * Closure argument to apc. */ void *apc_cls; /** * Function to call when we are done processing * a particular request. May be NULL. */ MHD_RequestCompletedCallback notify_completed; /** * Closure argument to notify_completed. */ void *notify_completed_cls; /** * Function to call when we are starting/stopping * a connection. May be NULL. */ MHD_NotifyConnectionCallback notify_connection; /** * Closure argument to notify_connection. */ void *notify_connection_cls; /** * Function to call with the full URI at the * beginning of request processing. May be NULL. *

* Returns the initial pointer to internal state * kept by the client for the request. */ LogCallback uri_log_callback; /** * Closure argument to @e uri_log_callback. */ void *uri_log_callback_cls; /** * Function to call when we unescape escape sequences. */ UnescapeCallback unescape_callback; /** * Closure for @e unescape_callback. */ void *unescape_callback_cls; #if HAVE_MESSAGES /** * Function for logging error messages (if we * support error reporting). */ void (*custom_error_log) (void *cls, const char *fmt, va_list va); /** * Closure argument to custom_error_log. */ void *custom_error_log_cls; #endif /** * Pointer to master daemon (NULL if this is the master) */ struct MHD_Daemon *master; /** * Worker daemons (one per thread) */ struct MHD_Daemon *worker_pool; /** * Table storing number of connections per IP */ void *per_ip_connection_count; /** * Size of the per-connection memory pools. */ size_t pool_size; /** * Increment for growth of the per-connection memory pools. */ size_t pool_increment; /** * Size of threads created by MHD. */ size_t thread_stack_size; /** * Number of worker daemons */ unsigned int worker_pool_size; /** * The select thread handle (if we have internal select) */ MHD_thread_handle_ pid; /** * Mutex for per-IP connection counts. */ MHD_mutex_ per_ip_connection_mutex; /** * Mutex for (modifying) access to the "cleanup" connection DLL. */ MHD_mutex_ cleanup_connection_mutex; /** * Listen socket. */ MHD_socket socket_fd; /** * Whether to allow/disallow/ignore reuse of listening address. * The semantics is the following: * 0: ignore (user did not ask for neither allow/disallow, use SO_REUSEADDR) * >0: allow (use SO_REUSEPORT on most platforms, SO_REUSEADDR on Windows) * <0: disallow (mostly no action, SO_EXCLUSIVEADDRUSE on Windows) */ int listening_address_reuse; #if EPOLL_SUPPORT /** * File descriptor associated with our epoll loop. */ int epoll_fd; /** * MHD_YES if the listen socket is in the 'epoll' set, * MHD_NO if not. */ int listen_socket_in_epoll; #endif /** * Pipe we use to signal shutdown, unless * 'HAVE_LISTEN_SHUTDOWN' is defined AND we have a listen * socket (which we can then 'shutdown' to stop listening). * MHD can be build with usage of socketpair instead of * pipe (forced on W32). */ MHD_pipe wpipe[2]; /** * Are we shutting down? */ int shutdown; /* * Do we need to process resuming connections? */ int resuming; /** * Number of active parallel connections. */ unsigned int connections; /** * Limit on the number of parallel connections. */ unsigned int connection_limit; /** * After how many seconds of inactivity should * connections time out? Zero for no timeout. */ unsigned int connection_timeout; /** * Maximum number of connections per IP, or 0 for * unlimited. */ unsigned int per_ip_connection_limit; /** * Daemon's flags (bitfield). */ enum MHD_FLAG options; /** * Listen port. */ uint16_t port; #if HTTPS_SUPPORT SSL_CTX* tls_context; /** * Pointer to our SSL/TLS key (in PEM) in memory. */ const char *https_mem_key; /** * Pointer to our SSL/TLS certificate (in PEM) in memory. */ const char *https_mem_cert; /** * Pointer to 0-terminated HTTPS passphrase in memory. */ const char *https_key_password; /** * Pointer to our SSL/TLS certificate authority (in PEM) in memory. */ const char *https_mem_trust; /** * Our Diffie-Hellman parameters (in PEM) in memory. */ const char *https_mem_dhparams; /** * Pointer to SSL/TLS cipher string in memory. */ const char *https_mem_cipher; /** * For how many connections do we have 'tls_read_ready' set to MHD_YES? * Used to avoid O(n) traversal over all connections when determining * event-loop timeout (as it needs to be zero if there is any connection * which might have ready data within TLS). */ unsigned int num_tls_read_ready; #endif #ifdef DAUTH_SUPPORT /** * Character array of random values. */ const char *digest_auth_random; /** * An array that contains the map nonce-nc. */ struct MHD_NonceNc *nnc; /** * A rw-lock for synchronizing access to `nnc'. */ MHD_mutex_ nnc_lock; /** * Size of `digest_auth_random. */ size_t digest_auth_rand_size; /** * Size of the nonce-nc array. */ unsigned int nonce_nc_size; #endif #ifdef TCP_FASTOPEN /** * The queue size for incoming SYN + DATA packets. */ unsigned int fastopen_queue_size; #endif }; #if EXTRA_CHECKS #define EXTRA_CHECK(a) do { if (!(a)) abort(); } while (0) #else #define EXTRA_CHECK(a) #endif /** * Insert an element at the head of a DLL. Assumes that head, tail and * element are structs with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to insert */ #define DLL_insert(head,tail,element) do { \ EXTRA_CHECK (NULL == (element)->next); \ EXTRA_CHECK (NULL == (element)->prev); \ (element)->next = (head); \ (element)->prev = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prev = element; \ (head) = (element); } while (0) /** * Remove an element from a DLL. Assumes * that head, tail and element are structs * with prev and next fields. * * @param head pointer to the head of the DLL * @param tail pointer to the tail of the DLL * @param element element to remove */ #define DLL_remove(head,tail,element) do { \ EXTRA_CHECK ( (NULL != (element)->next) || ((element) == (tail))); \ EXTRA_CHECK ( (NULL != (element)->prev) || ((element) == (head))); \ if ((element)->prev == NULL) \ (head) = (element)->next; \ else \ (element)->prev->next = (element)->next; \ if ((element)->next == NULL) \ (tail) = (element)->prev; \ else \ (element)->next->prev = (element)->prev; \ (element)->next = NULL; \ (element)->prev = NULL; } while (0) /** * Insert an element at the head of a XDLL. Assumes that head, tail and * element are structs with prevX and nextX fields. * * @param head pointer to the head of the XDLL * @param tail pointer to the tail of the XDLL * @param element element to insert */ #define XDLL_insert(head,tail,element) do { \ EXTRA_CHECK (NULL == (element)->nextX); \ EXTRA_CHECK (NULL == (element)->prevX); \ (element)->nextX = (head); \ (element)->prevX = NULL; \ if (NULL == (tail)) \ (tail) = element; \ else \ (head)->prevX = element; \ (head) = (element); } while (0) /** * Remove an element from a XDLL. Assumes * that head, tail and element are structs * with prevX and nextX fields. * * @param head pointer to the head of the XDLL * @param tail pointer to the tail of the XDLL * @param element element to remove */ #define XDLL_remove(head,tail,element) do { \ EXTRA_CHECK ( (NULL != (element)->nextX) || ((element) == (tail))); \ EXTRA_CHECK ( (NULL != (element)->prevX) || ((element) == (head))); \ if (NULL == (element)->prevX) \ (head) = (element)->nextX; \ else \ (element)->prevX->nextX = (element)->nextX; \ if (NULL == (element)->nextX) \ (tail) = (element)->prevX; \ else \ (element)->nextX->prevX = (element)->prevX; \ (element)->nextX = NULL; \ (element)->prevX = NULL; } while (0) /** * Insert an element at the head of a EDLL. Assumes that head, tail and * element are structs with prevE and nextE fields. * * @param head pointer to the head of the EDLL * @param tail pointer to the tail of the EDLL * @param element element to insert */ #define EDLL_insert(head,tail,element) do { \ (element)->nextE = (head); \ (element)->prevE = NULL; \ if ((tail) == NULL) \ (tail) = element; \ else \ (head)->prevE = element; \ (head) = (element); } while (0) /** * Remove an element from a EDLL. Assumes * that head, tail and element are structs * with prevE and nextE fields. * * @param head pointer to the head of the EDLL * @param tail pointer to the tail of the EDLL * @param element element to remove */ #define EDLL_remove(head,tail,element) do { \ if ((element)->prevE == NULL) \ (head) = (element)->nextE; \ else \ (element)->prevE->nextE = (element)->nextE; \ if ((element)->nextE == NULL) \ (tail) = (element)->prevE; \ else \ (element)->nextE->prevE = (element)->prevE; \ (element)->nextE = NULL; \ (element)->prevE = NULL; } while (0) /** * Equivalent to `time(NULL)` but tries to use some sort of monotonic * clock that isn't affected by someone setting the system real time * clock. * * @return 'current' time */ time_t MHD_monotonic_time(void); /** * Convert all occurences of '+' to ' '. * * @param arg string that is modified (in place), must be 0-terminated */ void MHD_unescape_plus (char *arg); #endif