/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/http-server.c
C | 236 lines | 182 code | 31 blank | 23 comment | 35 complexity | af571a12fee57696206b85c90c4571f4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
1/* 2 http-server.c - generic HTTP server 3 Copyright (C) 2008 siliconforks.com 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with this program; if not, write to the Free Software Foundation, Inc., 17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18*/ 19 20#include <config.h> 21 22#include "http-server.h" 23 24#include <stdarg.h> 25#include <string.h> 26 27#ifdef HAVE_PTHREAD_H 28#include <pthread.h> 29#endif 30 31#ifdef __MINGW32__ 32#include <process.h> 33#endif 34 35#include "util.h" 36 37#ifdef __MINGW32__ 38typedef void ThreadRoutineReturnType; 39#define THREAD_ROUTINE_RETURN return 40#else 41typedef void * ThreadRoutineReturnType; 42#define THREAD_ROUTINE_RETURN return NULL 43#endif 44 45struct HTTPServer { 46 char * ip_address; 47 uint16_t port; 48 HTTPServerHandler handler; 49 SOCKET s; 50}; 51 52struct HTTPServerConnection { 53 HTTPConnection * connection; 54 struct HTTPServer * server; 55}; 56 57static bool is_shutdown = false; 58#ifdef __MINGW32__ 59CRITICAL_SECTION shutdown_mutex; 60#define LOCK EnterCriticalSection 61#define UNLOCK LeaveCriticalSection 62#else 63pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER; 64#define LOCK pthread_mutex_lock 65#define UNLOCK pthread_mutex_unlock 66#endif 67 68static ThreadRoutineReturnType handle_connection(void * p) { 69 struct HTTPServerConnection * connection = p; 70 uint16_t port = connection->server->port; 71 72 HTTPExchange * exchange = HTTPExchange_new(connection->connection); 73 if (HTTPExchange_read_request_headers(exchange) == 0) { 74 connection->server->handler(exchange); 75 } 76 else { 77 HTTPExchange_set_status_code(exchange, 400); 78 const char * message = "Could not parse request headers\n"; 79 if (HTTPExchange_write_response(exchange, message, strlen(message)) != 0) { 80 HTTPServer_log_err("Warning: error writing to client\n"); 81 } 82 } 83 if (HTTPExchange_flush_response(exchange) != 0) { 84 HTTPServer_log_err("Warning: error writing to client\n"); 85 } 86 HTTPExchange_delete(exchange); 87 if (HTTPConnection_delete(connection->connection) != 0) { 88 HTTPServer_log_err("Warning: error closing connection to client\n"); 89 } 90 free(connection); 91 92 /* HACK: make connection to server to force accept() to return */ 93 LOCK(&shutdown_mutex); 94 if (is_shutdown) { 95 SOCKET s = socket(PF_INET, SOCK_STREAM, 0); 96 if (s == INVALID_SOCKET) { 97 HTTPServer_log_err("Warning: error creating socket\n"); 98 } 99 else { 100 struct sockaddr_in a; 101 a.sin_family = AF_INET; 102 a.sin_port = htons(port); 103 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 104 if (connect(s, (struct sockaddr *) &a, sizeof(a)) == -1) { 105 HTTPServer_log_err("Warning: error connecting to server\n"); 106 } 107 closesocket(s); 108 } 109 } 110 UNLOCK(&shutdown_mutex); 111 112 THREAD_ROUTINE_RETURN; 113} 114 115static struct HTTPServer * HTTPServer_new(const char * ip_address, uint16_t port, HTTPServerHandler handler) { 116 struct HTTPServer * result = xmalloc(sizeof(struct HTTPServer)); 117 if (ip_address == NULL) { 118 result->ip_address = NULL; 119 } 120 else { 121 result->ip_address = xstrdup(ip_address); 122 } 123 result->port = port; 124 result->handler = handler; 125 result->s = -1; 126 return result; 127} 128 129static void HTTPServer_delete(struct HTTPServer * server) { 130 free(server->ip_address); 131 closesocket(server->s); 132 free(server); 133} 134 135void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) { 136 struct HTTPServer * server = HTTPServer_new(ip_address, port, handler); 137 138#ifdef __MINGW32__ 139 WSADATA data; 140 if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { 141 fatal("could not start Winsock"); 142 } 143 InitializeCriticalSection(&shutdown_mutex); 144#endif 145 146 server->s = socket(PF_INET, SOCK_STREAM, 0); 147 if (server->s == INVALID_SOCKET) { 148 fatal("could not create socket"); 149 } 150 151 /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */ 152 int optval = 1; 153 setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval)); 154 155 struct sockaddr_in a; 156 a.sin_family = AF_INET; 157 a.sin_port = htons(server->port); 158 if (server->ip_address == NULL) { 159 /* 160 a.sin_addr.s_addr = htonl(INADDR_ANY); 161 */ 162 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 163 } 164 else { 165 if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) { 166 closesocket(server->s); 167 fatal("invalid address: %s", server->ip_address); 168 } 169 } 170 171 if (bind(server->s, (struct sockaddr *) &a, sizeof(a)) == -1) { 172 closesocket(server->s); 173 fatal("could not bind to address"); 174 } 175 176 if (listen(server->s, 5) == -1) { 177 closesocket(server->s); 178 fatal("could not listen for connections"); 179 } 180 181 for (;;) { 182 struct sockaddr_in client_address; 183 size_t client_address_size = sizeof(client_address); 184 SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size); 185 if (s == INVALID_SOCKET) { 186 HTTPServer_log_err("Warning: could not accept client connection\n"); 187 continue; 188 } 189 190 LOCK(&shutdown_mutex); 191 if (is_shutdown) { 192 closesocket(s); 193 break; 194 } 195 UNLOCK(&shutdown_mutex); 196 197 struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection)); 198 connection->server = server; 199 connection->connection = HTTPConnection_new_server(s); 200 201#ifdef __MINGW32__ 202 unsigned long thread = _beginthread(handle_connection, 0, connection); 203#else 204 pthread_t thread; 205 pthread_attr_t a; 206 pthread_attr_init(&a); 207 pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED); 208 pthread_create(&thread, &a, handle_connection, connection); 209 pthread_attr_destroy(&a); 210#endif 211 } 212 213 HTTPServer_delete(server); 214} 215 216void HTTPServer_shutdown(void) { 217 LOCK(&shutdown_mutex); 218 is_shutdown = true; 219 UNLOCK(&shutdown_mutex); 220} 221 222void HTTPServer_log_out(const char * format, ...) { 223 va_list a; 224 va_start(a, format); 225 vfprintf(stdout, format, a); 226 va_end(a); 227 fflush(stdout); 228} 229 230void HTTPServer_log_err(const char * format, ...) { 231 va_list a; 232 va_start(a, format); 233 vfprintf(stderr, format, a); 234 va_end(a); 235 fflush(stderr); 236}