diff options
Diffstat (limited to 'src/hostlist/hostlist-server.c')
-rw-r--r-- | src/hostlist/hostlist-server.c | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/hostlist/hostlist-server.c b/src/hostlist/hostlist-server.c new file mode 100644 index 000000000..a2bbe2dec --- /dev/null +++ b/src/hostlist/hostlist-server.c | |||
@@ -0,0 +1,232 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2008 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 2, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file hostlist/hostlist-server.c | ||
23 | * @author Christian Grothoff | ||
24 | * @brief application to provide an integrated hostlist HTTP server | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include <microhttpd.h> | ||
29 | #include "hostlist-server.h" | ||
30 | #include "gnunet_hello_lib.h" | ||
31 | #include "gnunet_peerinfo_service.h" | ||
32 | |||
33 | /** | ||
34 | * How often should we recalculate our response to hostlist requests? | ||
35 | */ | ||
36 | #define RESPONSE_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
37 | |||
38 | /** | ||
39 | * Handle to the HTTP server as provided by libmicrohttpd. | ||
40 | */ | ||
41 | static struct MHD_Daemon *daemon_handle; | ||
42 | |||
43 | /** | ||
44 | * Our configuration. | ||
45 | */ | ||
46 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
47 | |||
48 | /** | ||
49 | * Our scheduler. | ||
50 | */ | ||
51 | static struct GNUNET_SCHEDULER_Handle *sched; | ||
52 | |||
53 | /** | ||
54 | * Our canonical response. | ||
55 | */ | ||
56 | static struct MHD_Response *response; | ||
57 | |||
58 | /** | ||
59 | * Context for host processor. | ||
60 | */ | ||
61 | struct HostSet | ||
62 | { | ||
63 | size_t size; | ||
64 | |||
65 | char *data; | ||
66 | }; | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Task that will produce a new response object. | ||
71 | */ | ||
72 | static void | ||
73 | update_response (void *cls, | ||
74 | const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Function that assembles our response. | ||
79 | */ | ||
80 | static void | ||
81 | finish_response (struct HostSet *results) | ||
82 | { | ||
83 | if (response != NULL) | ||
84 | MHD_destroy_response (response); | ||
85 | response = MHD_create_response_from_data (results->size, | ||
86 | results->data, MHD_YES, MHD_NO); | ||
87 | GNUNET_free (results); | ||
88 | /* schedule next update of the response */ | ||
89 | GNUNET_SCHEDULER_add_delayed (sched, | ||
90 | GNUNET_NO, | ||
91 | GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
92 | GNUNET_SCHEDULER_NO_PREREQUISITE_TASK, | ||
93 | RESPONSE_UPDATE_FREQUENCY, | ||
94 | &update_response, | ||
95 | NULL); | ||
96 | } | ||
97 | |||
98 | |||
99 | /** | ||
100 | * Callback that processes each of the known HELLOs for the | ||
101 | * hostlist response construction. | ||
102 | */ | ||
103 | static void | ||
104 | host_processor (void *cls, | ||
105 | const struct GNUNET_PeerIdentity * peer, | ||
106 | const struct GNUNET_HELLO_Message *hello, | ||
107 | uint32_t trust) | ||
108 | { | ||
109 | struct HostSet *results = cls; | ||
110 | size_t old; | ||
111 | size_t s; | ||
112 | |||
113 | if (peer == NULL) | ||
114 | finish_response (results); | ||
115 | old = results->size; | ||
116 | s = GNUNET_HELLO_size(hello); | ||
117 | if (old + s >= GNUNET_MAX_MALLOC_CHECKED) | ||
118 | return; /* too large, skip! */ | ||
119 | GNUNET_array_grow (results->data, | ||
120 | results->size, | ||
121 | old + s); | ||
122 | memcpy (&results->data[old], hello, s); | ||
123 | } | ||
124 | |||
125 | |||
126 | /** | ||
127 | * Task that will produce a new response object. | ||
128 | */ | ||
129 | static void | ||
130 | update_response (void *cls, | ||
131 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
132 | { | ||
133 | struct HostSet *results; | ||
134 | |||
135 | results = GNUNET_malloc(sizeof(struct HostSet)); | ||
136 | GNUNET_PEERINFO_for_all (cfg, sched, | ||
137 | NULL, | ||
138 | 0, | ||
139 | GNUNET_TIME_UNIT_MINUTES, | ||
140 | &host_processor, | ||
141 | results); | ||
142 | } | ||
143 | |||
144 | |||
145 | |||
146 | static int | ||
147 | accept_policy_callback (void *cls, | ||
148 | const struct sockaddr *addr, socklen_t addrlen) | ||
149 | { | ||
150 | return MHD_YES; /* accept all */ | ||
151 | } | ||
152 | |||
153 | |||
154 | static int | ||
155 | access_handler_callback (void *cls, | ||
156 | struct MHD_Connection *connection, | ||
157 | const char *url, | ||
158 | const char *method, | ||
159 | const char *version, | ||
160 | const char *upload_data, | ||
161 | unsigned int *upload_data_size, void **con_cls) | ||
162 | { | ||
163 | static int dummy; | ||
164 | |||
165 | if (0 != strcmp (method, MHD_HTTP_METHOD_GET)) | ||
166 | return MHD_NO; | ||
167 | if (NULL == *con_cls) | ||
168 | { | ||
169 | (*con_cls) = &dummy; | ||
170 | return MHD_YES; /* send 100 continue */ | ||
171 | } | ||
172 | if (*upload_data_size != 0) | ||
173 | return MHD_NO; /* do not support upload data */ | ||
174 | if (response == NULL) | ||
175 | return MHD_NO; /* internal error, no response yet */ | ||
176 | return MHD_queue_response (connection, MHD_HTTP_OK, response); | ||
177 | } | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Start server offering our hostlist. | ||
182 | * | ||
183 | * @return GNUNET_OK on success | ||
184 | */ | ||
185 | int | ||
186 | GNUNET_HOSTLIST_server_start (struct GNUNET_CONFIGURATION_Handle *c, | ||
187 | struct GNUNET_SCHEDULER_Handle *s, | ||
188 | struct GNUNET_STATISTICS_Handle *st) | ||
189 | { | ||
190 | unsigned long long port; | ||
191 | |||
192 | sched = s; | ||
193 | cfg = c; | ||
194 | if (-1 == GNUNET_CONFIGURATION_get_value_number (cfg, | ||
195 | "HOSTLIST", | ||
196 | "PORT", | ||
197 | &port)) | ||
198 | return GNUNET_SYSERR; | ||
199 | /* FIXME: must use *external* SELECT mode since our | ||
200 | code is NOT thread safe! Integrate with scheduler! */ | ||
201 | daemon_handle = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_IPv6, | ||
202 | (unsigned short) port, | ||
203 | &accept_policy_callback, | ||
204 | NULL, | ||
205 | &access_handler_callback, | ||
206 | NULL, | ||
207 | MHD_OPTION_CONNECTION_LIMIT, 16, | ||
208 | MHD_OPTION_PER_IP_CONNECTION_LIMIT, 1, | ||
209 | MHD_OPTION_CONNECTION_TIMEOUT, 16, | ||
210 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
211 | 16 * 1024, MHD_OPTION_END); | ||
212 | if (daemon_handle == NULL) | ||
213 | { | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
215 | _("Could not start hostlist HTTP server on port %u\n"), | ||
216 | (unsigned short) port); | ||
217 | return GNUNET_SYSERR; | ||
218 | } | ||
219 | return GNUNET_OK; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Stop server offering our hostlist. | ||
224 | */ | ||
225 | void | ||
226 | GNUNET_HOSTLIST_server_stop () | ||
227 | { | ||
228 | MHD_stop_daemon (daemon_handle); | ||
229 | daemon_handle = NULL; | ||
230 | } | ||
231 | |||
232 | /* end of hostlist-server.c */ | ||