diff options
-rw-r--r-- | src/regex/gnunet-service-regex.c | 321 |
1 files changed, 163 insertions, 158 deletions
diff --git a/src/regex/gnunet-service-regex.c b/src/regex/gnunet-service-regex.c index 294670be6..e763bf08d 100644 --- a/src/regex/gnunet-service-regex.c +++ b/src/regex/gnunet-service-regex.c | |||
@@ -37,19 +37,14 @@ struct ClientEntry | |||
37 | { | 37 | { |
38 | 38 | ||
39 | /** | 39 | /** |
40 | * Kept in DLL. | 40 | * Queue for transmissions to @e client. |
41 | */ | 41 | */ |
42 | struct ClientEntry *next; | 42 | struct GNUNET_MQ_Handle *mq; |
43 | |||
44 | /** | ||
45 | * Kept in DLL. | ||
46 | */ | ||
47 | struct ClientEntry *prev; | ||
48 | 43 | ||
49 | /** | 44 | /** |
50 | * Handle identifying the client. | 45 | * Handle identifying the client. |
51 | */ | 46 | */ |
52 | struct GNUNET_SERVER_Client *client; | 47 | struct GNUNET_SERVICE_Client *client; |
53 | 48 | ||
54 | /** | 49 | /** |
55 | * Search handle (if this client is searching). | 50 | * Search handle (if this client is searching). |
@@ -69,7 +64,7 @@ struct ClientEntry | |||
69 | /** | 64 | /** |
70 | * Task for re-announcing. | 65 | * Task for re-announcing. |
71 | */ | 66 | */ |
72 | struct GNUNET_SCHEDULER_Task * refresh_task; | 67 | struct GNUNET_SCHEDULER_Task *refresh_task; |
73 | 68 | ||
74 | }; | 69 | }; |
75 | 70 | ||
@@ -85,70 +80,12 @@ static struct GNUNET_DHT_Handle *dht; | |||
85 | static struct GNUNET_STATISTICS_Handle *stats; | 80 | static struct GNUNET_STATISTICS_Handle *stats; |
86 | 81 | ||
87 | /** | 82 | /** |
88 | * Head of list of clients. | ||
89 | */ | ||
90 | static struct ClientEntry *client_head; | ||
91 | |||
92 | /** | ||
93 | * End of list of clients. | ||
94 | */ | ||
95 | static struct ClientEntry *client_tail; | ||
96 | |||
97 | /** | ||
98 | * Our notification context, used to send back results to the client. | ||
99 | */ | ||
100 | static struct GNUNET_SERVER_NotificationContext *nc; | ||
101 | |||
102 | /** | ||
103 | * Private key for this peer. | 83 | * Private key for this peer. |
104 | */ | 84 | */ |
105 | static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; | 85 | static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key; |
106 | 86 | ||
107 | 87 | ||
108 | /** | 88 | /** |
109 | * A client disconnected. Remove all of its data structure entries. | ||
110 | * | ||
111 | * @param cls closure, NULL | ||
112 | * @param client identification of the client | ||
113 | */ | ||
114 | static void | ||
115 | handle_client_disconnect (void *cls, | ||
116 | struct GNUNET_SERVER_Client *client) | ||
117 | { | ||
118 | struct ClientEntry *ce; | ||
119 | struct ClientEntry *nx; | ||
120 | |||
121 | nx = client_head; | ||
122 | for (ce = nx; NULL != ce; ce = nx) | ||
123 | { | ||
124 | nx = ce->next; | ||
125 | if (ce->client == client) | ||
126 | { | ||
127 | if (NULL != ce->refresh_task) | ||
128 | { | ||
129 | GNUNET_SCHEDULER_cancel (ce->refresh_task); | ||
130 | ce->refresh_task = NULL; | ||
131 | } | ||
132 | if (NULL != ce->ah) | ||
133 | { | ||
134 | REGEX_INTERNAL_announce_cancel (ce->ah); | ||
135 | ce->ah = NULL; | ||
136 | } | ||
137 | if (NULL != ce->sh) | ||
138 | { | ||
139 | REGEX_INTERNAL_search_cancel (ce->sh); | ||
140 | ce->sh = NULL; | ||
141 | } | ||
142 | GNUNET_CONTAINER_DLL_remove (client_head, | ||
143 | client_tail, | ||
144 | ce); | ||
145 | GNUNET_free (ce); | ||
146 | } | ||
147 | } | ||
148 | } | ||
149 | |||
150 | |||
151 | /** | ||
152 | * Task run during shutdown. | 89 | * Task run during shutdown. |
153 | * | 90 | * |
154 | * @param cls unused | 91 | * @param cls unused |
@@ -156,17 +93,11 @@ handle_client_disconnect (void *cls, | |||
156 | static void | 93 | static void |
157 | cleanup_task (void *cls) | 94 | cleanup_task (void *cls) |
158 | { | 95 | { |
159 | struct ClientEntry *ce; | ||
160 | |||
161 | while (NULL != (ce = client_head)) | ||
162 | handle_client_disconnect (NULL, | ||
163 | ce->client); | ||
164 | GNUNET_DHT_disconnect (dht); | 96 | GNUNET_DHT_disconnect (dht); |
165 | dht = NULL; | 97 | dht = NULL; |
166 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | 98 | GNUNET_STATISTICS_destroy (stats, |
99 | GNUNET_NO); | ||
167 | stats = NULL; | 100 | stats = NULL; |
168 | GNUNET_SERVER_notification_context_destroy (nc); | ||
169 | nc = NULL; | ||
170 | GNUNET_free (my_private_key); | 101 | GNUNET_free (my_private_key); |
171 | my_private_key = NULL; | 102 | my_private_key = NULL; |
172 | } | 103 | } |
@@ -191,35 +122,51 @@ reannounce (void *cls) | |||
191 | 122 | ||
192 | 123 | ||
193 | /** | 124 | /** |
194 | * Handle ANNOUNCE message. | 125 | * Check ANNOUNCE message. |
195 | * | 126 | * |
196 | * @param cls closure | 127 | * @param cls identification of the client |
197 | * @param client identification of the client | 128 | * @param am the actual message |
198 | * @param message the actual message | 129 | * @return #GNUNET_OK if @am is well-formed |
199 | */ | 130 | */ |
200 | static void | 131 | static int |
201 | handle_announce (void *cls, | 132 | check_announce (void *cls, |
202 | struct GNUNET_SERVER_Client *client, | 133 | const struct AnnounceMessage *am) |
203 | const struct GNUNET_MessageHeader *message) | ||
204 | { | 134 | { |
205 | const struct AnnounceMessage *am; | 135 | struct ClientEntry *ce = cls; |
206 | const char *regex; | 136 | const char *regex; |
207 | struct ClientEntry *ce; | ||
208 | uint16_t size; | 137 | uint16_t size; |
209 | 138 | ||
210 | size = ntohs (message->size); | 139 | size = ntohs (am->header.size) - sizeof (*am); |
211 | am = (const struct AnnounceMessage *) message; | ||
212 | regex = (const char *) &am[1]; | 140 | regex = (const char *) &am[1]; |
213 | if ( (size <= sizeof (struct AnnounceMessage)) || | 141 | if ('\0' != regex[size - 1]) |
214 | ('\0' != regex[size - sizeof (struct AnnounceMessage) - 1]) ) | ||
215 | { | 142 | { |
216 | GNUNET_break (0); | 143 | GNUNET_break (0); |
217 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 144 | return GNUNET_SYSERR; |
218 | return; | 145 | } |
146 | if (NULL != ce->ah) | ||
147 | { | ||
148 | /* only one announcement per client allowed */ | ||
149 | GNUNET_break (0); | ||
150 | return GNUNET_SYSERR; | ||
219 | } | 151 | } |
152 | return GNUNET_OK; | ||
153 | } | ||
220 | 154 | ||
221 | ce = GNUNET_new (struct ClientEntry); | 155 | |
222 | ce->client = client; | 156 | /** |
157 | * Handle ANNOUNCE message. | ||
158 | * | ||
159 | * @param cls identification of the client | ||
160 | * @param am the actual message | ||
161 | */ | ||
162 | static void | ||
163 | handle_announce (void *cls, | ||
164 | const struct AnnounceMessage *am) | ||
165 | { | ||
166 | struct ClientEntry *ce = cls; | ||
167 | const char *regex; | ||
168 | |||
169 | regex = (const char *) &am[1]; | ||
223 | ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay); | 170 | ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay); |
224 | ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency, | 171 | ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency, |
225 | &reannounce, | 172 | &reannounce, |
@@ -238,14 +185,11 @@ handle_announce (void *cls, | |||
238 | { | 185 | { |
239 | GNUNET_break (0); | 186 | GNUNET_break (0); |
240 | GNUNET_SCHEDULER_cancel (ce->refresh_task); | 187 | GNUNET_SCHEDULER_cancel (ce->refresh_task); |
241 | GNUNET_free (ce); | 188 | ce->refresh_task = NULL; |
242 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 189 | GNUNET_SERVICE_client_drop (ce->client); |
243 | return; | 190 | return; |
244 | } | 191 | } |
245 | GNUNET_CONTAINER_DLL_insert (client_head, | 192 | GNUNET_SERVICE_client_continue (ce->client); |
246 | client_tail, | ||
247 | ce); | ||
248 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
249 | } | 193 | } |
250 | 194 | ||
251 | 195 | ||
@@ -268,6 +212,7 @@ handle_search_result (void *cls, | |||
268 | unsigned int put_path_length) | 212 | unsigned int put_path_length) |
269 | { | 213 | { |
270 | struct ClientEntry *ce = cls; | 214 | struct ClientEntry *ce = cls; |
215 | struct GNUNET_MQ_Envelope *env; | ||
271 | struct ResultMessage *result; | 216 | struct ResultMessage *result; |
272 | struct GNUNET_PeerIdentity *gp; | 217 | struct GNUNET_PeerIdentity *gp; |
273 | uint16_t size; | 218 | uint16_t size; |
@@ -280,59 +225,73 @@ handle_search_result (void *cls, | |||
280 | GNUNET_break (0); | 225 | GNUNET_break (0); |
281 | return; | 226 | return; |
282 | } | 227 | } |
283 | size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity) + sizeof (struct ResultMessage); | 228 | size = (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); |
284 | result = GNUNET_malloc (size); | 229 | env = GNUNET_MQ_msg_extra (result, |
285 | result->header.size = htons (size); | 230 | size, |
286 | result->header.type = htons (GNUNET_MESSAGE_TYPE_REGEX_RESULT); | 231 | GNUNET_MESSAGE_TYPE_REGEX_RESULT); |
287 | result->get_path_length = htons ((uint16_t) get_path_length); | 232 | result->get_path_length = htons ((uint16_t) get_path_length); |
288 | result->put_path_length = htons ((uint16_t) put_path_length); | 233 | result->put_path_length = htons ((uint16_t) put_path_length); |
289 | result->id = *id; | 234 | result->id = *id; |
290 | gp = &result->id; | 235 | gp = &result->id; |
291 | GNUNET_memcpy (&gp[1], | 236 | GNUNET_memcpy (&gp[1], |
292 | get_path, | 237 | get_path, |
293 | get_path_length * sizeof (struct GNUNET_PeerIdentity)); | 238 | get_path_length * sizeof (struct GNUNET_PeerIdentity)); |
294 | GNUNET_memcpy (&gp[1 + get_path_length], | 239 | GNUNET_memcpy (&gp[1 + get_path_length], |
295 | put_path, | 240 | put_path, |
296 | put_path_length * sizeof (struct GNUNET_PeerIdentity)); | 241 | put_path_length * sizeof (struct GNUNET_PeerIdentity)); |
297 | GNUNET_SERVER_notification_context_unicast (nc, | 242 | GNUNET_MQ_send (ce->mq, |
298 | ce->client, | 243 | env); |
299 | &result->header, GNUNET_NO); | ||
300 | GNUNET_free (result); | ||
301 | } | 244 | } |
302 | 245 | ||
303 | 246 | ||
304 | /** | 247 | /** |
305 | * Handle SEARCH message. | 248 | * Check SEARCH message. |
306 | * | 249 | * |
307 | * @param cls closure | 250 | * @param cls identification of the client |
308 | * @param client identification of the client | ||
309 | * @param message the actual message | 251 | * @param message the actual message |
310 | */ | 252 | */ |
311 | static void | 253 | static int |
312 | handle_search (void *cls, | 254 | check_search (void *cls, |
313 | struct GNUNET_SERVER_Client *client, | 255 | const struct RegexSearchMessage *sm) |
314 | const struct GNUNET_MessageHeader *message) | ||
315 | { | 256 | { |
316 | const struct RegexSearchMessage *sm; | 257 | struct ClientEntry *ce = cls; |
317 | const char *string; | 258 | const char *string; |
318 | struct ClientEntry *ce; | ||
319 | uint16_t size; | 259 | uint16_t size; |
320 | 260 | ||
321 | size = ntohs (message->size); | 261 | size = ntohs (sm->header.size) - sizeof (*sm); |
322 | sm = (const struct RegexSearchMessage *) message; | ||
323 | string = (const char *) &sm[1]; | 262 | string = (const char *) &sm[1]; |
324 | if ( (size <= sizeof (struct RegexSearchMessage)) || | 263 | if ('\0' != string[size - 1]) |
325 | ('\0' != string[size - sizeof (struct RegexSearchMessage) - 1]) ) | ||
326 | { | 264 | { |
327 | GNUNET_break (0); | 265 | GNUNET_break (0); |
328 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 266 | return GNUNET_SYSERR; |
329 | return; | ||
330 | } | 267 | } |
268 | if (NULL != ce->sh) | ||
269 | { | ||
270 | /* only one search allowed per client */ | ||
271 | GNUNET_break (0); | ||
272 | return GNUNET_SYSERR; | ||
273 | } | ||
274 | return GNUNET_OK; | ||
275 | } | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Handle SEARCH message. | ||
280 | * | ||
281 | * @param cls identification of the client | ||
282 | * @param message the actual message | ||
283 | */ | ||
284 | static void | ||
285 | handle_search (void *cls, | ||
286 | const struct RegexSearchMessage *sm) | ||
287 | { | ||
288 | struct ClientEntry *ce = cls; | ||
289 | const char *string; | ||
290 | |||
291 | string = (const char *) &sm[1]; | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 292 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
332 | "Starting to search for `%s'\n", | 293 | "Starting to search for `%s'\n", |
333 | string); | 294 | string); |
334 | ce = GNUNET_new (struct ClientEntry); | ||
335 | ce->client = client; | ||
336 | ce->sh = REGEX_INTERNAL_search (dht, | 295 | ce->sh = REGEX_INTERNAL_search (dht, |
337 | string, | 296 | string, |
338 | &handle_search_result, | 297 | &handle_search_result, |
@@ -341,15 +300,10 @@ handle_search (void *cls, | |||
341 | if (NULL == ce->sh) | 300 | if (NULL == ce->sh) |
342 | { | 301 | { |
343 | GNUNET_break (0); | 302 | GNUNET_break (0); |
344 | GNUNET_free (ce); | 303 | GNUNET_SERVICE_client_drop (ce->client); |
345 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
346 | return; | 304 | return; |
347 | } | 305 | } |
348 | GNUNET_CONTAINER_DLL_insert (client_head, | 306 | GNUNET_SERVICE_client_continue (ce->client); |
349 | client_tail, | ||
350 | ce); | ||
351 | GNUNET_SERVER_notification_context_add (nc, client); | ||
352 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
353 | } | 307 | } |
354 | 308 | ||
355 | 309 | ||
@@ -357,19 +311,14 @@ handle_search (void *cls, | |||
357 | * Process regex requests. | 311 | * Process regex requests. |
358 | * | 312 | * |
359 | * @param cls closure | 313 | * @param cls closure |
360 | * @param server the initialized server | ||
361 | * @param cfg configuration to use | 314 | * @param cfg configuration to use |
315 | * @param service the initialized service | ||
362 | */ | 316 | */ |
363 | static void | 317 | static void |
364 | run (void *cls, struct GNUNET_SERVER_Handle *server, | 318 | run (void *cls, |
365 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 319 | const struct GNUNET_CONFIGURATION_Handle *cfg, |
320 | struct GNUNET_SERVICE_Handle *service) | ||
366 | { | 321 | { |
367 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
368 | {&handle_announce, NULL, GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE, 0}, | ||
369 | {&handle_search, NULL, GNUNET_MESSAGE_TYPE_REGEX_SEARCH, 0}, | ||
370 | {NULL, NULL, 0, 0} | ||
371 | }; | ||
372 | |||
373 | my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg); | 322 | my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg); |
374 | if (NULL == my_private_key) | 323 | if (NULL == my_private_key) |
375 | { | 324 | { |
@@ -386,28 +335,84 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
386 | } | 335 | } |
387 | GNUNET_SCHEDULER_add_shutdown (&cleanup_task, | 336 | GNUNET_SCHEDULER_add_shutdown (&cleanup_task, |
388 | NULL); | 337 | NULL); |
389 | nc = GNUNET_SERVER_notification_context_create (server, 1); | ||
390 | stats = GNUNET_STATISTICS_create ("regex", cfg); | 338 | stats = GNUNET_STATISTICS_create ("regex", cfg); |
391 | GNUNET_SERVER_add_handlers (server, handlers); | ||
392 | GNUNET_SERVER_disconnect_notify (server, | ||
393 | &handle_client_disconnect, | ||
394 | NULL); | ||
395 | } | 339 | } |
396 | 340 | ||
397 | 341 | ||
398 | /** | 342 | /** |
399 | * The main function for the regex service. | 343 | * Callback called when a client connects to the service. |
400 | * | 344 | * |
401 | * @param argc number of arguments from the command line | 345 | * @param cls closure for the service |
402 | * @param argv command line arguments | 346 | * @param c the new client that connected to the service |
403 | * @return 0 ok, 1 on error | 347 | * @param mq the message queue used to send messages to the client |
348 | * @return @a c | ||
404 | */ | 349 | */ |
405 | int | 350 | static void * |
406 | main (int argc, char *const *argv) | 351 | client_connect_cb (void *cls, |
352 | struct GNUNET_SERVICE_Client *c, | ||
353 | struct GNUNET_MQ_Handle *mq) | ||
407 | { | 354 | { |
408 | return (GNUNET_OK == | 355 | struct ClientEntry *ce; |
409 | GNUNET_SERVICE_run (argc, argv, "regex", | 356 | |
410 | GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1; | 357 | ce = GNUNET_new (struct ClientEntry); |
358 | ce->client = c; | ||
359 | ce->mq = mq; | ||
360 | return ce; | ||
411 | } | 361 | } |
412 | 362 | ||
363 | |||
364 | /** | ||
365 | * Callback called when a client disconnected from the service | ||
366 | * | ||
367 | * @param cls closure for the service | ||
368 | * @param c the client that disconnected | ||
369 | * @param internal_cls should be equal to @a c | ||
370 | */ | ||
371 | static void | ||
372 | client_disconnect_cb (void *cls, | ||
373 | struct GNUNET_SERVICE_Client *c, | ||
374 | void *internal_cls) | ||
375 | { | ||
376 | struct ClientEntry *ce = internal_cls; | ||
377 | |||
378 | if (NULL != ce->refresh_task) | ||
379 | { | ||
380 | GNUNET_SCHEDULER_cancel (ce->refresh_task); | ||
381 | ce->refresh_task = NULL; | ||
382 | } | ||
383 | if (NULL != ce->ah) | ||
384 | { | ||
385 | REGEX_INTERNAL_announce_cancel (ce->ah); | ||
386 | ce->ah = NULL; | ||
387 | } | ||
388 | if (NULL != ce->sh) | ||
389 | { | ||
390 | REGEX_INTERNAL_search_cancel (ce->sh); | ||
391 | ce->sh = NULL; | ||
392 | } | ||
393 | GNUNET_free (ce); | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Define "main" method using service macro. | ||
399 | */ | ||
400 | GNUNET_SERVICE_MAIN | ||
401 | ("regex", | ||
402 | GNUNET_SERVICE_OPTION_NONE, | ||
403 | &run, | ||
404 | &client_connect_cb, | ||
405 | &client_disconnect_cb, | ||
406 | NULL, | ||
407 | GNUNET_MQ_hd_var_size (announce, | ||
408 | GNUNET_MESSAGE_TYPE_REGEX_ANNOUNCE, | ||
409 | struct AnnounceMessage, | ||
410 | NULL), | ||
411 | GNUNET_MQ_hd_var_size (search, | ||
412 | GNUNET_MESSAGE_TYPE_REGEX_SEARCH, | ||
413 | struct RegexSearchMessage, | ||
414 | NULL), | ||
415 | GNUNET_MQ_handler_end ()); | ||
416 | |||
417 | |||
413 | /* end of gnunet-service-regex.c */ | 418 | /* end of gnunet-service-regex.c */ |