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

Annotation of /trunk/http-server.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 116 - (hide annotations)
Sat May 31 21:42:36 2008 UTC (11 years, 6 months ago) by siliconforks
File MIME type: text/plain
File size: 6030 byte(s)
Add jscoverage-server.

1 siliconforks 116 /*
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     #include <arpa/inet.h>
28     #include <pthread.h>
29    
30     #include "util.h"
31    
32     #ifdef _WIN32
33     typedef void ThreadRoutineReturnType;
34     #define THREAD_ROUTINE_RETURN return
35     #else
36     typedef void * ThreadRoutineReturnType;
37     #define THREAD_ROUTINE_RETURN return NULL
38     #endif
39    
40     struct HTTPServer {
41     char * ip_address;
42     uint16_t port;
43     HTTPServerHandler handler;
44     SOCKET s;
45     };
46    
47     struct HTTPServerConnection {
48     HTTPConnection * connection;
49     struct HTTPServer * server;
50     };
51    
52     static bool is_shutdown = false;
53     pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
54    
55     static ThreadRoutineReturnType handle_connection(void * p) {
56     struct HTTPServerConnection * connection = p;
57     uint16_t port = connection->server->port;
58    
59     HTTPExchange * exchange = HTTPExchange_new(connection->connection);
60     if (HTTPExchange_read_request_headers(exchange) == 0) {
61     connection->server->handler(exchange);
62     }
63     else {
64     HTTPExchange_set_status_code(exchange, 400);
65     const char * message = "Could not parse request headers\n";
66     if (HTTPExchange_write_response(exchange, message, strlen(message)) != 0) {
67     HTTPServer_log_err("Warning: error writing to client\n");
68     }
69     }
70     if (HTTPExchange_flush_response(exchange) != 0) {
71     HTTPServer_log_err("Warning: error writing to client\n");
72     }
73     HTTPExchange_delete(exchange);
74     if (HTTPConnection_delete(connection->connection) != 0) {
75     HTTPServer_log_err("Warning: error closing connection to client\n");
76     }
77     free(connection);
78    
79     /* HACK: make connection to server to force accept() to return */
80     if (is_shutdown) {
81     SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
82     if (s == -1) {
83     HTTPServer_log_err("Warning: error creating socket\n");
84     }
85     else {
86     struct sockaddr_in a;
87     a.sin_family = AF_INET;
88     a.sin_port = htons(port);
89     a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
90     if (connect(s, (struct sockaddr *) &a, sizeof(a)) == -1) {
91     HTTPServer_log_err("Warning: error connecting to server\n");
92     }
93     closesocket(s);
94     }
95     }
96    
97     THREAD_ROUTINE_RETURN;
98     }
99    
100     static struct HTTPServer * HTTPServer_new(const char * ip_address, uint16_t port, HTTPServerHandler handler) {
101     struct HTTPServer * result = xmalloc(sizeof(struct HTTPServer));
102     if (ip_address == NULL) {
103     result->ip_address = NULL;
104     }
105     else {
106     result->ip_address = xstrdup(ip_address);
107     }
108     result->port = port;
109     result->handler = handler;
110     result->s = -1;
111     return result;
112     }
113    
114     static void HTTPServer_delete(struct HTTPServer * server) {
115     free(server->ip_address);
116     closesocket(server->s);
117     free(server);
118     }
119    
120     void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) {
121     struct HTTPServer * server = HTTPServer_new(ip_address, port, handler);
122    
123     #ifdef _WIN32
124     WSADATA data;
125     if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
126     fatal("Could not start Winsock");
127     }
128     #endif
129    
130     server->s = socket(PF_INET, SOCK_STREAM, 0);
131     if (server->s == -1) {
132     fatal("could not create socket");
133     }
134    
135     /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */
136     int optval = 1;
137     setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval));
138    
139     struct sockaddr_in a;
140     a.sin_family = AF_INET;
141     a.sin_port = htons(server->port);
142     if (server->ip_address == NULL) {
143     /*
144     a.sin_addr.s_addr = htonl(INADDR_ANY);
145     */
146     a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
147     }
148     else {
149     if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) {
150     closesocket(server->s);
151     fatal("invalid address: %s", server->ip_address);
152     }
153     }
154    
155     if (bind(server->s, (struct sockaddr *) &a, sizeof(a)) == -1) {
156     closesocket(server->s);
157     fatal("could not bind to address");
158     }
159    
160     if (listen(server->s, 5) == -1) {
161     closesocket(server->s);
162     fatal("could not listen for connections");
163     }
164    
165     for (;;) {
166     struct sockaddr_in client_address;
167     size_t client_address_size = sizeof(client_address);
168     SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size);
169     if (s == -1) {
170     HTTPServer_log_err("Warning: could not accept client connection\n");
171     continue;
172     }
173    
174     if (is_shutdown) {
175     closesocket(s);
176     break;
177     }
178    
179     struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection));
180     connection->server = server;
181     connection->connection = HTTPConnection_new_server(s);
182    
183     #ifdef _WIN32
184     unsigned long thread = _beginthread(handle_connection, 0, connection);
185     #else
186     pthread_t thread;
187     pthread_attr_t a;
188     pthread_attr_init(&a);
189     pthread_attr_setdetachstate(&a, PTHREAD_CREATE_DETACHED);
190     pthread_create(&thread, &a, handle_connection, connection);
191     pthread_attr_destroy(&a);
192     #endif
193     }
194    
195     HTTPServer_delete(server);
196     }
197    
198     void HTTPServer_shutdown(void) {
199     pthread_mutex_lock(&shutdown_mutex);
200     is_shutdown = true;
201     pthread_mutex_unlock(&shutdown_mutex);
202     }
203    
204     void HTTPServer_log_out(const char * format, ...) {
205     va_list a;
206     va_start(a, format);
207     vfprintf(stdout, format, a);
208     va_end(a);
209     }
210    
211     void HTTPServer_log_err(const char * format, ...) {
212     va_list a;
213     va_start(a, format);
214     vfprintf(stderr, format, a);
215     va_end(a);
216     }

  ViewVC Help
Powered by ViewVC 1.1.24