2 http-server.c - generic HTTP server
3 Copyright (C) 2008 siliconforks.com
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.
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.
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.
22 #include "http-server.h"
38 typedef void ThreadRoutineReturnType;
39 #define THREAD_ROUTINE_RETURN return
41 typedef void * ThreadRoutineReturnType;
42 #define THREAD_ROUTINE_RETURN return NULL
48 HTTPServerHandler handler;
52 struct HTTPServerConnection {
53 HTTPConnection * connection;
54 struct HTTPServer * server;
57 static bool is_shutdown = false;
59 CRITICAL_SECTION shutdown_mutex;
60 #define LOCK EnterCriticalSection
61 #define UNLOCK LeaveCriticalSection
63 pthread_mutex_t shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
64 #define LOCK pthread_mutex_lock
65 #define UNLOCK pthread_mutex_unlock
68 static ThreadRoutineReturnType handle_connection(void * p) {
69 struct HTTPServerConnection * connection = p;
70 uint16_t port = connection->server->port;
72 HTTPExchange * exchange = HTTPExchange_new(connection->connection);
73 if (HTTPExchange_read_request_headers(exchange) == 0) {
74 connection->server->handler(exchange);
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");
83 if (HTTPExchange_flush_response(exchange) != 0) {
84 HTTPServer_log_err("Warning: error writing to client\n");
86 HTTPExchange_delete(exchange);
87 if (HTTPConnection_delete(connection->connection) != 0) {
88 HTTPServer_log_err("Warning: error closing connection to client\n");
92 /* HACK: make connection to server to force accept() to return */
93 LOCK(&shutdown_mutex);
95 SOCKET s = socket(PF_INET, SOCK_STREAM, 0);
96 if (s == INVALID_SOCKET) {
97 HTTPServer_log_err("Warning: error creating socket\n");
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");
110 UNLOCK(&shutdown_mutex);
112 THREAD_ROUTINE_RETURN;
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;
121 result->ip_address = xstrdup(ip_address);
124 result->handler = handler;
129 static void HTTPServer_delete(struct HTTPServer * server) {
130 free(server->ip_address);
131 closesocket(server->s);
135 void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) {
136 struct HTTPServer * server = HTTPServer_new(ip_address, port, handler);
140 if (WSAStartup(MAKEWORD(1, 1), &data) != 0) {
141 fatal("could not start Winsock");
143 InitializeCriticalSection(&shutdown_mutex);
146 server->s = socket(PF_INET, SOCK_STREAM, 0);
147 if (server->s == INVALID_SOCKET) {
148 fatal("could not create socket");
151 /* http://hea-www.harvard.edu/~fine/Tech/addrinuse.html */
153 setsockopt(server->s, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval));
155 struct sockaddr_in a;
156 a.sin_family = AF_INET;
157 a.sin_port = htons(server->port);
158 if (server->ip_address == NULL) {
160 a.sin_addr.s_addr = htonl(INADDR_ANY);
162 a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
165 if (inet_aton(server->ip_address, &(a.sin_addr)) == 0) {
166 closesocket(server->s);
167 fatal("invalid address: %s", server->ip_address);
171 if (bind(server->s, (struct sockaddr *) &a, sizeof(a)) == -1) {
172 closesocket(server->s);
173 fatal("could not bind to address");
176 if (listen(server->s, 5) == -1) {
177 closesocket(server->s);
178 fatal("could not listen for connections");
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");
190 LOCK(&shutdown_mutex);
195 UNLOCK(&shutdown_mutex);
197 struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection));
198 connection->server = server;
199 connection->connection = HTTPConnection_new_server(s);
202 unsigned long thread = _beginthread(handle_connection, 0, connection);
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);
213 HTTPServer_delete(server);
216 void HTTPServer_shutdown(void) {
217 LOCK(&shutdown_mutex);
219 UNLOCK(&shutdown_mutex);
222 void HTTPServer_log_out(const char * format, ...) {
225 vfprintf(stdout, format, a);
230 void HTTPServer_log_err(const char * format, ...) {
233 vfprintf(stderr, format, a);