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

Contents of /trunk/http-server.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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 #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