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

Annotation of /trunk/http-server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 583 - (hide annotations)
Sat Sep 11 20:20:14 2010 UTC (8 years, 11 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 siliconforks 116 /*
2     http-server.c - generic HTTP server
3 siliconforks 505 Copyright (C) 2008, 2009, 2010 siliconforks.com
4 siliconforks 116
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 siliconforks 125 #ifdef HAVE_PTHREAD_H
28 siliconforks 116 #include <pthread.h>
29 siliconforks 125 #endif
30 siliconforks 116
31 siliconforks 125 #ifdef __MINGW32__
32     #include <process.h>
33     #endif
34    
35 siliconforks 116 #include "util.h"
36    
37 siliconforks 125 #ifdef __MINGW32__
38 siliconforks 116 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 siliconforks 125 #ifdef __MINGW32__
59     CRITICAL_SECTION shutdown_mutex;
60     #define LOCK EnterCriticalSection
61     #define UNLOCK LeaveCriticalSection
62     #else
63 siliconforks 116 pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
64 siliconforks 125 #define LOCK pthread_mutex_lock
65     #define UNLOCK pthread_mutex_unlock
66     #endif
67 siliconforks 116
68     static ThreadRoutineReturnType handle_connection(void * p) {
69     struct HTTPServerConnection * connection = p;
70 siliconforks 583 struct HTTPServer * server = connection->server;
71 siliconforks 116 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 siliconforks 125 LOCK(&shutdown_mutex);
95 siliconforks 116 if (is_shutdown) {
96     SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
97 siliconforks 125 if (s == INVALID_SOCKET) {
98 siliconforks 116 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 siliconforks 583
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 siliconforks 116 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 siliconforks 125 UNLOCK(&shutdown_mutex);
126 siliconforks 116
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 siliconforks 125 #ifdef __MINGW32__
154 siliconforks 116 WSADATA data;
155     if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
156 siliconforks 134 fatal("could not start Winsock");
157 siliconforks 116 }
158 siliconforks 125 InitializeCriticalSection(&shutdown_mutex);
159 siliconforks 116 #endif
160    
161     server->s = socket(PF_INET, SOCK_STREAM, 0);
162 siliconforks 125 if (server->s == INVALID_SOCKET) {
163 siliconforks 116 fatal("could not create socket");
164     }
165    
166     /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */
167 siliconforks 476 /* note that SO_REUSEADDR has different semantics on Windows */
168     #ifndef __MINGW32__
169 siliconforks 116 int optval = 1;
170     setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval));
171 siliconforks 476 #endif
172 siliconforks 116
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 siliconforks 125 if (s == INVALID_SOCKET) {
204 siliconforks 116 HTTPServer_log_err("Warning: could not accept client connection\n");
205     continue;
206     }
207    
208 siliconforks 125 LOCK(&shutdown_mutex);
209 siliconforks 116 if (is_shutdown) {
210     closesocket(s);
211     break;
212     }
213 siliconforks 125 UNLOCK(&shutdown_mutex);
214 siliconforks 116
215     struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection));
216     connection->server = server;
217     connection->connection = HTTPConnection_new_server(s);
218    
219 siliconforks 125 #ifdef __MINGW32__
220 siliconforks 116 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 siliconforks 125 LOCK(&shutdown_mutex);
236 siliconforks 116 is_shutdown = true;
237 siliconforks 125 UNLOCK(&shutdown_mutex);
238 siliconforks 116 }
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 siliconforks 125 fflush(stdout);
246 siliconforks 116 }
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 siliconforks 125 fflush(stderr);
254 siliconforks 116 }

  ViewVC Help
Powered by ViewVC 1.1.24