Inital Commit
[oweals/finalsclub.git] / bruml / lib / socket.io / support / expresso / deps / jscoverage / http-server.c
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__
38 typedef void ThreadRoutineReturnType;
39 #define THREAD_ROUTINE_RETURN return
40 #else
41 typedef void * ThreadRoutineReturnType;
42 #define THREAD_ROUTINE_RETURN return NULL
43 #endif
44
45 struct HTTPServer {
46   char * ip_address;
47   uint16_t port;
48   HTTPServerHandler handler;
49   SOCKET s;
50 };
51
52 struct HTTPServerConnection {
53   HTTPConnection * connection;
54   struct HTTPServer * server;
55 };
56
57 static bool is_shutdown = false;
58 #ifdef __MINGW32__
59 CRITICAL_SECTION shutdown_mutex;
60 #define LOCK EnterCriticalSection
61 #define UNLOCK LeaveCriticalSection
62 #else
63 pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
64 #define LOCK pthread_mutex_lock
65 #define UNLOCK pthread_mutex_unlock
66 #endif
67
68 static 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
115 static 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
129 static void HTTPServer_delete(struct HTTPServer * server) {
130   free(server->ip_address);
131   closesocket(server->s);
132   free(server);
133 }
134
135 void 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
216 void HTTPServer_shutdown(void) {
217   LOCK(&shutdown_mutex);
218   is_shutdown = true;
219   UNLOCK(&shutdown_mutex);
220 }
221
222 void 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
230 void 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 }