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