/[jscoverage]/trunk/http-server.c
ViewVC logotype

Contents of /trunk/http-server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 583 - (show annotations)
Sat Sep 11 20:20:14 2010 UTC (8 years, 2 months ago) by siliconforks
File MIME type: text/plain
File size: 7051 byte(s)
Allow shutdown of server even if --ip-address was specified as a non-loopback address, as long as client has same address.

1 /*
2 http-server.c - generic HTTP server
3 Copyright (C) 2008, 2009, 2010 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 struct HTTPServer * server = connection->server;
71 uint16_t port = connection->server->port;
72
73 HTTPExchange * exchange = HTTPExchange_new(connection->connection);
74 if (HTTPExchange_read_request_headers(exchange) == 0) {
75 connection->server->handler(exchange);
76 }
77 else {
78 HTTPExchange_set_status_code(exchange, 400);
79 const char * message = "Could not parse request headers\n";
80 if (HTTPExchange_write_response(exchange, message, strlen(message)) != 0) {
81 HTTPServer_log_err("Warning: error writing to client\n");
82 }
83 }
84 if (HTTPExchange_flush_response(exchange) != 0) {
85 HTTPServer_log_err("Warning: error writing to client\n");
86 }
87 HTTPExchange_delete(exchange);
88 if (HTTPConnection_delete(connection->connection) != 0) {
89 HTTPServer_log_err("Warning: error closing connection to client\n");
90 }
91 free(connection);
92
93 /* HACK: make connection to server to force accept() to return */
94 LOCK(&shutdown_mutex);
95 if (is_shutdown) {
96 SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
97 if (s == INVALID_SOCKET) {
98 HTTPServer_log_err("Warning: error creating socket\n");
99 }
100 else {
101 struct sockaddr_in a;
102 a.sin_family = AF_INET;
103 a.sin_port = htons(port);
104
105 if (server->ip_address == NULL) {
106 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
107 }
108 else {
109 if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) {
110 HTTPServer_log_err("Warning: server has invalid IP address\n");
111 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
112 }
113
114 if (a.sin_addr.s_addr == htonl(INADDR_ANY)) {
115 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
116 }
117 }
118
119 if (connect(s, (struct sockaddr *) &a, sizeof(a)) == -1) {
120 HTTPServer_log_err("Warning: error connecting to server\n");
121 }
122 closesocket(s);
123 }
124 }
125 UNLOCK(&shutdown_mutex);
126
127 THREAD_ROUTINE_RETURN;
128 }
129
130 static struct HTTPServer * HTTPServer_new(const char * ip_address, uint16_t port, HTTPServerHandler handler) {
131 struct HTTPServer * result = xmalloc(sizeof(struct HTTPServer));
132 if (ip_address == NULL) {
133 result->ip_address = NULL;
134 }
135 else {
136 result->ip_address = xstrdup(ip_address);
137 }
138 result->port = port;
139 result->handler = handler;
140 result->s = -1;
141 return result;
142 }
143
144 static void HTTPServer_delete(struct HTTPServer * server) {
145 free(server->ip_address);
146 closesocket(server->s);
147 free(server);
148 }
149
150 void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) {
151 struct HTTPServer * server = HTTPServer_new(ip_address, port, handler);
152
153 #ifdef __MINGW32__
154 WSADATA data;
155 if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
156 fatal("could not start Winsock");
157 }
158 InitializeCriticalSection(&shutdown_mutex);
159 #endif
160
161 server->s = socket(PF_INET, SOCK_STREAM, 0);
162 if (server->s == INVALID_SOCKET) {
163 fatal("could not create socket");
164 }
165
166 /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */
167 /* note that SO_REUSEADDR has different semantics on Windows */
168 #ifndef __MINGW32__
169 int optval = 1;
170 setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval));
171 #endif
172
173 struct sockaddr_in a;
174 a.sin_family = AF_INET;
175 a.sin_port = htons(server->port);
176 if (server->ip_address == NULL) {
177 /*
178 a.sin_addr.s_addr = htonl(INADDR_ANY);
179 */
180 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
181 }
182 else {
183 if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) {
184 closesocket(server->s);
185 fatal("invalid address: %s", server->ip_address);
186 }
187 }
188
189 if (bind(server->s, (struct sockaddr *) &a, sizeof(a)) == -1) {
190 closesocket(server->s);
191 fatal("could not bind to address");
192 }
193
194 if (listen(server->s, 5) == -1) {
195 closesocket(server->s);
196 fatal("could not listen for connections");
197 }
198
199 for (;;) {
200 struct sockaddr_in client_address;
201 size_t client_address_size = sizeof(client_address);
202 SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size);
203 if (s == INVALID_SOCKET) {
204 HTTPServer_log_err("Warning: could not accept client connection\n");
205 continue;
206 }
207
208 LOCK(&shutdown_mutex);
209 if (is_shutdown) {
210 closesocket(s);
211 break;
212 }
213 UNLOCK(&shutdown_mutex);
214
215 struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection));
216 connection->server = server;
217 connection->connection = HTTPConnection_new_server(s);
218
219 #ifdef __MINGW32__
220 unsigned long thread = _beginthread(handle_connection, 0, connection);
221 #else
222 pthread_t thread;
223 pthread_attr_t a;
224 pthread_attr_init(&a);
225 pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
226 pthread_create(&thread, &a, handle_connection, connection);
227 pthread_attr_destroy(&a);
228 #endif
229 }
230
231 HTTPServer_delete(server);
232 }
233
234 void HTTPServer_shutdown(void) {
235 LOCK(&shutdown_mutex);
236 is_shutdown = true;
237 UNLOCK(&shutdown_mutex);
238 }
239
240 void HTTPServer_log_out(const char * format, ...) {
241 va_list a;
242 va_start(a, format);
243 vfprintf(stdout, format, a);
244 va_end(a);
245 fflush(stdout);
246 }
247
248 void HTTPServer_log_err(const char * format, ...) {
249 va_list a;
250 va_start(a, format);
251 vfprintf(stderr, format, a);
252 va_end(a);
253 fflush(stderr);
254 }

  ViewVC Help
Powered by ViewVC 1.1.24