aboutsummaryrefslogtreecommitdiff
path: root/src/rest/gnunet-rest-server.c
diff options
context:
space:
mode:
authort3sserakt <t3ss@posteo.de>2020-08-06 16:25:51 +0200
committert3sserakt <t3ss@posteo.de>2020-08-06 16:25:51 +0200
commit38193fe48a572e475b4f84717ff5b3edbcaf2d2a (patch)
treed6deeb56d81f75ab411d88a03b865f7da7eaaed4 /src/rest/gnunet-rest-server.c
parent33954ae13d4d26cefa45ac86f5e2184b6abd724f (diff)
parent6ab14a20690a499ad32e3f2ad448d64d4e6b65fc (diff)
downloadgnunet-38193fe48a572e475b4f84717ff5b3edbcaf2d2a.tar.gz
gnunet-38193fe48a572e475b4f84717ff5b3edbcaf2d2a.zip
Merge branch 'master' of ssh://gnunet.org/gnunet
Diffstat (limited to 'src/rest/gnunet-rest-server.c')
-rw-r--r--src/rest/gnunet-rest-server.c379
1 files changed, 291 insertions, 88 deletions
diff --git a/src/rest/gnunet-rest-server.c b/src/rest/gnunet-rest-server.c
index 875509536..436b5b205 100644
--- a/src/rest/gnunet-rest-server.c
+++ b/src/rest/gnunet-rest-server.c
@@ -115,11 +115,6 @@ static struct MHD_Response *failure_response;
115static const struct GNUNET_CONFIGURATION_Handle *cfg; 115static const struct GNUNET_CONFIGURATION_Handle *cfg;
116 116
117/** 117/**
118 * Map of loaded plugins.
119 */
120static struct GNUNET_CONTAINER_MultiHashMap *plugin_map;
121
122/**
123 * Echo request Origin in CORS 118 * Echo request Origin in CORS
124 */ 119 */
125static int echo_origin; 120static int echo_origin;
@@ -140,6 +135,38 @@ static char *allow_headers;
140static char *allow_credentials; 135static char *allow_credentials;
141 136
142/** 137/**
138 * Plugin list head
139 */
140static struct PluginListEntry *plugins_head;
141
142/**
143 * Plugin list tail
144 */
145static struct PluginListEntry *plugins_tail;
146
147/**
148 * A plugin list entry
149 */
150struct PluginListEntry
151{
152 /* DLL */
153 struct PluginListEntry *next;
154
155 /* DLL */
156 struct PluginListEntry *prev;
157
158 /**
159 * libname (to cleanup)
160 */
161 char *libname;
162
163 /**
164 * The plugin
165 */
166 struct GNUNET_REST_Plugin *plugin;
167};
168
169/**
143 * MHD Connection handle 170 * MHD Connection handle
144 */ 171 */
145struct MhdConnectionHandle 172struct MhdConnectionHandle
@@ -148,8 +175,6 @@ struct MhdConnectionHandle
148 175
149 struct MHD_Response *response; 176 struct MHD_Response *response;
150 177
151 struct GNUNET_REST_Plugin *plugin;
152
153 struct GNUNET_REST_RequestHandle *data_handle; 178 struct GNUNET_REST_RequestHandle *data_handle;
154 179
155 struct MHD_PostProcessor *pp; 180 struct MHD_PostProcessor *pp;
@@ -159,6 +184,42 @@ struct MhdConnectionHandle
159 int state; 184 int state;
160}; 185};
161 186
187/**
188 * Accepted requests
189 */
190struct AcceptedRequest
191{
192 /**
193 * DLL
194 */
195 struct AcceptedRequest *next;
196
197 /**
198 * DLL
199 */
200 struct AcceptedRequest *prev;
201
202 /**
203 * Socket
204 */
205 struct GNUNET_NETWORK_Handle *sock;
206
207 /**
208 * Connection
209 */
210 struct MhdConnectionHandle *con_handle;
211};
212
213/**
214 * AcceptedRequest list head
215 */
216static struct AcceptedRequest *req_list_head;
217
218/**
219 * AcceptedRequest list tail
220 */
221static struct AcceptedRequest *req_list_tail;
222
162/* ************************* Global helpers ********************* */ 223/* ************************* Global helpers ********************* */
163 224
164 225
@@ -213,7 +274,6 @@ cleanup_url_map (void *cls, const struct GNUNET_HashCode *key, void *value)
213 return GNUNET_YES; 274 return GNUNET_YES;
214} 275}
215 276
216
217static void 277static void
218cleanup_handle (struct MhdConnectionHandle *handle) 278cleanup_handle (struct MhdConnectionHandle *handle)
219{ 279{
@@ -243,6 +303,19 @@ cleanup_handle (struct MhdConnectionHandle *handle)
243 GNUNET_free (handle); 303 GNUNET_free (handle);
244} 304}
245 305
306static void
307cleanup_ar (struct AcceptedRequest *ar)
308{
309 if (NULL != ar->con_handle)
310 {
311 cleanup_handle (ar->con_handle);
312 }
313 GNUNET_NETWORK_socket_free_memory_only_ (ar->sock);
314 GNUNET_CONTAINER_DLL_remove (req_list_head,
315 req_list_tail,
316 ar);
317 GNUNET_free (ar);
318}
246 319
247static int 320static int
248header_iterator (void *cls, 321header_iterator (void *cls,
@@ -321,19 +394,24 @@ post_data_iter (void *cls,
321 return MHD_YES; 394 return MHD_YES;
322 395
323 GNUNET_CRYPTO_hash (key, strlen (key), &hkey); 396 GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
324 GNUNET_asprintf (&val, "%s", data); 397 val = GNUNET_CONTAINER_multihashmap_get (handle->url_param_map,
325 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put ( 398 &hkey);
326 handle->url_param_map, 399 if (NULL == val)
327 &hkey,
328 val,
329 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
330 { 400 {
331 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 401 val = GNUNET_malloc (65536);
332 "Could not load add url param '%s'=%s\n", 402 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (
333 key, 403 handle->url_param_map,
334 data); 404 &hkey,
335 GNUNET_free (val); 405 val,
406 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
407 {
408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
409 "Could not add url param '%s'\n",
410 key);
411 GNUNET_free (val);
412 }
336 } 413 }
414 memcpy (val + off, data, size);
337 return MHD_YES; 415 return MHD_YES;
338} 416}
339 417
@@ -373,41 +451,30 @@ create_response (void *cls,
373 size_t *upload_data_size, 451 size_t *upload_data_size,
374 void **con_cls) 452 void **con_cls)
375{ 453{
376 char *plugin_name;
377 char *origin; 454 char *origin;
455 struct AcceptedRequest *ar;
378 struct GNUNET_HashCode key; 456 struct GNUNET_HashCode key;
379 struct MhdConnectionHandle *con_handle; 457 struct MhdConnectionHandle *con_handle;
380 struct GNUNET_REST_RequestHandle *rest_conndata_handle; 458 struct GNUNET_REST_RequestHandle *rest_conndata_handle;
459 struct PluginListEntry *ple;
381 460
382 con_handle = *con_cls; 461 ar = *con_cls;
462 if (NULL == ar)
463 {
464 GNUNET_break (0);
465 return MHD_NO;
466 }
383 467
384 if (NULL == *con_cls) 468 if (NULL == ar->con_handle)
385 { 469 {
386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url); 470 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
387 char tmp_url[strlen (url) + 1];
388 strcpy (tmp_url, url);
389 con_handle = GNUNET_new (struct MhdConnectionHandle); 471 con_handle = GNUNET_new (struct MhdConnectionHandle);
390 con_handle->con = con; 472 con_handle->con = con;
391 con_handle->state = GN_REST_STATE_INIT; 473 con_handle->state = GN_REST_STATE_INIT;
392 *con_cls = con_handle; 474 ar->con_handle = con_handle;
393
394 plugin_name = strtok (tmp_url, "/");
395
396 if (NULL != plugin_name)
397 {
398 GNUNET_CRYPTO_hash (plugin_name, strlen (plugin_name), &key);
399
400 con_handle->plugin = GNUNET_CONTAINER_multihashmap_get (plugin_map, &key);
401 }
402 if (NULL == con_handle->plugin)
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing response with MHD\n");
405 GNUNET_free (con_handle);
406 return MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
407 }
408
409 return MHD_YES; 475 return MHD_YES;
410 } 476 }
477 con_handle = ar->con_handle;
411 if (GN_REST_STATE_INIT == con_handle->state) 478 if (GN_REST_STATE_INIT == con_handle->state)
412 { 479 {
413 rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle); 480 rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
@@ -428,6 +495,7 @@ create_response (void *cls,
428 MHD_HEADER_KIND, 495 MHD_HEADER_KIND,
429 (MHD_KeyValueIterator) & header_iterator, 496 (MHD_KeyValueIterator) & header_iterator,
430 rest_conndata_handle); 497 rest_conndata_handle);
498
431 con_handle->pp = MHD_create_post_processor (con, 499 con_handle->pp = MHD_create_post_processor (con,
432 65536, 500 65536,
433 &post_data_iter, 501 &post_data_iter,
@@ -439,9 +507,18 @@ create_response (void *cls,
439 MHD_destroy_post_processor (con_handle->pp); 507 MHD_destroy_post_processor (con_handle->pp);
440 508
441 con_handle->state = GN_REST_STATE_PROCESSING; 509 con_handle->state = GN_REST_STATE_PROCESSING;
442 con_handle->plugin->process_request (rest_conndata_handle, 510 for (ple = plugins_head; NULL != ple; ple = ple->next)
443 &plugin_callback, 511 {
444 con_handle); 512 if (GNUNET_YES == ple->plugin->process_request (rest_conndata_handle,
513 &plugin_callback,
514 con_handle))
515 break; /* Request handled */
516 }
517 if (NULL == ple)
518 {
519 /** Request not handled **/
520 MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
521 }
445 *upload_data_size = 0; 522 *upload_data_size = 0;
446 run_mhd_now (); 523 run_mhd_now ();
447 return MHD_YES; 524 return MHD_YES;
@@ -513,7 +590,7 @@ create_response (void *cls,
513 MHD_RESULT ret = MHD_queue_response (con, 590 MHD_RESULT ret = MHD_queue_response (con,
514 con_handle->status, 591 con_handle->status,
515 con_handle->response); 592 con_handle->response);
516 cleanup_handle (con_handle); 593 //cleanup_handle (con_handle);
517 return ret; 594 return ret;
518 } 595 }
519} 596}
@@ -521,27 +598,6 @@ create_response (void *cls,
521 598
522/* ******************** MHD HTTP setup and event loop ******************** */ 599/* ******************** MHD HTTP setup and event loop ******************** */
523 600
524/**
525 * Function called when MHD decides that we are done with a connection.
526 *
527 * @param cls NULL
528 * @param connection connection handle
529 * @param con_cls value as set by the last call to
530 * the MHD_AccessHandlerCallback, should be our handle
531 * @param toe reason for request termination (ignored)
532 */
533static void
534mhd_completed_cb (void *cls,
535 struct MHD_Connection *connection,
536 void **con_cls,
537 enum MHD_RequestTerminationCode toe)
538{
539 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
541 "MHD encountered error handling request: %d\n",
542 toe);
543}
544
545 601
546/** 602/**
547 * Kill the MHD daemon. 603 * Kill the MHD daemon.
@@ -649,6 +705,135 @@ schedule_httpd ()
649 GNUNET_NETWORK_fdset_destroy (wws); 705 GNUNET_NETWORK_fdset_destroy (wws);
650} 706}
651 707
708/**
709 * Function called when MHD first processes an incoming connection.
710 * Gives us the respective URI information.
711 *
712 * We use this to associate the `struct MHD_Connection` with our
713 * internal `struct AcceptedRequest` data structure (by checking
714 * for matching sockets).
715 *
716 * @param cls the HTTP server handle (a `struct MhdHttpList`)
717 * @param url the URL that is being requested
718 * @param connection MHD connection object for the request
719 * @return the `struct Socks5Request` that this @a connection is for
720 */
721static void *
722mhd_log_callback (void *cls,
723 const char *url,
724 struct MHD_Connection *connection)
725{
726 struct AcceptedRequest *ar;
727 const union MHD_ConnectionInfo *ci;
728
729 ci = MHD_get_connection_info (connection,
730 MHD_CONNECTION_INFO_SOCKET_CONTEXT);
731 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
732 if (NULL == ci)
733 {
734 GNUNET_break (0);
735 return NULL;
736 }
737 ar = ci->socket_context;
738 return ar;
739}
740
741
742
743/**
744 * Function called when MHD decides that we are done with a connection.
745 *
746 * @param cls NULL
747 * @param connection connection handle
748 * @param con_cls value as set by the last call to
749 * the MHD_AccessHandlerCallback, should be our handle
750 * @param toe reason for request termination (ignored)
751 */
752static void
753mhd_completed_cb (void *cls,
754 struct MHD_Connection *connection,
755 void **con_cls,
756 enum MHD_RequestTerminationCode toe)
757{
758 struct AcceptedRequest *ar = *con_cls;
759 if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
760 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
761 "MHD encountered error handling request: %d\n",
762 toe);
763 if (NULL == ar)
764 return;
765 if (NULL != ar->con_handle)
766 {
767 cleanup_handle (ar->con_handle);
768 ar->con_handle = NULL;
769 }
770 schedule_httpd ();
771 *con_cls = NULL;
772}
773
774/**
775 * Function called when MHD connection is opened or closed.
776 *
777 * @param cls NULL
778 * @param connection connection handle
779 * @param con_cls value as set by the last call to
780 * the MHD_AccessHandlerCallback, should be our `struct Socks5Request *`
781 * @param toe connection notification type
782 */
783static void
784mhd_connection_cb (void *cls,
785 struct MHD_Connection *connection,
786 void **con_cls,
787 enum MHD_ConnectionNotificationCode cnc)
788{
789 struct AcceptedRequest *ar;
790 const union MHD_ConnectionInfo *ci;
791 int sock;
792
793 switch (cnc)
794 {
795 case MHD_CONNECTION_NOTIFY_STARTED:
796 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
797 ci = MHD_get_connection_info (connection,
798 MHD_CONNECTION_INFO_CONNECTION_FD);
799 if (NULL == ci)
800 {
801 GNUNET_break (0);
802 return;
803 }
804 sock = ci->connect_fd;
805 for (ar = req_list_head; NULL != ar; ar = ar->next)
806 {
807 if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
808 {
809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 "Context set...\n");
811 *con_cls = ar;
812 break;
813 }
814 }
815 break;
816
817 case MHD_CONNECTION_NOTIFY_CLOSED:
818 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
819 "Connection closed... cleaning up\n");
820 ar = *con_cls;
821 if (NULL == ar)
822 {
823 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
824 "Connection stale!\n");
825 return;
826 }
827 cleanup_ar (ar);
828 *con_cls = NULL;
829 break;
830
831 default:
832 GNUNET_break (0);
833 }
834}
835
836
652 837
653/** 838/**
654 * Task run whenever HTTP server operations are pending. 839 * Task run whenever HTTP server operations are pending.
@@ -674,7 +859,7 @@ static void
674do_accept (void *cls) 859do_accept (void *cls)
675{ 860{
676 struct GNUNET_NETWORK_Handle *lsock = cls; 861 struct GNUNET_NETWORK_Handle *lsock = cls;
677 struct GNUNET_NETWORK_Handle *s; 862 struct AcceptedRequest *ar;
678 int fd; 863 int fd;
679 const struct sockaddr *addr; 864 const struct sockaddr *addr;
680 socklen_t len; 865 socklen_t len;
@@ -696,24 +881,30 @@ do_accept (void *cls)
696 } 881 }
697 else 882 else
698 GNUNET_assert (0); 883 GNUNET_assert (0);
699 s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL); 884 ar = GNUNET_new (struct AcceptedRequest);
700 if (NULL == s) 885 ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
886 if (NULL == ar->sock)
701 { 887 {
888 GNUNET_free (ar);
702 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept"); 889 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
703 return; 890 return;
704 } 891 }
705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
706 "Got an inbound connection, waiting for data\n"); 893 "Got an inbound connection, waiting for data\n");
707 fd = GNUNET_NETWORK_get_fd (s); 894 fd = GNUNET_NETWORK_get_fd (ar->sock);
708 addr = GNUNET_NETWORK_get_addr (s); 895 addr = GNUNET_NETWORK_get_addr (ar->sock);
709 len = GNUNET_NETWORK_get_addrlen (s); 896 len = GNUNET_NETWORK_get_addrlen (ar->sock);
897 GNUNET_CONTAINER_DLL_insert (req_list_head,
898 req_list_tail,
899 ar);
710 if (MHD_YES != MHD_add_connection (httpd, fd, addr, len)) 900 if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
711 { 901 {
902 GNUNET_NETWORK_socket_close (ar->sock);
903 GNUNET_free (ar);
712 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 904 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
713 _ ("Failed to pass client to MHD\n")); 905 _ ("Failed to pass client to MHD\n"));
714 return; 906 return;
715 } 907 }
716 GNUNET_free (s);
717 schedule_httpd (); 908 schedule_httpd ();
718} 909}
719 910
@@ -726,6 +917,18 @@ do_accept (void *cls)
726static void 917static void
727do_shutdown (void *cls) 918do_shutdown (void *cls)
728{ 919{
920 struct PluginListEntry *ple;
921
922 while (NULL != plugins_head)
923 {
924 ple = plugins_head;
925 GNUNET_CONTAINER_DLL_remove (plugins_head,
926 plugins_tail,
927 ple);
928 GNUNET_PLUGIN_unload (ple->libname, NULL);
929 GNUNET_free (ple->libname);
930 GNUNET_free (ple);
931 }
729 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n"); 932 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
730 kill_httpd (); 933 kill_httpd ();
731 GNUNET_free (allow_credentials); 934 GNUNET_free (allow_credentials);
@@ -814,7 +1017,7 @@ static void
814load_plugin (void *cls, const char *libname, void *lib_ret) 1017load_plugin (void *cls, const char *libname, void *lib_ret)
815{ 1018{
816 struct GNUNET_REST_Plugin *plugin = lib_ret; 1019 struct GNUNET_REST_Plugin *plugin = lib_ret;
817 struct GNUNET_HashCode key; 1020 struct PluginListEntry *ple;
818 1021
819 if (NULL == lib_ret) 1022 if (NULL == lib_ret)
820 { 1023 {
@@ -825,18 +1028,12 @@ load_plugin (void *cls, const char *libname, void *lib_ret)
825 } 1028 }
826 GNUNET_assert (1 < strlen (plugin->name)); 1029 GNUNET_assert (1 < strlen (plugin->name));
827 GNUNET_assert ('/' == *plugin->name); 1030 GNUNET_assert ('/' == *plugin->name);
828 GNUNET_CRYPTO_hash (plugin->name + 1, strlen (plugin->name + 1), &key); 1031 ple = GNUNET_new (struct PluginListEntry);
829 if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put ( 1032 ple->libname = GNUNET_strdup (libname);
830 plugin_map, 1033 ple->plugin = plugin;
831 &key, 1034 GNUNET_CONTAINER_DLL_insert (plugins_head,
832 plugin, 1035 plugins_tail,
833 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) 1036 ple);
834 {
835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
836 "Could not load add plugin `%s'\n",
837 libname);
838 return;
839 }
840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", libname); 1037 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", libname);
841} 1038}
842 1039
@@ -858,8 +1055,8 @@ run (void *cls,
858 char *addr_str; 1055 char *addr_str;
859 1056
860 cfg = c; 1057 cfg = c;
861 plugin_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); 1058 plugins_head = NULL;
862 1059 plugins_tail = NULL;
863 /* Get port to bind to */ 1060 /* Get port to bind to */
864 if (GNUNET_OK != 1061 if (GNUNET_OK !=
865 GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port)) 1062 GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
@@ -1004,6 +1201,12 @@ run (void *cls,
1004 NULL, 1201 NULL,
1005 MHD_OPTION_CONNECTION_TIMEOUT, 1202 MHD_OPTION_CONNECTION_TIMEOUT,
1006 (unsigned int) 16, 1203 (unsigned int) 16,
1204 MHD_OPTION_NOTIFY_CONNECTION,
1205 &mhd_connection_cb,
1206 NULL,
1207 MHD_OPTION_URI_LOG_CALLBACK,
1208 mhd_log_callback,
1209 NULL,
1007 MHD_OPTION_NOTIFY_COMPLETED, 1210 MHD_OPTION_NOTIFY_COMPLETED,
1008 &mhd_completed_cb, 1211 &mhd_completed_cb,
1009 NULL, 1212 NULL,