diff options
Diffstat (limited to 'src/microhttpd/internal.h')
-rw-r--r-- | src/microhttpd/internal.h | 1459 |
1 files changed, 1459 insertions, 0 deletions
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h new file mode 100644 index 00000000..286aee68 --- /dev/null +++ b/src/microhttpd/internal.h @@ -0,0 +1,1459 @@ +/* + 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 <gnutls/gnutls.h> +#if GNUTLS_VERSION_MAJOR >= 3 +#include <gnutls/abstract.h> +#endif +#endif +#if EPOLL_SUPPORT +#include <sys/epoll.h> +#endif +#if HAVE_NETINET_TCP_H +/* for TCP_FASTOPEN */ +#include <netinet/tcp.h> +#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. + */ + gnutls_session_t tls_session; + + /** + * Memory location to return for protocol session info. + */ + int protocol; + + /** + * Memory location to return for protocol session info. + */ + int 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. + * <p> + * 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 + /** + * Desired cipher algorithms. + */ + gnutls_priority_t priority_cache; + + /** + * What kind of credentials are we offering + * for SSL/TLS? + */ + gnutls_credentials_type_t cred_type; + + /** + * Server x509 credentials + */ + gnutls_certificate_credentials_t x509_cred; + + /** + * Diffie-Hellman parameters + */ + gnutls_dh_params_t dh_params; + +#if GNUTLS_VERSION_MAJOR >= 3 + /** + * Function that can be used to obtain the certificate. Needed + * for SNI support. See #MHD_OPTION_HTTPS_CERT_CALLBACK. + */ + gnutls_certificate_retrieve_function2 *cert_callback; +#endif + + /** + * Pointer to our SSL/TLS key (in ASCII) in memory. + */ + const char *https_mem_key; + + /** + * Pointer to our SSL/TLS certificate (in ASCII) 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 ASCII) in memory. + */ + const char *https_mem_trust; + + /** + * Our Diffie-Hellman parameters in memory. + */ + gnutls_dh_params_t https_mem_dhparams; + + /** + * #MHD_YES if we have initialized @e https_mem_dhparams. + */ + int have_dhparams; + + /** + * 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 |