📄 daemon.c
字号:
/* This file is part of libmicrohttpd (C) 2007 Daniel Pittman and Christian Grothoff libmicrohttpd is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. libmicrohttpd 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 General Public License for more details. You should have received a copy of the GNU General Public License along with libmicrohttpd; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.*//** * @file daemon.c * @brief A minimal-HTTP server library * @author Daniel Pittman * @author Christian Grothoff */#include "internal.h"#include "response.h"#include "connection.h"#include "memorypool.h"/** * Default connection limit. */#define MHD_MAX_CONNECTIONS_DEFAULT FD_SETSIZE -4/** * Default memory allowed per connection. */#define MHD_POOL_SIZE_DEFAULT (1024 * 1024)/** * Register an access handler for all URIs beginning with uri_prefix. * * @param uri_prefix * @return MRI_NO if a handler for this exact prefix * already exists */intMHD_register_handler (struct MHD_Daemon *daemon, const char *uri_prefix, MHD_AccessHandlerCallback dh, void *dh_cls){ struct MHD_Access_Handler *ah; if ((daemon == NULL) || (uri_prefix == NULL) || (dh == NULL)) return MHD_NO; ah = daemon->handlers; while (ah != NULL) { if (0 == strcmp (uri_prefix, ah->uri_prefix)) return MHD_NO; ah = ah->next; } ah = malloc (sizeof (struct MHD_Access_Handler)); ah->next = daemon->handlers; ah->uri_prefix = strdup (uri_prefix); ah->dh = dh; ah->dh_cls = dh_cls; daemon->handlers = ah; return MHD_YES;}/** * Unregister an access handler for the URIs beginning with * uri_prefix. * * @param uri_prefix * @return MHD_NO if a handler for this exact prefix * is not known for this daemon */intMHD_unregister_handler (struct MHD_Daemon *daemon, const char *uri_prefix, MHD_AccessHandlerCallback dh, void *dh_cls){ struct MHD_Access_Handler *prev; struct MHD_Access_Handler *pos; if ((daemon == NULL) || (uri_prefix == NULL) || (dh == NULL)) return MHD_NO; pos = daemon->handlers; prev = NULL; while (pos != NULL) { if ((dh == pos->dh) && (dh_cls == pos->dh_cls) && (0 == strcmp (uri_prefix, pos->uri_prefix))) { if (prev == NULL) daemon->handlers = pos->next; else prev->next = pos->next; free (pos); return MHD_YES; } prev = pos; pos = pos->next; } return MHD_NO;}/** * Obtain the select sets for this daemon. * * @return MHD_YES on success, MHD_NO if this * daemon was not started with the right * options for this call. */intMHD_get_fdset (struct MHD_Daemon *daemon, fd_set * read_fd_set, fd_set * write_fd_set, fd_set * except_fd_set, int *max_fd){ struct MHD_Connection *pos; if ((daemon == NULL) || (read_fd_set == NULL) || (write_fd_set == NULL) || (except_fd_set == NULL) || (max_fd == NULL) || ((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0)) return MHD_NO; FD_SET (daemon->socket_fd, read_fd_set); if ((*max_fd) < daemon->socket_fd) *max_fd = daemon->socket_fd; pos = daemon->connections; while (pos != NULL) { if (MHD_YES != MHD_connection_get_fdset (pos, read_fd_set, write_fd_set, except_fd_set, max_fd)) return MHD_NO; pos = pos->next; } return MHD_YES;}/** * Main function of the thread that handles an individual * connection. */static void *MHD_handle_connection (void *data){ struct MHD_Connection *con = data; int num_ready; fd_set rs; fd_set ws; fd_set es; int max; if (con == NULL) abort (); while ((!con->daemon->shutdown) && (con->socket_fd != -1)) { FD_ZERO (&rs); FD_ZERO (&ws); FD_ZERO (&es); max = 0; MHD_connection_get_fdset (con, &rs, &ws, &es, &max); num_ready = SELECT (max + 1, &rs, &ws, &es, NULL); if (num_ready <= 0) { if (errno == EINTR) continue; break; } if (((FD_ISSET (con->socket_fd, &rs)) && (MHD_YES != MHD_connection_handle_read (con))) || ((con->socket_fd != -1) && (FD_ISSET (con->socket_fd, &ws)) && (MHD_YES != MHD_connection_handle_write (con)))) break; if ((con->headersReceived == 1) && (con->response == NULL)) MHD_call_connection_handler (con); } if (con->socket_fd != -1) { CLOSE (con->socket_fd); con->socket_fd = -1; } return NULL;}/** * Accept an incoming connection and create the MHD_Connection object for * it. This function also enforces policy by way of checking with the * accept policy callback. */static intMHD_accept_connection (struct MHD_Daemon *daemon){ struct MHD_Connection *connection; struct sockaddr_in6 addr6; struct sockaddr *addr = (struct sockaddr *) &addr6; socklen_t addrlen; int s; if (sizeof (struct sockaddr) > sizeof (struct sockaddr_in6)) abort (); /* fatal, serious error */ addrlen = sizeof (struct sockaddr_in6); memset (addr, 0, sizeof (struct sockaddr_in6)); s = ACCEPT (daemon->socket_fd, addr, &addrlen); if ((s < 0) || (addrlen <= 0)) { MHD_DLOG (daemon, "Error accepting connection: %s\n", STRERROR (errno)); if (s != -1) CLOSE (s); /* just in case */ return MHD_NO; } if (daemon->max_connections == 0) { /* above connection limit - reject */ CLOSE (s); return MHD_NO; } if ((daemon->apc != NULL) && (MHD_NO == daemon->apc (daemon->apc_cls, addr, addrlen))) { CLOSE (s); return MHD_YES; } connection = malloc (sizeof (struct MHD_Connection)); memset (connection, 0, sizeof (struct MHD_Connection)); connection->pool = NULL; connection->addr = malloc (addrlen); if (connection->addr == NULL) { CLOSE (s); free (connection); return MHD_NO; } memcpy (connection->addr, addr, addrlen); connection->addr_len = addrlen; connection->socket_fd = s; connection->daemon = daemon; if ((0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) && (0 != pthread_create (&connection->pid, NULL, &MHD_handle_connection, connection))) { MHD_DLOG (daemon, "Failed to create a thread: %s\n", STRERROR (errno)); CLOSE (s); free (connection->addr); free (connection); return MHD_NO; } connection->next = daemon->connections; daemon->connections = connection; daemon->max_connections--; return MHD_YES;}/** * Free resources associated with all closed connections. * (destroy responses, free buffers, etc.). A connection * is known to be closed if the socket_fd is -1. * * Also performs connection actions that need to be run * even if the connection is not selectable (such as * calling the application again with upload data when * the upload data buffer is full). */static voidMHD_cleanup_connections (struct MHD_Daemon *daemon){ struct MHD_Connection *pos; struct MHD_Connection *prev; void *unused; pos = daemon->connections; prev = NULL; while (pos != NULL) { if (pos->socket_fd == -1) { if (prev == NULL) daemon->connections = pos->next; else prev->next = pos->next; if (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) { pthread_kill (pos->pid, SIGALRM); pthread_join (pos->pid, &unused); } if (pos->response != NULL) MHD_destroy_response (pos->response); MHD_pool_destroy (pos->pool); free (pos->addr); free (pos); daemon->max_connections++; if (prev == NULL) pos = daemon->connections; else pos = prev->next; continue; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -