aboutsummaryrefslogtreecommitdiff
path: root/src/daemon/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/daemon/daemon.c')
-rw-r--r--src/daemon/daemon.c1817
1 files changed, 396 insertions, 1421 deletions
diff --git a/src/daemon/daemon.c b/src/daemon/daemon.c
index dd22ce6d..8a602df4 100644
--- a/src/daemon/daemon.c
+++ b/src/daemon/daemon.c
@@ -20,544 +20,123 @@
20 20
21/** 21/**
22 * @file daemon.c 22 * @file daemon.c
23 * @brief This is my implementation of the libmicrohttpd interface. Many features incomplete at this time. 23 * @brief A minimal-HTTP server library
24 * @author Daniel Pittman 24 * @author Daniel Pittman
25 * @author Christian Grothoff
25 * @version 0.1.0 26 * @version 0.1.0
26 */ 27 */
27 28
28#include "config.h"
29#include "microhttpd.h"
30
31#include <netinet/in.h>
32#include <stdio.h> 29#include <stdio.h>
33#include <stdlib.h> 30#include <stdlib.h>
34#include <netdb.h> 31#include <netdb.h>
35#include <string.h> 32#include <string.h>
36#include <unistd.h> 33#include <unistd.h>
34#include <stdarg>
37#include <fcntl.h> 35#include <fcntl.h>
38#include <pthread.h> 36#include <pthread.h>
37#include <netinet/in.h>
39 38
39#include "microhttpd.h"
40#include "internal.h"
41#include "response.h"
42#include "session.h"
43#include "config.h"
40 44
41#define MHD_MAX_CONNECTIONS FD_SETSIZE -4 45#define MHD_MAX_CONNECTIONS FD_SETSIZE -4
42#define MHD_MAX_BUF_SIZE 2048
43#define MHD_MAX_HEADERS 1024
44#define MHD_MAX_HANDLERS 1024
45#define MHD_MAX_RESPONSE 1024
46
47
48int MHD_handle_read(int, struct MHD_Daemon *);
49int MHD_handle_write(int, struct MHD_Daemon *);
50void * MHD_spawn_connections(void * data);
51void * MHD_select(void * data);
52int MHD_parse_message(struct MHD_Session * session);
53void MHD_parse_URL(struct MHD_Session * session);
54
55struct MHD_Daemon {
56 unsigned int options;
57
58 unsigned short port;
59 int socket_fd;
60 int max_fd;
61
62 MHD_AcceptPolicyCallback apc;
63 void * apc_cls;
64
65 fd_set read_fd_set;
66 fd_set write_fd_set;
67 fd_set except_fd_set;
68
69 int shutdown;
70 pthread_t pid;
71
72 struct MHD_Session * connections[MHD_MAX_CONNECTIONS];
73
74 int firstFreeHandler;
75 struct MHD_Access_Handler * handlers[MHD_MAX_HANDLERS];
76 MHD_AccessHandlerCallback dh;
77 void * dh_cls;
78};
79
80struct MHD_Session {
81 struct sockaddr_in addr;
82
83 int readLoc;
84 int writeLoc;
85
86 int id;
87 int socket_fd;
88 pthread_t pid;
89
90 struct MHD_Daemon * daemon;
91
92 int bufPos;
93 int messagePos;
94 char inbuf[MHD_MAX_BUF_SIZE];
95
96 int firstFreeHeader;
97 char * requestType;
98 char * documentName;
99 struct MHD_HTTP_Header * headers[MHD_MAX_HEADERS];
100 46
101 unsigned short responsePending; 47#define MHD_MAX_BUF_SIZE 2048
102 int currentResponse;
103 struct MHD_Response * currentResponses[MHD_MAX_RESPONSE];
104};
105
106
107struct MHD_Response {
108 pthread_mutex_t mutex;
109
110 unsigned int responseCode;
111
112 int freeWhenFinished;
113
114 unsigned int headersSent;
115
116 size_t size;
117 void * data;
118 int bytesSentSoFar;
119
120 int must_free;
121 MHD_ContentReaderCallback crc;
122
123 void * crc_cls;
124 MHD_ContentReaderFreeCallback crfc;
125
126 int firstFreeHeader;
127 struct MHD_HTTP_Header * headers[MHD_MAX_HEADERS];
128
129 struct MHD_Session * currentSession;
130};
131
132struct MHD_Access_Handler {
133 char * uri_prefix;
134 MHD_AccessHandlerCallback dh;
135 void * dh_cls;
136};
137 48
138struct MHD_HTTP_Header {
139 char * header;
140 char * headerContent;
141 enum MHD_ValueKind kind;
142};
143 49
144/** 50/**
145 * Add a header line to the response. 51 * fprintf-like helper function for logging debug
146 * 52 * messages.
147 * @return MHD_NO on error (i.e. invalid header or content format).
148 */ 53 */
149int 54static void DLOG(const struct MHD_Daemon * daemon,
150MHD_add_response_header(struct MHD_Response * response, 55 const char * format,
151 const char * header, 56 ...) {
152 const char * content) { 57 va_list va;
153 //Note that as of this time this function will also return 58
154 //an error if the maximum number of headers allowed is exceeded. 59 if ( (daemon->options & MHD_USE_DEBUG) == 0)
155 60 return;
156 char * saveptr; 61 va_start(va, format);
157 char * newHeader; 62 vfprintf(stderr, format, va);
158 char * newContent; 63 va_end(va);
159 int i;
160
161 if(response == NULL || header == NULL || content == NULL || strlen(header) == 0 || strlen(content) == 0) {
162 return MHD_NO;
163 }
164 /* CG: use linked list to avoid limitation and over-allocation! */
165 if(response->firstFreeHeader >= MHD_MAX_HEADERS) {
166 return MHD_NO;
167 }
168
169 newHeader = (char *)malloc(strlen(header)+1);
170 newContent = (char *)malloc(strlen(content)+1);
171 /* CG: useless check! */
172 if(newHeader == NULL || newContent == NULL) {
173 /* CG: printf! */
174 fprintf(stderr, "Error allocating memory!\n");
175 return MHD_NO;
176 }
177
178 /* CG: do you mean strcpy/strdup? defer allocation
179 until you need to (after malformed checks!) */
180 sprintf(newHeader, "%s", header);
181 sprintf(newContent, "%s", content);
182
183 /* CG: why not use strstr? */
184 if(strtok_r(newHeader, " \t\r\n", &saveptr) != NULL) {
185 fprintf(stderr, "Malformed header!\n");
186 free(newContent);
187 free(newHeader);
188 return MHD_NO;
189 }
190
191 /* CG: why not use strstr? */
192 if(strtok_r(newContent, "\n", &saveptr) != NULL) {
193 fprintf(stderr, "Malformed content!\n");
194 free(newContent);
195 free(newHeader);
196 return MHD_NO;
197 }
198
199 /* CG: this is not C++ -- no need to cast after malloc! */
200 struct MHD_HTTP_Header * newHTTPHeader = (struct MHD_HTTP_Header *)malloc(sizeof(struct MHD_HTTP_Header));
201
202 if(newHTTPHeader == NULL) {
203 /* CG: useless check, printf */
204 fprintf(stderr, "Error allocating memory!\n");
205 free(newContent);
206 free(newHeader);
207 return MHD_NO;
208 }
209
210 /* CG: strdup here, avoids free's above! */
211 response->headers[response->firstFreeHeader]->header = newHeader;
212 response->headers[response->firstFreeHeader]->headerContent = newContent;
213
214 //For now, everything is a HTTP Header... this needs to be improved!
215 /* CG: what else are you thinking about? Cookies?
216 sounds like you are proposing an API change!!! */
217
218 response->headers[response->firstFreeHeader]->kind = MHD_HEADER_KIND;
219
220 /* CG: YUCK! Yet another reason for linked lists...
221 Why bother with the firstFreeHandler field if
222 you're O(n) anyway!? */
223 response->firstFreeHeader=MHD_MAX_HEADERS;
224 for(i = 0; i < MHD_MAX_HEADERS; i++) {
225 if(response->headers[i] == NULL) {
226 response->firstFreeHeader = i;
227 break;
228 }
229 }
230
231 return MHD_YES;
232} 64}
233 65
234/**
235 * This function accepts an incoming connection
236 * and creates the MHD_Session object for it.
237 * It also enforces policy by way of calling the accept policy callback
238 */
239int
240MHD_create_connection(struct MHD_Daemon * daemon) {
241 int i, first_free, size;
242
243 if(daemon == NULL)
244 return -1;
245
246 first_free = -1;
247 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) {
248 if(daemon->connections[i] == NULL) {
249 first_free = i;
250 break;
251 }
252 }
253
254 if(first_free == -1)
255 return -1;
256
257 /* CG: delay allocation until at accept has succeeded! */
258 daemon->connections[first_free] = (struct MHD_Session *)malloc(sizeof(struct MHD_Session));
259
260 if(daemon->connections[first_free] == NULL) {
261 /* CG: use MACRO or (static) helper function
262 instead of writing this option check everywhere! */
263 if((daemon->options & MHD_USE_DEBUG) != 0)
264 fprintf(stderr, "Error allocating memory!\n");
265 return -1;
266 }
267
268 size = sizeof(struct sockaddr);
269 daemon->connections[first_free]->socket_fd =
270
271 accept(daemon->socket_fd, (struct sockaddr *)&daemon->connections[first_free]->addr,
272 (socklen_t *)&size);
273
274 if(daemon->connections[first_free]->socket_fd == -1) {
275 free(daemon->connections[first_free]);
276 daemon->connections[first_free] = NULL;
277 if((daemon->options & MHD_USE_DEBUG) != 0) {
278 fprintf(stderr, "Error accepting incoming connections!\n");
279 }
280 return -1;
281 }
282
283 if(daemon->apc != NULL && daemon->apc(daemon->apc_cls, (const struct sockaddr *)&daemon->connections[first_free]->addr, (socklen_t)sizeof(struct sockaddr_in))==MHD_NO) {
284 close(daemon->connections[first_free]->socket_fd);
285 free(daemon->connections[first_free]);
286 daemon->connections[first_free] = NULL;
287 if((daemon->options & MHD_USE_DEBUG) != 0) {
288 fprintf(stderr, "Connection denied based on accept policy callback!\n");
289 }
290 return -1;
291 }
292
293 daemon->connections[first_free]->id = first_free;
294 daemon->connections[first_free]->daemon = daemon;
295 daemon->connections[first_free]->pid = (pthread_t)-1;
296 daemon->connections[first_free]->bufPos = 0;
297 daemon->connections[first_free]->messagePos= 0;
298 daemon->connections[first_free]->responsePending = 0;
299 memset(daemon->connections[first_free]->inbuf, '\0', MHD_MAX_BUF_SIZE);
300 daemon->connections[first_free]->currentResponse = 0;
301 daemon->connections[first_free]->firstFreeHeader = 0;
302
303 for(i = 0; i < MHD_MAX_HEADERS; i++) {
304 daemon->connections[first_free]->headers[i] = NULL;
305 }
306
307 for(i = 0; i < MHD_MAX_RESPONSE; i++) {
308 daemon->connections[first_free]->currentResponses[i] = NULL;
309 }
310 /* CG: maybe better to re-compute max_fd closer to select;
311 also handles deletion mo re graceful, need to iterate over
312 all connections anyway for FD_SET... */
313 if(daemon->max_fd < daemon->connections[first_free]->socket_fd) {
314 daemon->max_fd = daemon->connections[first_free]->socket_fd;
315 }
316
317 return first_free;
318}
319 66
320/** 67/**
321 * Create a response object. The response object can be extended with 68 * Register an access handler for all URIs beginning with uri_prefix.
322 * header information and then be used any number of times.
323 * 69 *
324 * @param size size of the data portion of the response, -1 for unknown 70 * @param uri_prefix
325 * @param crc callback to use to obtain response data 71 * @return MRI_NO if a handler for this exact prefix
326 * @param crc_cls extra argument to crc 72 * already exists
327 * @param crfc callback to call to free crc_cls resources
328 * @return NULL on error (i.e. invalid arguments, out of memory)
329 */ 73 */
330struct MHD_Response * 74int
331MHD_create_response_from_callback(size_t size, 75MHD_register_handler(struct MHD_Daemon * daemon,
332 MHD_ContentReaderCallback crc, 76 const char * uri_prefix,
333 void * crc_cls, 77 MHD_AccessHandlerCallback dh,
334 MHD_ContentReaderFreeCallback crfc) { 78 void * dh_cls) {
335 79 struct MHD_Access_Handler * ah;
336 struct MHD_Response * retVal; 80
337 int i; 81 if ( (daemon == NULL) ||
338 82 (uri_prefix == NULL) ||
339 83 (dh == NULL) )
340 if(crc == NULL) { 84 return MHD_NO;
341 /* CG: printf! */ 85 ah = daemon->handlers;
342 fprintf(stderr, "A ContentReaderCallback must be provided to MHD_create_response_from_callback!\n"); 86 while (ah != NULL) {
343 return NULL; 87 if (0 == strcmp(uri_prefix,
344 } 88 ah->uri_prefix))
345 89 return MHD_NO;
346 retVal = (struct MHD_Response *) malloc(sizeof(struct MHD_Response)); 90 ah = ah->next;
347 if(retVal == NULL) { 91 }
348 /* CG: printf, useless check, useless cast */ 92 ah = malloc(sizeof(MHD_AccessHandlerCallback));
349 fprintf(stderr, "Error allocating memory!\n"); 93 ah->next = daemon->handlers;
350 return NULL; 94 ah->uri_prefix = strdup(uri_prefix);
351 } 95 ah->dh = dh;
352 96 ah->dh_cls = dh_cls;
353 retVal->size = size; 97 daemon->handlers = ah;
354 98 return MHD_YES;
355 retVal->crc = crc;
356 retVal->crc_cls = crc_cls;
357
358 retVal->crfc = crfc;
359
360 retVal->firstFreeHeader = 0;
361
362 retVal->responseCode = 0;
363
364 retVal->headersSent = 0;
365
366 retVal->bytesSentSoFar = 0;
367
368 retVal->freeWhenFinished = 0;
369 retVal->currentSession = NULL;
370
371 if(pthread_mutex_init(&retVal->mutex, NULL) != 0) {
372 fprintf(stderr, "Error initializing mutex!\n");
373 free(retVal);
374 return NULL;
375 }
376 /* CG: use memset? linked list!!? */
377 for(i = 0; i < MHD_MAX_HEADERS; i++) {
378 retVal->headers[i] = NULL;
379 }
380
381 retVal->data = NULL;
382 retVal->must_free = 0;
383
384 return retVal;
385} 99}
386 100
387/**
388 * Create a response object. The response object can be extended with
389 * header information and then be used any number of times.
390 *
391 * @param size size of the data portion of the response
392 * @param data the data itself
393 * @param must_free libmicrohttpd should free data when done
394 * @param must_copy libmicrohttpd must make a copy of data
395 * right away, the data maybe released anytime after
396 * this call returns
397 * @return NULL on error (i.e. invalid arguments, out of memory)
398 */
399struct MHD_Response *
400MHD_create_response_from_data(size_t size,
401 void * data,
402 int must_free,
403 int must_copy) {
404
405 struct MHD_Response * retVal;
406 int i;
407
408
409 if(data == NULL) {
410 fprintf(stderr, "data must be provided to MHD_Create_response_from_data!\n");
411 return NULL;
412 }
413
414 retVal = (struct MHD_Response *) malloc(sizeof(struct MHD_Response));
415 if(retVal == NULL) {
416 fprintf(stderr, "Error allocating memory!\n");
417 return NULL;
418 }
419
420 retVal->size = size;
421
422 retVal->crc = NULL;
423 retVal->crc_cls = NULL;
424 retVal->crfc = NULL;
425
426 retVal->responseCode = 0;
427
428 retVal->firstFreeHeader = 0;
429 retVal->freeWhenFinished = 0;
430 retVal->currentSession = NULL;
431
432 retVal->headersSent = 0;
433
434 retVal->bytesSentSoFar = 0;
435
436 for(i = 0; i < MHD_MAX_HEADERS; i++) {
437 retVal->headers[i] = NULL;
438 }
439
440 if(pthread_mutex_init(&retVal->mutex, NULL) != 0) {
441 fprintf(stderr, "Error initializing mutex!\n");
442 free(retVal);
443 return NULL;
444 }
445
446 if(must_copy) {
447 retVal->data = malloc(size);
448 if(retVal->data == NULL) {
449 fprintf(stderr, "Error allocating memory!\n");
450 free(retVal);
451 return NULL;
452 }
453 memcpy(retVal->data, data, size);
454 retVal->must_free = 1;
455 } else {
456 retVal->data = data;
457 retVal->must_free = must_free;
458 }
459
460 return retVal;
461}
462 101
463/** 102/**
464 * Delete a header line from the response. 103 * Unregister an access handler for the URIs beginning with
104 * uri_prefix.
465 * 105 *
466 * @return MHD_NO on error (no such header known) 106 * @param uri_prefix
467 */ 107 * @return MHD_NO if a handler for this exact prefix
468int 108 * is not known for this daemon
469MHD_del_response_header(struct MHD_Response * response,
470 const char * header,
471 const char * content) {
472 int i;
473
474 if(header == NULL || content == NULL) {
475 return MHD_NO;
476 }
477
478 for(i = 0; i < MHD_MAX_HEADERS; i++) {
479 if(response->headers[i] != NULL &&
480 strncmp(header, response->headers[i]->header, strlen(header)) == 0 &&
481 strncmp(content, response->headers[i]->headerContent, strlen(header)) == 0) {
482 free(response->headers[i]->header);
483 free(response->headers[i]->headerContent);
484 free(response->headers[i]);
485 response->headers[i] = NULL;
486 return MHD_YES;
487 }
488 }
489 return MHD_NO;
490}
491
492/**
493 * Destroy a response object and associated resources. Note that
494 * libmicrohttpd may keep some of the resources around if the response
495 * is still in the queue for some clients, so the memory may not
496 * necessarily be freed immediatley.
497 */
498void
499MHD_destroy_response(struct MHD_Response * response) {
500 int i;
501
502 if(response == NULL) {
503 return;
504 }
505
506 pthread_mutex_lock(&response->mutex);
507
508 if(response->currentSession != NULL) {
509 response->freeWhenFinished = 1;
510 pthread_mutex_unlock(&response->mutex);
511 return;
512 }
513
514 if(response->must_free && response->data != NULL) {
515 free(response->data);
516 }
517
518 if(response->crfc != NULL && response->crc_cls != NULL) {
519 response->crfc(response->crc_cls);
520 }
521
522 for(i = 0; i < MHD_MAX_HEADERS; i++) {
523 if(response->headers[i] == NULL)
524 continue;
525
526 free(response->headers[i]->header);
527 free(response->headers[i]->headerContent);
528 free(response->headers[i]);
529 }
530
531 pthread_mutex_unlock(&response->mutex);
532 pthread_mutex_destroy(&response->mutex);
533
534 free(response);
535}
536
537/**
538 * Thi function is similar to destroy_response except
539 * that it was created to destroy the session object.
540 */ 109 */
541void 110int
542MHD_destroy_session(struct MHD_Session * session) { 111MHD_unregister_handler(struct MHD_Daemon * daemon,
543 int i; 112 const char * uri_prefix,
544 113 MHD_AccessHandlerCallback dh,
545 for(i = 0; i < MHD_MAX_HEADERS; i++) { 114 void * dh_cls) {
546 if(session->headers[i] != NULL) { 115 struct MHD_Access_Handler * prev;
547 free(session->headers[i]); 116 struct MHD_Access_Handler * pos;
548 } 117
549 } 118 if ( (daemon == NULL) ||
550 119 (uri_prefix == NULL) ||
551 for(i = 0; i < MHD_MAX_RESPONSE; i++) { 120 (dh == NULL) )
552 if(session->currentResponses[i] != NULL) { 121 return MHD_NO;
553 pthread_mutex_lock(&session->currentResponses[i]->mutex); 122 pos = daemon->handlers;
554 session->currentResponses[i]->currentSession = NULL; 123 prev = NULL;
555 pthread_mutex_unlock(&session->currentResponses[i]->mutex); 124 while (pos != NULL) {
556 } 125 if ( (dh == ah->dh) &&
557 } 126 (dh_cls == ah->dh_cls) &&
558 127 (0 == strcmp(uri_prefix,
559 close(session->socket_fd); 128 ah->uri_prefix)) ) {
560 free(session); 129 if (prev == NULL)
130 daemon->handlers = pos->next;
131 else
132 prev->next = pos->next;
133 free(pos);
134 return MHD_YES;
135 }
136 prev = pos;
137 pos = pos->next;
138 }
139 return MHD_NO;
561} 140}
562 141
563/** 142/**
@@ -573,576 +152,233 @@ MHD_get_fdset(struct MHD_Daemon * daemon,
573 fd_set * write_fd_set, 152 fd_set * write_fd_set,
574 fd_set * except_fd_set, 153 fd_set * except_fd_set,
575 int * max_fd) { 154 int * max_fd) {
576 155 struct MHD_Session * pos;
577 int i; 156
578 157 if ( (daemon == NULL) ||
579 if(daemon == NULL || read_fd_set == NULL || write_fd_set == NULL || except_fd_set == NULL || max_fd == NULL) { 158 (read_fd_set == NULL) ||
580 return MHD_NO; 159 (write_fd_set == NULL) ||
581 } 160 (except_fd_set == NULL) ||
582 161 (max_fd == NULL) ||
583 if((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) { 162 ( (daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) )
584 return MHD_NO; 163 return MHD_NO;
585 } 164 FD_SET(daemon->socket_fd,
586 165 &daemon->read_fd_set);
587 FD_ZERO(read_fd_set); 166 if ( (*max_fd) < daemon->socket_fd)
588 FD_ZERO(write_fd_set); 167 *max_fd = daemon->socket_fd;
589 FD_ZERO(except_fd_set); 168 pos = daemon->session;
590 169 while (pos != NULL) {
591 FD_SET(daemon->socket_fd, &daemon->read_fd_set); 170 if (MHD_YES != MHD_session_get_fdset(pos,
592 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) { 171 read_fd_set,
593 if(daemon->connections[i] != NULL) { 172 write_fd_set,
594 FD_SET(daemon->connections[i]->socket_fd, read_fd_set); 173 except_fd_set,
595 FD_SET(daemon->connections[i]->socket_fd, write_fd_set); 174 max_fd))
596 } 175 return MHD_NO;
597 } 176 pos = pos->next;
598 177 }
599 *max_fd = daemon->max_fd; 178 return MHD_YES;
600
601 return MHD_YES;
602}
603
604/**
605 * Get all of the headers added to a response.
606 *
607 * @param iterator callback to call on each header;
608 * maybe NULL (then just count headers)
609 * @param iterator_cls extra argument to iterator
610 * @return number of entries iterated over
611 */
612int
613MHD_get_response_headers(struct MHD_Response * response,
614 MHD_KeyValueIterator * iterator,
615 void * iterator_cls) {
616 int i, numHeaders;
617
618 if(response == NULL) {
619 return -1;
620 }
621
622 numHeaders = 0;
623 for(i = 0; i < MHD_MAX_HEADERS; i++) {
624 if(response->headers[i] != NULL) {
625 if(iterator != NULL) {
626 (*iterator)(iterator_cls, response->headers[i]->kind, response->headers[i]->header, response->headers[i]->headerContent);
627 }
628 numHeaders++;
629 }
630 }
631 return numHeaders;
632} 179}
633 180
634/**
635 * Get all of the headers from the request.
636 *
637 * @param iterator callback to call on each header;
638 * maybe NULL (then just count headers)
639 * @param iterator_cls extra argument to iterator
640 * @return number of entries iterated over
641 */
642int
643MHD_get_session_values(struct MHD_Session * session,
644 enum MHD_ValueKind kind,
645 MHD_KeyValueIterator * iterator,
646 void * iterator_cls) {
647 int i, numHeaders;
648
649 if(session == NULL) {
650 return -1;
651 }
652 numHeaders = 0;
653 for(i = 0; i < MHD_MAX_HEADERS; i++) {
654 if(session->headers[i] != NULL && session->headers[i]->kind == kind) {
655 if(iterator != NULL) {
656 (*iterator)(iterator_cls, session->headers[i]->kind, session->headers[i]->header, session->headers[i]->headerContent);
657 }
658 numHeaders++;
659 }
660 }
661 return numHeaders;
662}
663 181
664/** 182/**
665 * This function is intented to be called in the case of 183 * Main function of the thread that handles an individual
666 * multithreaded connections. A thread will be spawned calling this 184 * connection.
667 * function with a particular connection, and the thread will poll the connection
668 * (this should be improved) until there is something to do
669 */ 185 */
670void * 186static void *
671MHD_handle_connection(void * data) { 187MHD_handle_connection(void * data) {
672 struct MHD_Session * con; 188 struct MHD_Session * con = data;
673 int num_ready; 189 int num_ready;
674 struct timeval timeout; 190 fd_set rs;
675 fd_set read; 191 fd_set ws;
676 fd_set write; 192 fd_set es;
677 193 int max;
678 con = data; 194
679 195 if (con == NULL)
680 if(con == NULL) 196 abort();
681 return NULL; 197 while (! con->daemon->shutdown) {
682 198 FD_ZERO(&rs);
683 do { 199 FD_ZERO(&ws);
684 200 FD_ZERO(&es);
685 FD_ZERO(&read); 201 max = 0;
686 FD_ZERO(&write); 202 MHD_session_get_fdset(con,
687 203 &rs,
688 FD_SET(con->socket_fd, &read); 204 &ws,
689 FD_SET(con->socket_fd, &write); 205 &es,
690 206 &max);
691 timeout.tv_sec = 0; 207 num_ready = select(max + 1,
692 timeout.tv_usec = 0; 208 &rs,
693 209 &ws,
694 num_ready = select(con->socket_fd + 1, 210 &es,
695 &read, &write, NULL, &timeout); 211 NULL);
696 212 if (num_ready <= 0) {
697 if(num_ready > 0) { 213 if (errno == EINTR)
698 if(FD_ISSET(con->socket_fd, &read)) { 214 continue;
699 if(MHD_handle_read(con->id, con->daemon) == MHD_NO) { 215 break;
700 pthread_detach(pthread_self()); 216 }
701 return NULL; 217 if ( ( (FD_ISSET(con->socket_fd, &rs)) &&
702 } 218 (MHD_YES != MHD_session_handle_read(con)) ) ||
703 } 219 ( (FD_ISSET(con->socket_fd, &ws)) &&
704 if (FD_ISSET(con->socket_fd, &write)) { 220 (MHD_YES != MHD_session_handle_write(con)) ) )
705 if(MHD_handle_write(con->id, con->daemon) == MHD_NO) { 221 break;
706 pthread_detach(pthread_self()); 222 }
707 return NULL; 223 close(con->socket_fd);
708 } 224 con->socket_fd = -1;
709 } 225 return NULL;
710 }
711 } while (!con->daemon->shutdown);
712
713 return NULL;
714}
715
716/**
717 * This function is created to handle the except file descriptor
718 * set, but it is doubtfull that it will ever be used.
719 */
720void
721MHD_handle_except(int connection_id, struct MHD_Daemon * daemon) {
722 //It is unlikely that this function will ever need to be implemented.
723} 226}
724 227
725/**
726 * This function handles a particular connection when it has been
727 * determined that there is data to be read off a socket. All implementations
728 * (multithreaded, external select, internal select) call this function
729 * to handle reads.
730 */
731int
732MHD_handle_read(int connection_id, struct MHD_Daemon * daemon) {
733 int bytes_read,i;
734
735 if((daemon->options & MHD_USE_DEBUG) != 0) {
736 fprintf(stderr, "Enter MHD_handle_read\n");
737 }
738
739 if(daemon == NULL || daemon->connections[connection_id]==NULL) {
740 return MHD_NO;
741 }
742
743 if(daemon->connections[connection_id]->responsePending) {
744 return MHD_YES;
745 }
746
747 daemon->connections[connection_id]->firstFreeHeader = 0;
748 daemon->connections[connection_id]->requestType = NULL;
749
750 for(i = 0; i < MHD_MAX_HEADERS; i++) {
751 daemon->connections[connection_id]->headers[i] = NULL;
752 }
753
754
755
756 memmove(daemon->connections[connection_id]->inbuf, daemon->connections[connection_id]->inbuf+daemon->connections[connection_id]->messagePos, daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos);
757
758 memset(daemon->connections[connection_id]->inbuf + daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos,
759 0, MHD_MAX_BUF_SIZE - daemon->connections[connection_id]->bufPos + (daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos));
760
761 bytes_read = recv(daemon->connections[connection_id]->socket_fd,
762 daemon->connections[connection_id]->inbuf + daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos,
763 MHD_MAX_BUF_SIZE - (daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos), 0);
764
765 daemon->connections[connection_id]->bufPos = bytes_read + daemon->connections[connection_id]->bufPos - daemon->connections[connection_id]->messagePos;
766
767 if(bytes_read == 0) {
768 MHD_destroy_session(daemon->connections[connection_id]);
769 daemon->connections[connection_id] = NULL;
770 return MHD_NO;
771 } else {
772 fprintf(stderr, "\"%s\"\n", daemon->connections[connection_id]->inbuf);
773 i = MHD_parse_message(daemon->connections[connection_id]);
774 if(i == -1) {
775 daemon->connections[connection_id]->messagePos = daemon->connections[connection_id]->bufPos;
776 return MHD_YES;
777 } else {
778 daemon->connections[connection_id]->messagePos = i;
779 fprintf(stderr, "Number of bytes in header: %i\n", daemon->connections[connection_id]->messagePos);
780 }
781
782 daemon->connections[connection_id]->responsePending = 1;
783
784 MHD_parse_URL(daemon->connections[connection_id]);
785
786 for(i = 0; i < MHD_MAX_HANDLERS; i++) {
787 if(daemon->handlers[i] == NULL)
788 continue;
789
790 //header 0 will hold the url of the request
791 if(strstr(daemon->connections[connection_id]->headers[0]->headerContent, daemon->handlers[i]->uri_prefix) != NULL){
792 return daemon->handlers[i]->dh(daemon->handlers[i]->dh_cls, daemon->connections[connection_id],
793 daemon->connections[connection_id]->documentName, daemon->connections[connection_id]->requestType, NULL, NULL);
794 }
795 }
796 return daemon->dh(daemon->dh_cls, daemon->connections[connection_id],
797 daemon->connections[connection_id]->documentName, daemon->connections[connection_id]->requestType, NULL, NULL);
798 }
799
800 return MHD_YES;
801}
802 228
803/** 229/**
804 * This function was created to handle writes to sockets when it has been 230 * Accept an incoming connection and create the MHD_Session object for
805 * determined that the socket can be written to. If there is no data 231 * it. This function also enforces policy by way of checking with the
806 * to be written, however, the function call does nothing. All implementations 232 * accept policy callback.
807 * (multithreaded, external select, internal select) call this function
808 */ 233 */
809int 234static int
810MHD_handle_write(int connection_id, struct MHD_Daemon * daemon) { 235MHD_accept_connection(struct MHD_Daemon * daemon) {
811 struct MHD_Session * session; 236 struct MHD_Session * session;
812 237 struct sockaddr addr;
813 struct MHD_Response * response; 238 socklen_t addrlen;
814 239 int s;
815 int i; 240
816 241 addrlen = sizeof(struct sockaddr);
817 char * buffer[2048]; 242 memset(&addr,
818 243 0,
819 char * responseMessage; 244 sizeof(struct sockaddr));
820 int numBytesInMessage; 245 if ( (0 != (s = accept(daemon->socket_fd,
821 246 &addr,
822 if((daemon->options & MHD_USE_DEBUG) != 0) { 247 &addrlen))) ||
823 fprintf(stderr, "Enter MHD_handle_write\n"); 248 (addrlen <= 0) ) {
824 } 249 DLOG(daemon,
825 250 "Error accepting connection: %s\n",
826 251 strerror(errno));
827 session = daemon->connections[connection_id]; 252 return MHD_NO;
828 253 }
829 response = session->currentResponses[session->currentResponse]; 254 if (MHD_NO == daemon->apc(mhd->apc_cls,
830 255 &addr,
831 numBytesInMessage = 25; 256 addrlen)) {
832 257 close(s);
833 responseMessage = malloc(25); 258 return MHD_YES;
834 if(responseMessage == NULL) { 259 }
835 if(daemon->options & MHD_USE_DEBUG) 260 session = malloc(sizeof(struct MHD_Session));
836 fprintf(stderr, "Error allocating memory!\n"); 261 memset(session,
837 return MHD_NO; 262 0,
838 } 263 sizeof(struct MHD_Session));
839 264 session->addr = malloc(addrlen);
840 if(response == NULL) 265 memcpy(session->addr,
841 return MHD_NO; 266 &addr,
842 267 addrlen);
843 pthread_mutex_lock(&response->mutex); 268 session->addr_len = addrlen;
844 269 session->socket_fd = s;
845 if(!response->headersSent) { 270 session->daemon = daemon;
846 sprintf(responseMessage, "HTTP/1.1 %i Go to hell!\r\n", response->responseCode); 271 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION) ) &&
847 fprintf(stderr, "%s\n", responseMessage); 272 (0 != pthread_create(&session->pid,
848 if(send(session->socket_fd, responseMessage, strlen(responseMessage), 0) != strlen(responseMessage)) { 273 NULL,
849 fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n"); 274 &MHD_handle_connection,
850 pthread_mutex_unlock(&response->mutex); 275 session)) ) {
851 return MHD_NO; 276 DLOG(daemon,
852 } 277 "Failed to create a thread: %s\n",
853 278 strerror(errno));
854 for(i = 0; i < MHD_MAX_HEADERS; i++) { 279 free(session->addr);
855 if(response->headers[i] == NULL) 280 close(s);
856 continue; 281 free(session);
857 282 return MHD_NO;
858 if(strlen(response->headers[i]->header) + strlen(response->headers[i]->headerContent) + 5 > numBytesInMessage) { 283 }
859 free(responseMessage); 284 session->next = daemon->connections;
860 responseMessage = malloc(strlen(response->headers[i]->header) + strlen(response->headers[i]->headerContent) + 5); 285 daemon->connections = session;
861 if(responseMessage == NULL) { 286 return MHD_YES;
862 if(daemon->options & MHD_USE_DEBUG)
863 fprintf(stderr, "Error allocating memory!\n");
864 pthread_mutex_unlock(&response->mutex);
865 return MHD_NO;
866 }
867 numBytesInMessage = strlen(response->headers[i]->header) + strlen(response->headers[i]->headerContent) + 5;
868 }
869 sprintf(responseMessage, "%s: %s\r\n", response->headers[i]->header, response->headers[i]->headerContent);
870 fprintf(stderr, "%s\n", responseMessage);
871 if(send(session->socket_fd, responseMessage, strlen(responseMessage), 0) != strlen(responseMessage)) {
872 fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n");
873 pthread_mutex_unlock(&response->mutex);
874 return MHD_NO;
875 }
876 }
877
878 response->headersSent = 1;
879 }
880
881 if(response->data != NULL) {
882 if(response->bytesSentSoFar == 0) {
883 if(numBytesInMessage < 32) {
884 free(responseMessage);
885 responseMessage = malloc(32);
886 if(responseMessage == NULL) {
887 if(daemon->options & MHD_USE_DEBUG)
888 fprintf(stderr, "Error allocating memory!\n");
889 pthread_mutex_unlock(&response->mutex);
890 return MHD_NO;
891 }
892 }
893 sprintf(responseMessage, "Content-length: %llu\r\n\r\n", (unsigned long long)response->size);
894 fprintf(stderr, "%s\n", responseMessage);
895 if(send(session->socket_fd, responseMessage, strlen(responseMessage),0)!= strlen(responseMessage)) {
896 fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n");
897 pthread_mutex_unlock(&response->mutex);
898 return MHD_NO;
899 }
900 }
901
902 i = send(session->socket_fd, response->data+response->bytesSentSoFar, response->size-response->bytesSentSoFar,0);
903 response->bytesSentSoFar += i;
904
905 fprintf(stderr, "Sent %i bytes of data\nTotal to send is %llu bytes\n", i, (unsigned long long)response->size);
906
907 if(response->bytesSentSoFar == response->size) {
908 session->currentResponses[session->currentResponse] = NULL;
909 session->currentResponse = (session->currentResponse + 1) % MHD_MAX_RESPONSE;
910 response->currentSession = NULL;
911
912 if(response->freeWhenFinished) {
913 pthread_mutex_unlock(&response->mutex);
914 MHD_destroy_response(response);
915 }
916 /*THIS NEEDS TO BE HANDLED ANOTHER WAY!!! TIMEOUT, ect..., as of now this is the only way to get test case to work
917 * since client never disconnects on their own!
918 */
919 if(session->currentResponses[session->currentResponse] == NULL) {
920 MHD_destroy_session(session);
921 daemon->connections[connection_id] = NULL;
922 return MHD_NO;
923 }
924 }
925 } else {
926 if(response->crc == NULL) {
927 pthread_mutex_unlock(&response->mutex);
928 return MHD_NO;
929 }
930
931 if(response->bytesSentSoFar == 0) {
932 if(send(session->socket_fd, "\r\n", response->size,0) != 2) {
933 fprintf(stderr, "Error! could not send an entire header in one call to send! unable to handle this case as of this time.\n");
934 pthread_mutex_unlock(&response->mutex);
935 return MHD_NO;
936 }
937 }
938 memset(buffer, 0, 2048);
939
940 i = response->crc(response->crc_cls, response->bytesSentSoFar, (char *)buffer, 2048);
941
942 if(i == -1) {
943 pthread_mutex_unlock(&response->mutex);
944
945 session->currentResponses[session->currentResponse] = NULL;
946 session->currentResponse = (session->currentResponse + 1) % MHD_MAX_RESPONSE;
947 response->currentSession = NULL;
948
949 if(response->freeWhenFinished) {
950 pthread_mutex_unlock(&response->mutex);
951 MHD_destroy_response(response);
952 }
953 /*THIS NEEDS TO BE HANDLED ANOTHER WAY!!! TIMEOUT, ect..., as of now this is the only way to get test case to work
954 * since client never disconnects on their own!
955 */
956 if(session->currentResponses[session->currentResponse] == NULL) {
957 MHD_destroy_session(session);
958 daemon->connections[connection_id] = NULL;
959 return MHD_NO;
960 }
961
962 } else {
963 i = send(session->socket_fd, buffer, i,0);
964 response->bytesSentSoFar += i;
965 }
966 }
967 pthread_mutex_unlock(&response->mutex);
968 return MHD_YES;
969}
970
971
972/**
973 * Get a particular header value. If multiple
974 * values match the kind, return any one of them.
975 *
976 * @param key the header to look for
977 * @return NULL if no such item was found
978 */
979const char *
980MHD_lookup_session_value(struct MHD_Session * session,
981 enum MHD_ValueKind kind,
982 const char * key) {
983 int i;
984
985 for(i = 0; i < MHD_MAX_HEADERS; i++) {
986 if(session->headers[i] != NULL &&
987 session->headers[i]->kind == kind &&
988 strncmp(session->headers[i]->header, key, strlen(session->headers[i]->header)) == 0) {
989 return (const char *)session->headers[i]->headerContent;
990 }
991 }
992
993 return NULL;
994} 287}
995 288
996 289
997/** 290/**
998 * This function is designed to parse the input buffer of a given session. 291 * Free resources associated with all closed sessions.
999 * It is assumed that the data being parsed originates at buffer location 292 * (destroy responses, free buffers, etc.). A session
1000 * 0 (a valid assumption since the buffer is shifted after each message) 293 * is known to be closed if the socket_fd is -1.
1001 */ 294 */
1002int 295static void
1003MHD_parse_message(struct MHD_Session * session) { 296MHD_cleanup_sessions(struct MHD_Daemon * daemon) {
1004 const char * crlfcrlf = "\r\n\r\n"; 297 struct MHD_Session * pos;
1005 const char * crlf = "\r\n"; 298 struct MHD_Session * prev;
1006 299
1007 char * saveptr; 300 pos = daemon->connections;
1008 char * saveptr1; 301 prev = NULL;
1009 302 while (pos != NULL) {
1010 struct MHD_HTTP_Header * newHeader; 303 if (pos->socket_fd == -1) {
1011 char * curTok; 304 if (prev == NULL)
1012 char * curTok1; 305 daemon->connections = pos->next;
1013 306 else
1014 int numBytes; 307 prev->next = pos->next;
1015 308 free(pos->addr);
1016 curTok = strstr(session->inbuf, crlfcrlf); 309 /* FIXME: more to free here! */
1017 310 free(pos);
1018 if(curTok == NULL) { 311 }
1019 return -1; 312 prev = pos;
1020 } 313 pos = pos->next;
1021 314 }
1022 memset(curTok+2, 0, 2);
1023
1024 numBytes = strlen(session->inbuf) + 2;
1025
1026 curTok = strtok_r(session->inbuf, crlf, &saveptr);
1027
1028 session->requestType = strtok_r(curTok, " ", &saveptr1);
1029
1030 newHeader = (struct MHD_HTTP_Header *)malloc(sizeof(struct MHD_HTTP_Header));
1031 if(newHeader == NULL) {
1032 if(session->daemon->options & MHD_USE_DEBUG)
1033 fprintf(stderr, "Error allocating memory!\n");
1034 return -1;
1035 }
1036 newHeader->kind = MHD_GET_ARGUMENT_KIND;
1037 newHeader->header = session->requestType;
1038 newHeader->headerContent = strtok_r(NULL, " ", &saveptr1);
1039
1040 session->headers[session->firstFreeHeader++] = newHeader;
1041
1042 curTok = strtok_r(NULL, crlf, &saveptr);
1043 while(curTok != NULL && session->firstFreeHeader < MHD_MAX_HEADERS) {
1044 curTok1 = strtok_r(curTok, ":", &saveptr1);
1045 newHeader = (struct MHD_HTTP_Header *)malloc(sizeof(struct MHD_HTTP_Header));
1046 if(newHeader == NULL) {
1047 if(session->daemon->options & MHD_USE_DEBUG)
1048 fprintf(stderr, "Error allocating memory!\n");
1049 return -1;
1050 }
1051 newHeader->header = curTok1;
1052 newHeader->headerContent = curTok + strlen(curTok1) + 2;
1053 //For now, everything is a get!
1054 newHeader->kind = MHD_GET_ARGUMENT_KIND;
1055 session->headers[session->firstFreeHeader++] = newHeader;
1056 curTok = strtok_r(NULL, crlf, &saveptr);
1057 }
1058
1059 return numBytes;
1060} 315}
1061 316
1062/**
1063 * This function needs to do a lot more (i.e. break up get arguments)
1064 * but for now just seperates the prefix of the url from the document
1065 * portion.
1066 */
1067void
1068MHD_parse_URL(struct MHD_Session * session) {
1069 char * working;
1070 int pos,i;
1071
1072 working = session->headers[0]->headerContent;
1073
1074 pos = 0;
1075 for(i = 0; i < strlen(working); i++) {
1076 if(working[i] == '/')
1077 pos = i+1;
1078 }
1079 if(pos >= strlen(working))
1080 pos = 0;
1081
1082 session->documentName = session->headers[0]->headerContent+pos;
1083}
1084 317
1085/** 318/**
1086 * Queue a response to be transmitted to the client (as soon as 319 * Main select call.
1087 * possible). 320 *
1088 * 321 * @return MHD_NO on serious errors, MHD_YES on success
1089 * @param session the session identifying the client
1090 * @param status_code HTTP status code (i.e. 200 for OK)
1091 * @param response response to transmit
1092 * @return MHD_NO on error (i.e. reply already sent),
1093 * MHD_YES on success or if message has been queued
1094 */ 322 */
1095int 323static int
1096MHD_queue_response(struct MHD_Session * session, 324MHD_select(struct MHD_Daemon * daemon) {
1097 unsigned int status_code, 325 struct MHD_Session * pos;
1098 struct MHD_Response * response) { 326 int num_ready;
1099 327 fd_set rs;
1100 //As of now this function can only support a fixed amount of queued responses, and will 328 fd_set ws;
1101 //return MHD_NO if that queue is full 329 fd_set es;
1102 330 int max;
1103 int index; 331
1104 332 if(daemon == NULL)
1105 if(session == NULL || response == NULL) { 333 abort();
1106 return MHD_NO; 334 FD_ZERO(&rs);
1107 } 335 FD_ZERO(&ws);
1108 336 FD_ZERO(&es);
1109 pthread_mutex_lock(&response->mutex); 337 max = 0;
1110 338
1111 if(response->currentSession != NULL) { 339 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) {
1112 return MHD_NO; 340 /* single-threaded, go over everything */
1113 } 341 if (MHD_NO == MHD_get_fdset(daemon,
1114 342 &rs,
1115 if(session->currentResponses[session->currentResponse] == NULL) { 343 &ws,
1116 index = session->currentResponse; 344 &es,
1117 } else if(session->currentResponses[session->currentResponse + 1 % MHD_MAX_RESPONSE] == NULL) { 345 &max))
1118 index = session->currentResponse + 1 % MHD_MAX_RESPONSE; 346 return MHD_NO;
1119 } else { 347 } else {
1120 pthread_mutex_unlock(&response->mutex); 348 /* accept only, have one thread per connection */
1121 return MHD_NO; 349 max = daemon->socket_fd;
1122 } 350 FD_SET(daemon->socket_fd, &rs);
1123 351 }
1124 response->responseCode = status_code; 352 num_ready = select(max + 1,
1125 session->currentResponses[index] = response; 353 &rs,
1126 response->currentSession = session; 354 &ws,
1127 session->responsePending = 0; 355 &es,
1128 356 NULL);
1129 pthread_mutex_unlock(&response->mutex); 357 if (num_ready < 0) {
1130 358 if (errno == EINTR)
1131 return MHD_YES; 359 return MHD_YES;
360 DLOG(daemon,
361 "Select failed: %s\n",
362 strerror(errno));
363 return MHD_NO;
364 }
365 if (FD_ISSET(daemon->socket_fd,
366 &rs))
367 MHD_accept_connection(daemon);
368 if (0 == (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) {
369 /* do not have a thread per connection, process all connections now */
370 pos = daemon->connections;
371 while (pos != NULL) {
372 if (FD_ISSET(pos->socket_fd, &rs))
373 MHD_session_handle_read(pos);
374 if (FD_ISSET(pos->socket_fd, &ws))
375 MHD_session_handle_write(pos);
376 pos = pos->next;
377 }
378 }
379 return MHD_YES;
1132} 380}
1133 381
1134/**
1135 * @return -1 if no data uploaded; otherwise number of bytes
1136 * read into buf; 0 for end of transmission
1137 * Specification not complete at this time.
1138 */
1139int
1140MHD_read_file_upload(struct MHD_Session * session,
1141 void * buf,
1142 size_t len) {
1143 //This function will not be implemented until the specification is completed.
1144 return -1;
1145}
1146 382
1147/** 383/**
1148 * Run webserver operations (without blocking unless 384 * Run webserver operations (without blocking unless
@@ -1156,190 +392,34 @@ MHD_read_file_upload(struct MHD_Session * session,
1156 */ 392 */
1157int 393int
1158MHD_run(struct MHD_Daemon * daemon) { 394MHD_run(struct MHD_Daemon * daemon) {
1159 395 if ( (daemon->shutdown != 0) ||
1160 if((daemon->options & MHD_USE_THREAD_PER_CONNECTION) != 0) { 396 (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1161 daemon->shutdown = 0; 397 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
1162 if(pthread_create(&daemon->pid, NULL, (void *) &MHD_spawn_connections, (void *)daemon) == 0) { 398 return MHD_NO;
1163 return MHD_YES; 399 MHD_select(daemon);
1164 } else { 400 MHD_cleanup_sessions(daemon);
1165 return MHD_NO; 401 return MHD_YES;
1166 }
1167 } else if((daemon->options & MHD_USE_SELECT_INTERNALLY) != 0) {
1168 daemon->shutdown = 0;
1169 if(pthread_create(&daemon->pid, NULL, (void *) &MHD_select, (void *)daemon) == 0) {
1170 return MHD_YES;
1171 } else {
1172 return MHD_NO;
1173 }
1174 } else {
1175 daemon->shutdown = 1;
1176 return (MHD_select((void *)daemon) == NULL);
1177 }
1178} 402}
1179 403
1180 404
1181/** 405/**
1182 * Register an access handler for all URIs beginning with uri_prefix. 406 * Thread that runs the select loop until the daemon
1183 * 407 * is explicitly shut down.
1184 * @param uri_prefix
1185 * @return MRI_NO if a handler for this exact prefix
1186 * already exists
1187 */ 408 */
1188int 409static void *
1189MHD_register_handler(struct MHD_Daemon * daemon, 410MHD_select_thread(void * cls) {
1190 const char * uri_prefix, 411 struct MHD_Daemon * daemon = cls;
1191 MHD_AccessHandlerCallback dh, 412 while (daemon->shutdown == 0) {
1192 void * dh_cls) { 413 MHD_select(daemon);
1193 int i; 414 MHD_cleanup_sessions(daemon);
1194 415 }
1195 //This function will also return MHD_NO if the maximum number of supported handlers is exceeded 416 return NULL;
1196
1197 if(daemon == NULL || uri_prefix == NULL || dh == NULL) {
1198 return MHD_NO;
1199 }
1200
1201 if(daemon->firstFreeHandler >= MHD_MAX_HANDLERS) {
1202 return MHD_NO;
1203 }
1204
1205 daemon->handlers[daemon->firstFreeHandler] = malloc(sizeof(struct MHD_Access_Handler));
1206
1207 if(daemon->handlers[daemon->firstFreeHandler] == NULL) {
1208 if((daemon->options & MHD_USE_DEBUG) != 0)
1209 fprintf(stderr, "Error allocating memory!\n");
1210 return MHD_NO;
1211 }
1212
1213 daemon->handlers[daemon->firstFreeHandler]->uri_prefix = malloc(strlen(uri_prefix)+1);
1214 if(daemon->handlers[daemon->firstFreeHandler]->uri_prefix == NULL) {
1215 if((daemon->options & MHD_USE_DEBUG) != 0) {
1216 free(daemon->handlers[daemon->firstFreeHandler]);
1217 fprintf(stderr, "Error allocating memory!\n");
1218 }
1219 return MHD_NO;
1220 }
1221 sprintf(daemon->handlers[daemon->firstFreeHandler]->uri_prefix, "%s", uri_prefix);
1222
1223 daemon->handlers[daemon->firstFreeHandler]->dh = dh;
1224 daemon->handlers[daemon->firstFreeHandler]->dh_cls = dh_cls;
1225
1226 daemon->firstFreeHandler = MHD_MAX_HANDLERS;
1227 for(i = 0; i < MHD_MAX_HANDLERS; i++) {
1228 if(daemon->handlers[i] == NULL) {
1229 daemon->firstFreeHandler = i;
1230 break;
1231 }
1232 }
1233
1234 return MHD_YES;
1235
1236} 417}
1237 418
1238/**
1239 * This function is the entry point for either internal or external select.
1240 * The only differences between the two forms of running is whether the call is
1241 * made from a new thread or the main thread, and whether the initial value
1242 * of shutdown is 0 or 1 (1 for loop, 0 for one time pass)
1243 */
1244void *
1245MHD_select(void * data) {
1246 struct MHD_Daemon * daemon;
1247 int i, num_ready;
1248 struct timeval timeout;
1249
1250 daemon = data;
1251 if(daemon == NULL) {
1252 return NULL;
1253 }
1254 do {
1255 FD_ZERO(&daemon->read_fd_set);
1256 FD_ZERO(&daemon->write_fd_set);
1257 FD_ZERO(&daemon->except_fd_set);
1258
1259 FD_SET(daemon->socket_fd, &daemon->read_fd_set);
1260 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) {
1261 if(daemon->connections[i] != NULL) {
1262 FD_SET(daemon->connections[i]->socket_fd, &daemon->read_fd_set);
1263 FD_SET(daemon->connections[i]->socket_fd, &daemon->write_fd_set);
1264 }
1265 }
1266
1267 timeout.tv_sec = 0;
1268 timeout.tv_usec = 0;
1269
1270 num_ready = select(daemon->max_fd + 1,
1271 &(daemon->read_fd_set), &(daemon->write_fd_set), &(daemon->except_fd_set), &timeout);
1272
1273 if(num_ready > 0) {
1274 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) {
1275 if(daemon->connections[i] != NULL) {
1276 if(FD_ISSET(daemon->connections[i]->socket_fd, &(daemon->read_fd_set))) {
1277 if(MHD_handle_read(i, daemon) == MHD_NO)
1278 continue;
1279 }
1280 if (FD_ISSET(daemon->connections[i]->socket_fd, &(daemon->write_fd_set))) {
1281 if(MHD_handle_write(i, daemon) == MHD_NO)
1282 continue;
1283 }
1284 if (FD_ISSET(daemon->connections[i]->socket_fd, &(daemon->except_fd_set))) {
1285 MHD_handle_except(i, daemon);
1286 }
1287 }
1288 }
1289 if(FD_ISSET(daemon->socket_fd, &(daemon->read_fd_set))) {
1290 if(MHD_create_connection(daemon) == -1) {
1291 continue;
1292 }
1293 }
1294 }
1295 } while (!daemon->shutdown);
1296
1297 return NULL;
1298}
1299
1300/**
1301 * This function was created for the case of multithreaded connections.
1302 * A thread will spawned to sit on this function, and in turn spawns more
1303 * threads, one per connection.
1304 */
1305void *
1306MHD_spawn_connections(void * data) {
1307 struct MHD_Daemon * daemon;
1308 int con, num_ready;
1309 struct timeval timeout;
1310 fd_set read;
1311
1312 daemon = data;
1313 if(daemon == NULL) {
1314 return NULL;
1315 }
1316
1317 do {
1318 FD_ZERO(&read);
1319 FD_SET(daemon->socket_fd, &read);
1320
1321 timeout.tv_sec = 0;
1322 timeout.tv_usec = 0;
1323
1324 num_ready = select(daemon->socket_fd + 1,&read, NULL, NULL, &timeout);
1325
1326 if(num_ready > 0) {
1327 con = MHD_create_connection(daemon);
1328 if(con == -1)
1329 continue;
1330
1331 if(pthread_create(&daemon->connections[con]->pid, NULL, (void *) &MHD_handle_connection, (void *)daemon->connections[con]) != 0) {
1332 if((daemon->options & MHD_USE_DEBUG) != 0)
1333 fprintf(stderr, "Error creating connection handler!.\n");
1334 }
1335 }
1336 } while (!daemon->shutdown);
1337
1338 return NULL;
1339}
1340 419
1341/** 420/**
1342 * Start a webserver on the given port. 421 * Start a webserver on the given port.
422 *
1343 * @param port port to bind to 423 * @param port port to bind to
1344 * @param apc callback to call to check which clients 424 * @param apc callback to call to check which clients
1345 * will be allowed to connect 425 * will be allowed to connect
@@ -1355,128 +435,73 @@ MHD_start_daemon(unsigned int options,
1355 void * apc_cls, 435 void * apc_cls,
1356 MHD_AccessHandlerCallback dh, 436 MHD_AccessHandlerCallback dh,
1357 void * dh_cls) { 437 void * dh_cls) {
1358 438 struct MHD_Daemon * retVal;
1359 439 int socket_fd;
1360 struct MHD_Daemon * retVal = NULL; 440 int opt;
1361 int socket_fd, opt, res, i; 441 int res;
1362 struct sockaddr_in servaddr; 442 struct sockaddr_in servaddr;
1363 struct hostent *hostptr; 443
1364 char hostid[32]; 444 if ((options & MHD_USE_SSL) != 0)
1365 445 return NULL;
1366 if((options & MHD_USE_SSL) != 0) { 446 if ((options & MHD_USE_IPv6) != 0)
1367 if((options & MHD_USE_DEBUG) != 0) 447 return NULL;
1368 fprintf(stderr, "SSL at this time is unsupported.\n"); 448 if ((options & MHD_USE_IPv4) == 0)
1369 return NULL; 449 return NULL;
1370 } 450 if ( (port == 0) ||
1371 if((options & MHD_USE_IPv6) != 0) { 451 (dh == NULL) )
1372 if((options & MHD_USE_DEBUG) != 0) 452 return NULL;
1373 fprintf(stderr, "IP version 6 is not supported at this time.\n"); 453 socket_fd = socket(AF_INET, SOCK_STREAM, 0);
1374 return NULL; 454 if (socket_fd < 0) {
1375 } 455 /* FIXME: log error */
1376 456 return NULL;
1377 if((options & MHD_USE_IPv4) != 0) { 457 }
1378 if((options & MHD_USE_DEBUG) != 0) 458 memset(&servaddr,
1379 fprintf(stderr, "Enter MHD_start_daemon. Starting Daemon on port %i\n", port); 459 0,
1380 460 sizeof(struct sockaddr_in));
1381 if(port < 1) { 461 servaddr.sin_family = AF_INET;
1382 if((options & MHD_USE_DEBUG) != 0) 462 servaddr.sin_port = htons(port);
1383 fprintf(stderr, "Invalid port: %i!\n", port); 463 if (bind(socket_fd,
1384 return NULL; 464 (struct sockaddr *)&servaddr,
1385 } 465 sizeof(struct sockaddr_in)) < 0) {
1386 466 /* FIXME: log error */
1387 if(dh == NULL) { 467 close(socket_fd);
1388 if((options & MHD_USE_DEBUG) != 0) 468 return NULL;
1389 fprintf(stderr, "A default access handler must be provided\n"); 469 }
1390 return NULL; 470 if (listen(socket_fd, 20) < 0) {
1391 } 471 /* FIXME: log error */
1392 472 return NULL;
1393 retVal = (struct MHD_Daemon *)malloc(sizeof(struct MHD_Daemon)); 473 }
1394 if(retVal == NULL) { 474 opt = fcntl(socket_fd, F_GETFL, 0);
1395 if((options & MHD_USE_DEBUG) != 0) 475 res = fcntl(socket_fd, F_SETFL, opt | O_NONBLOCK);
1396 fprintf(stderr, "Error allocating memory!\n"); 476 if (res < 0) {
1397 return NULL; 477 /* FIXME: log error */
1398 } 478 close(socket_fd);
1399 479 return NULL;
1400 retVal->options = options; 480 }
1401 retVal->port = port; 481
1402 retVal->apc = apc; 482 retVal = malloc(sizeof(struct MHD_Daemon));
1403 retVal->apc_cls = apc_cls; 483 memset(retVal,
1404 retVal->dh = dh; 484 0,
1405 retVal->dh_cls = dh_cls; 485 sizeof(struct MHD_Daemon));
1406 retVal->shutdown = 0; 486 retVal->options = options;
1407 retVal->pid = (pthread_t)-1; 487 retVal->port = port;
1408 488 retVal->apc = apc;
1409 retVal->firstFreeHandler = 0; 489 retVal->apc_cls = apc_cls;
1410 for(i = 0; i < MHD_MAX_HANDLERS; i++) { 490 retVal->dh = dh;
1411 retVal->handlers[i] = NULL; 491 retVal->dh_cls = dh_cls;
1412 } 492 retVal->socket_fd = socket_fd;
1413 493 if ( ( (0 != (options & MHD_USE_THREAD_PER_CONNECTION)) ||
1414 FD_ZERO(&retVal->read_fd_set); 494 (0 != (options & MHD_USE_SELECT_INTERNALLY)) ) &&
1415 FD_ZERO(&retVal->write_fd_set); 495 (0 != pthread_create(&daemon->pid,
1416 FD_ZERO(&retVal->except_fd_set); 496 NULL,
1417 497 &MHD_select_thread,
1418 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) { 498 daemon)) ) {
1419 retVal->connections[i] = NULL; 499 /* FIXME: log error */
1420 } 500 free(retVal);
1421 501 close(socket_fd);
1422 socket_fd = socket(AF_INET, SOCK_STREAM, 0); 502 return NULL;
1423 if(socket_fd < 0) { 503 }
1424 if((options & MHD_USE_DEBUG) != 0) 504 return retVal;
1425 perror("Error creating socket!");
1426 return NULL;
1427 }
1428
1429 memset((void *)&servaddr, 0, (size_t)sizeof(servaddr));
1430
1431 if (gethostname(hostid,32) < 0){
1432 if((options & MHD_USE_DEBUG) != 0)
1433 perror("server_tcp:gethostname");
1434 return NULL;
1435 }
1436
1437 if ((hostptr = gethostbyname(hostid)) == NULL){
1438 if((options & MHD_USE_DEBUG) != 0)
1439 fprintf(stderr, "invalid host name, %s\n",hostid);
1440 return NULL;
1441 }
1442
1443 servaddr.sin_family = AF_INET;
1444 memcpy((void *)&(servaddr.sin_addr), (void *)(hostptr->h_addr), hostptr->h_length);
1445 servaddr.sin_port = htons(port);
1446
1447
1448 if (bind(socket_fd, (struct sockaddr *)&servaddr, (socklen_t)sizeof(servaddr)) < 0) {
1449 if((options & MHD_USE_DEBUG) != 0)
1450 perror("server:bind");
1451 return NULL;
1452 }
1453
1454 if(listen(socket_fd, 20) < 0) {
1455 if((options & MHD_USE_DEBUG) != 0)
1456 perror("server:bind");
1457 return NULL;
1458 }
1459
1460 retVal->socket_fd = socket_fd;
1461 retVal->max_fd = socket_fd;
1462 FD_SET(socket_fd, &retVal->read_fd_set);
1463
1464 opt = fcntl(socket_fd, F_GETFL, 0);
1465 res = fcntl(socket_fd, F_SETFL, opt | O_NONBLOCK);
1466 if(res < 0) {
1467 if((options & MHD_USE_DEBUG) != 0)
1468 perror("Error disabling block on socket!");
1469 return NULL;
1470 }
1471
1472 return retVal;
1473 }
1474
1475 if((options & MHD_USE_DEBUG) != 0)
1476 fprintf(stderr, "No options given to start_daemon!\n");
1477
1478 return NULL;
1479
1480} 505}
1481 506
1482/** 507/**
@@ -1484,76 +509,26 @@ MHD_start_daemon(unsigned int options,
1484 */ 509 */
1485void 510void
1486MHD_stop_daemon(struct MHD_Daemon * daemon) { 511MHD_stop_daemon(struct MHD_Daemon * daemon) {
1487 int i, j; 512 void * unused;
1488 513
1489 if(daemon == NULL) { 514 if (daemon == NULL)
1490 return; 515 return;
1491 } 516 daemon->shutdown = 1;
1492 517 close(daemon->socket_fd);
1493 if((daemon->options & MHD_USE_DEBUG) != 0) 518 daemon->socket_fd = -1;
1494 fprintf(stderr, "Enter MHD_stop_daemon. Stopping daemon on port %i\n", daemon->port); 519 if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) ||
1495 520 (0 != (daemon->options & MHD_USE_SELECT_INTERNALLY)) )
1496 daemon->shutdown = 1; 521 pthread_join(daemon->pid, &unused);
1497 522
1498 if(daemon->pid != (pthread_t)-1) { 523 while (daemon->connections != NULL) {
1499 pthread_join(daemon->pid, NULL); 524 if (-1 != daemon->connections->socket_fd) {
1500 } 525 close(daemon->connections->socket_fd);
1501 526 daemon->connections->socket_fd = -1;
1502 for(i = 0; i < MHD_MAX_CONNECTIONS; i++) { 527 }
1503 if(daemon->connections[i] != NULL) { 528 pthread_join(daemon->connections->pid, &unused);
1504 if(daemon->connections[i]->pid != (pthread_t)-1) { 529
1505 pthread_join(daemon->connections[i]->pid, NULL); 530 MHD_cleanup_sessions(daemon);
1506 } 531 }
1507 532 free(daemon);
1508 for(j = 0; j < MHD_MAX_RESPONSE; j++) {
1509 if(daemon->connections[i]->currentResponses[j] != NULL) {
1510 MHD_destroy_response(daemon->connections[i]->currentResponses[j]);
1511 }
1512 }
1513 MHD_destroy_session(daemon->connections[i]);
1514 }
1515 }
1516
1517 for(i = 0; i < MHD_MAX_HANDLERS; i++) {
1518 if(daemon->handlers[i] != NULL) {
1519 free(daemon->handlers[i]->uri_prefix);
1520 free(daemon->handlers[i]);
1521 }
1522 }
1523
1524 close(daemon->socket_fd);
1525
1526 free(daemon);
1527}
1528
1529
1530/**
1531 * Unregister an access handler for the URIs beginning with
1532 * uri_prefix.
1533 *
1534 * @param uri_prefix
1535 * @return MHD_NO if a handler for this exact prefix
1536 * is not known for this daemon
1537 */
1538int
1539MHD_unregister_handler(struct MHD_Daemon * daemon,
1540 const char * uri_prefix,
1541 MHD_AccessHandlerCallback dh,
1542 void * dh_cls) {
1543 int i;
1544
1545 for(i = 0; i < MHD_MAX_HANDLERS; i++) {
1546 if(daemon->handlers[i] != NULL) {
1547 if(strncmp(daemon->handlers[i]->uri_prefix, uri_prefix, strlen(daemon->handlers[i]->uri_prefix)) == 0) {
1548 if(daemon->handlers[i]->dh == dh && daemon->handlers[i]->dh_cls == dh_cls) {
1549 free(daemon->handlers[i]->uri_prefix);
1550 free(daemon->handlers[i]);
1551 return MHD_YES;
1552 }
1553 }
1554 }
1555 }
1556
1557 return MHD_NO;
1558} 533}
1559 534