24 |
#include <stdarg.h> |
#include <stdarg.h> |
25 |
#include <string.h> |
#include <string.h> |
26 |
|
|
27 |
#include <arpa/inet.h> |
#ifdef HAVE_PTHREAD_H |
28 |
#include <pthread.h> |
#include <pthread.h> |
29 |
|
#endif |
30 |
|
|
31 |
|
#ifdef __MINGW32__ |
32 |
|
#include <process.h> |
33 |
|
#endif |
34 |
|
|
35 |
#include "util.h" |
#include "util.h" |
36 |
|
|
37 |
#ifdef _WIN32 |
#ifdef __MINGW32__ |
38 |
typedef void ThreadRoutineReturnType; |
typedef void ThreadRoutineReturnType; |
39 |
#define THREAD_ROUTINE_RETURN return |
#define THREAD_ROUTINE_RETURN return |
40 |
#else |
#else |
55 |
}; |
}; |
56 |
|
|
57 |
static bool is_shutdown = false; |
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; |
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) { |
static ThreadRoutineReturnType handle_connection(void * p) { |
69 |
struct HTTPServerConnection * connection = p; |
struct HTTPServerConnection * connection = p; |
90 |
free(connection); |
free(connection); |
91 |
|
|
92 |
/* HACK: make connection to server to force accept() to return */ |
/* HACK: make connection to server to force accept() to return */ |
93 |
|
LOCK(&shutdown_mutex); |
94 |
if (is_shutdown) { |
if (is_shutdown) { |
95 |
SOCKET s = socket(PF_INET, SOCK_STREAM, 0); |
SOCKET s = socket(PF_INET, SOCK_STREAM, 0); |
96 |
if (s == -1) { |
if (s == INVALID_SOCKET) { |
97 |
HTTPServer_log_err("Warning: error creating socket\n"); |
HTTPServer_log_err("Warning: error creating socket\n"); |
98 |
} |
} |
99 |
else { |
else { |
107 |
closesocket(s); |
closesocket(s); |
108 |
} |
} |
109 |
} |
} |
110 |
|
UNLOCK(&shutdown_mutex); |
111 |
|
|
112 |
THREAD_ROUTINE_RETURN; |
THREAD_ROUTINE_RETURN; |
113 |
} |
} |
135 |
void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) { |
void HTTPServer_run(const char * ip_address, uint16_t port, HTTPServerHandler handler) { |
136 |
struct HTTPServer * server = HTTPServer_new(ip_address, port, handler); |
struct HTTPServer * server = HTTPServer_new(ip_address, port, handler); |
137 |
|
|
138 |
#ifdef _WIN32 |
#ifdef __MINGW32__ |
139 |
WSADATA data; |
WSADATA data; |
140 |
if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { |
if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { |
141 |
fatal("Could not start Winsock"); |
fatal("Could not start Winsock"); |
142 |
} |
} |
143 |
|
InitializeCriticalSection(&shutdown_mutex); |
144 |
#endif |
#endif |
145 |
|
|
146 |
server->s = socket(PF_INET, SOCK_STREAM, 0); |
server->s = socket(PF_INET, SOCK_STREAM, 0); |
147 |
if (server->s == -1) { |
if (server->s == INVALID_SOCKET) { |
148 |
fatal("could not create socket"); |
fatal("could not create socket"); |
149 |
} |
} |
150 |
|
|
182 |
struct sockaddr_in client_address; |
struct sockaddr_in client_address; |
183 |
size_t client_address_size = sizeof(client_address); |
size_t client_address_size = sizeof(client_address); |
184 |
SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size); |
SOCKET s = accept(server->s, (struct sockaddr *) &client_address, &client_address_size); |
185 |
if (s == -1) { |
if (s == INVALID_SOCKET) { |
186 |
HTTPServer_log_err("Warning: could not accept client connection\n"); |
HTTPServer_log_err("Warning: could not accept client connection\n"); |
187 |
continue; |
continue; |
188 |
} |
} |
189 |
|
|
190 |
|
LOCK(&shutdown_mutex); |
191 |
if (is_shutdown) { |
if (is_shutdown) { |
192 |
closesocket(s); |
closesocket(s); |
193 |
break; |
break; |
194 |
} |
} |
195 |
|
UNLOCK(&shutdown_mutex); |
196 |
|
|
197 |
struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection)); |
struct HTTPServerConnection * connection = xmalloc(sizeof(struct HTTPServerConnection)); |
198 |
connection->server = server; |
connection->server = server; |
199 |
connection->connection = HTTPConnection_new_server(s); |
connection->connection = HTTPConnection_new_server(s); |
200 |
|
|
201 |
#ifdef _WIN32 |
#ifdef __MINGW32__ |
202 |
unsigned long thread = _beginthread(handle_connection, 0, connection); |
unsigned long thread = _beginthread(handle_connection, 0, connection); |
203 |
#else |
#else |
204 |
pthread_t thread; |
pthread_t thread; |
214 |
} |
} |
215 |
|
|
216 |
void HTTPServer_shutdown(void) { |
void HTTPServer_shutdown(void) { |
217 |
pthread_mutex_lock(&shutdown_mutex); |
LOCK(&shutdown_mutex); |
218 |
is_shutdown = true; |
is_shutdown = true; |
219 |
pthread_mutex_unlock(&shutdown_mutex); |
UNLOCK(&shutdown_mutex); |
220 |
} |
} |
221 |
|
|
222 |
void HTTPServer_log_out(const char * format, ...) { |
void HTTPServer_log_out(const char * format, ...) { |
224 |
va_start(a, format); |
va_start(a, format); |
225 |
vfprintf(stdout, format, a); |
vfprintf(stdout, format, a); |
226 |
va_end(a); |
va_end(a); |
227 |
|
fflush(stdout); |
228 |
} |
} |
229 |
|
|
230 |
void HTTPServer_log_err(const char * format, ...) { |
void HTTPServer_log_err(const char * format, ...) { |
232 |
va_start(a, format); |
va_start(a, format); |
233 |
vfprintf(stderr, format, a); |
vfprintf(stderr, format, a); |
234 |
va_end(a); |
va_end(a); |
235 |
|
fflush(stderr); |
236 |
} |
} |