PageRenderTime 24ms CodeModel.GetById 11ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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}