/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/http-server.c

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs · C · 236 lines · 182 code · 31 blank · 23 comment · 35 complexity · af571a12fee57696206b85c90c4571f4 MD5 · raw file

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