diff options
Diffstat (limited to 'src/statistics/statistics_api.c')
-rw-r--r-- | src/statistics/statistics_api.c | 688 |
1 files changed, 688 insertions, 0 deletions
diff --git a/src/statistics/statistics_api.c b/src/statistics/statistics_api.c new file mode 100644 index 000000000..f68cf9396 --- /dev/null +++ b/src/statistics/statistics_api.c | |||
@@ -0,0 +1,688 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2009 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 statistics/statistics_api.c | ||
23 | * @brief API of the statistics service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_client_lib.h" | ||
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_server_lib.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_strings_lib.h" | ||
32 | #include "statistics.h" | ||
33 | |||
34 | #define SET_TRANSMIT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Types of actions. | ||
39 | */ | ||
40 | enum ActionType | ||
41 | { | ||
42 | ACTION_GET, | ||
43 | ACTION_SET, | ||
44 | ACTION_UPDATE | ||
45 | }; | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Linked list of things we still need to do. | ||
50 | */ | ||
51 | struct ActionItem | ||
52 | { | ||
53 | /** | ||
54 | * This is a linked list. | ||
55 | */ | ||
56 | struct ActionItem *next; | ||
57 | |||
58 | /** | ||
59 | * What subsystem is this action about? (can be NULL) | ||
60 | */ | ||
61 | char *subsystem; | ||
62 | |||
63 | /** | ||
64 | * What value is this action about? (can be NULL) | ||
65 | */ | ||
66 | char *name; | ||
67 | |||
68 | /** | ||
69 | * Continuation to call once action is complete. | ||
70 | */ | ||
71 | GNUNET_STATISTICS_Callback cont; | ||
72 | |||
73 | /** | ||
74 | * Function to call (for GET actions only). | ||
75 | */ | ||
76 | GNUNET_STATISTICS_Iterator proc; | ||
77 | |||
78 | /** | ||
79 | * Closure for proc and cont. | ||
80 | */ | ||
81 | void *cls; | ||
82 | |||
83 | /** | ||
84 | * Timeout for this action. | ||
85 | */ | ||
86 | struct GNUNET_TIME_Absolute timeout; | ||
87 | |||
88 | /** | ||
89 | * Associated value. | ||
90 | */ | ||
91 | unsigned long long value; | ||
92 | |||
93 | /** | ||
94 | * Flag for SET/UPDATE actions. | ||
95 | */ | ||
96 | int make_persistent; | ||
97 | |||
98 | /** | ||
99 | * Has the current iteration been aborted; for GET actions. | ||
100 | */ | ||
101 | int aborted; | ||
102 | |||
103 | /** | ||
104 | * Is this a GET, SET or UPDATE? | ||
105 | */ | ||
106 | enum ActionType type; | ||
107 | |||
108 | /** | ||
109 | * Size of the message that we will be transmitting. | ||
110 | */ | ||
111 | uint16_t msize; | ||
112 | |||
113 | }; | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Handle for the service. | ||
118 | */ | ||
119 | struct GNUNET_STATISTICS_Handle | ||
120 | { | ||
121 | /** | ||
122 | * Our scheduler. | ||
123 | */ | ||
124 | struct GNUNET_SCHEDULER_Handle *sched; | ||
125 | |||
126 | /** | ||
127 | * Name of our subsystem. | ||
128 | */ | ||
129 | char *subsystem; | ||
130 | |||
131 | /** | ||
132 | * Configuration to use. | ||
133 | */ | ||
134 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
135 | |||
136 | /** | ||
137 | * Socket (if available). | ||
138 | */ | ||
139 | struct GNUNET_CLIENT_Connection *client; | ||
140 | |||
141 | /** | ||
142 | * Head of the linked list of pending actions (first action | ||
143 | * to be performed). | ||
144 | */ | ||
145 | struct ActionItem *action_head; | ||
146 | |||
147 | /** | ||
148 | * Tail of the linked list of actions (for fast append). | ||
149 | */ | ||
150 | struct ActionItem *action_tail; | ||
151 | |||
152 | /** | ||
153 | * Action we are currently busy with (action request has been | ||
154 | * transmitted, we're now receiving the response from the | ||
155 | * service). | ||
156 | */ | ||
157 | struct ActionItem *current; | ||
158 | |||
159 | /** | ||
160 | * Should this handle be destroyed once we've processed | ||
161 | * all actions? | ||
162 | */ | ||
163 | int do_destroy; | ||
164 | |||
165 | }; | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Try to (re)connect to the statistics service. | ||
170 | * | ||
171 | * @return GNUNET_YES on success, GNUNET_NO on failure. | ||
172 | */ | ||
173 | static int | ||
174 | try_connect (struct GNUNET_STATISTICS_Handle *ret) | ||
175 | { | ||
176 | if (ret->client != NULL) | ||
177 | return GNUNET_OK; | ||
178 | ret->client = GNUNET_CLIENT_connect (ret->sched, "statistics", ret->cfg); | ||
179 | if (ret->client != NULL) | ||
180 | return GNUNET_YES; | ||
181 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
182 | _("Failed to connect to statistics service!\n")); | ||
183 | return GNUNET_NO; | ||
184 | } | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Free memory associated with the given action item. | ||
189 | */ | ||
190 | static void | ||
191 | free_action_item (struct ActionItem *ai) | ||
192 | { | ||
193 | GNUNET_free_non_null (ai->subsystem); | ||
194 | GNUNET_free_non_null (ai->name); | ||
195 | GNUNET_free (ai); | ||
196 | } | ||
197 | |||
198 | |||
199 | /** | ||
200 | * Get handle for the statistics service. | ||
201 | * | ||
202 | * @param subsystem name of subsystem using the service | ||
203 | * @param cfg services configuration in use | ||
204 | * @return handle to use | ||
205 | */ | ||
206 | struct GNUNET_STATISTICS_Handle * | ||
207 | GNUNET_STATISTICS_create (struct GNUNET_SCHEDULER_Handle *sched, | ||
208 | const char *subsystem, | ||
209 | struct GNUNET_CONFIGURATION_Handle *cfg) | ||
210 | { | ||
211 | struct GNUNET_STATISTICS_Handle *ret; | ||
212 | |||
213 | GNUNET_assert (subsystem != NULL); | ||
214 | GNUNET_assert (sched != NULL); | ||
215 | GNUNET_assert (cfg != NULL); | ||
216 | ret = GNUNET_malloc (sizeof (struct GNUNET_STATISTICS_Handle)); | ||
217 | ret->sched = sched; | ||
218 | ret->cfg = cfg; | ||
219 | ret->subsystem = GNUNET_strdup (subsystem); | ||
220 | try_connect (ret); | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Actually free the handle. | ||
227 | */ | ||
228 | static void | ||
229 | do_destroy (struct GNUNET_STATISTICS_Handle *h) | ||
230 | { | ||
231 | GNUNET_assert (h->action_head == NULL); | ||
232 | GNUNET_assert (h->current == NULL); | ||
233 | if (h->client != NULL) | ||
234 | { | ||
235 | GNUNET_CLIENT_disconnect (h->client); | ||
236 | h->client = NULL; | ||
237 | } | ||
238 | GNUNET_free (h->subsystem); | ||
239 | GNUNET_free (h); | ||
240 | } | ||
241 | |||
242 | |||
243 | /** | ||
244 | * Destroy a handle (free all state associated with | ||
245 | * it). | ||
246 | */ | ||
247 | void | ||
248 | GNUNET_STATISTICS_destroy (struct GNUNET_STATISTICS_Handle *handle) | ||
249 | { | ||
250 | GNUNET_assert (handle->do_destroy == GNUNET_NO); | ||
251 | if ((handle->action_head != NULL) || (handle->current != NULL)) | ||
252 | { | ||
253 | handle->do_destroy = GNUNET_YES; | ||
254 | return; | ||
255 | } | ||
256 | do_destroy (handle); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Process the message. | ||
262 | * | ||
263 | * @return GNUNET_OK if the message was well-formed | ||
264 | */ | ||
265 | static int | ||
266 | process_message (struct GNUNET_STATISTICS_Handle *h, | ||
267 | const struct GNUNET_MessageHeader *msg) | ||
268 | { | ||
269 | char *service; | ||
270 | char *name; | ||
271 | const struct GNUNET_STATISTICS_ReplyMessage *smsg; | ||
272 | uint16_t size; | ||
273 | |||
274 | if (h->current->aborted) | ||
275 | return GNUNET_OK; /* don't bother */ | ||
276 | size = ntohs (msg->size); | ||
277 | if (size < sizeof (struct GNUNET_STATISTICS_ReplyMessage)) | ||
278 | { | ||
279 | GNUNET_break (0); | ||
280 | return GNUNET_SYSERR; | ||
281 | } | ||
282 | smsg = (const struct GNUNET_STATISTICS_ReplyMessage *) msg; | ||
283 | size -= sizeof (struct GNUNET_STATISTICS_ReplyMessage); | ||
284 | if (size != GNUNET_STRINGS_buffer_tokenize ((const char *) &smsg[1], | ||
285 | size, 2, &service, &name)) | ||
286 | { | ||
287 | GNUNET_break (0); | ||
288 | return GNUNET_SYSERR; | ||
289 | } | ||
290 | #if DEBUG_STATISTICS | ||
291 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
292 | "Received valid statistic on `%s:%s': %llu\n", | ||
293 | service, name, GNUNET_ntohll (smsg->value)); | ||
294 | #endif | ||
295 | if (GNUNET_OK != | ||
296 | h->current->proc (h->current->cls, | ||
297 | service, | ||
298 | name, | ||
299 | GNUNET_ntohll (smsg->value), | ||
300 | 0 != | ||
301 | (ntohl (smsg->uid) & GNUNET_STATISTICS_PERSIST_BIT))) | ||
302 | { | ||
303 | #if DEBUG_STATISTICS | ||
304 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
305 | "Processing of remaining statistics aborted by client.\n"); | ||
306 | #endif | ||
307 | h->current->aborted = GNUNET_YES; | ||
308 | } | ||
309 | return GNUNET_OK; | ||
310 | } | ||
311 | |||
312 | |||
313 | |||
314 | /** | ||
315 | * Schedule the next action to be performed. | ||
316 | */ | ||
317 | static void schedule_action (struct GNUNET_STATISTICS_Handle *h); | ||
318 | |||
319 | |||
320 | /** | ||
321 | * GET processing is complete, tell client about it. | ||
322 | */ | ||
323 | static void | ||
324 | finish (struct GNUNET_STATISTICS_Handle *h, int code) | ||
325 | { | ||
326 | struct ActionItem *pos = h->current; | ||
327 | h->current = NULL; | ||
328 | schedule_action (h); | ||
329 | if (pos->cont != NULL) | ||
330 | pos->cont (pos->cls, code); | ||
331 | free_action_item (pos); | ||
332 | } | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Function called with messages from stats service. | ||
337 | * | ||
338 | * @param cls closure | ||
339 | * @param msg message received, NULL on timeout or fatal error | ||
340 | */ | ||
341 | static void | ||
342 | receive_stats (void *cls, const struct GNUNET_MessageHeader *msg) | ||
343 | { | ||
344 | struct GNUNET_STATISTICS_Handle *h = cls; | ||
345 | |||
346 | if (msg == NULL) | ||
347 | { | ||
348 | GNUNET_CLIENT_disconnect (h->client); | ||
349 | h->client = NULL; | ||
350 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | ||
351 | _ | ||
352 | ("Error receiving statistics from service, is the service running?\n")); | ||
353 | finish (h, GNUNET_SYSERR); | ||
354 | return; | ||
355 | } | ||
356 | switch (ntohs (msg->type)) | ||
357 | { | ||
358 | case GNUNET_MESSAGE_TYPE_STATISTICS_END: | ||
359 | #if DEBUG_STATISTICS | ||
360 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
361 | "Received end of statistics marker\n"); | ||
362 | #endif | ||
363 | finish (h, GNUNET_OK); | ||
364 | return; | ||
365 | case GNUNET_MESSAGE_TYPE_STATISTICS_VALUE: | ||
366 | if (GNUNET_OK == process_message (h, msg)) | ||
367 | { | ||
368 | /* finally, look for more! */ | ||
369 | GNUNET_CLIENT_receive (h->client, | ||
370 | &receive_stats, | ||
371 | h, | ||
372 | GNUNET_TIME_absolute_get_remaining (h-> | ||
373 | current-> | ||
374 | timeout)); | ||
375 | return; | ||
376 | } | ||
377 | GNUNET_break (0); | ||
378 | break; | ||
379 | default: | ||
380 | GNUNET_break (0); | ||
381 | break; | ||
382 | } | ||
383 | GNUNET_CLIENT_disconnect (h->client); | ||
384 | h->client = NULL; | ||
385 | finish (h, GNUNET_SYSERR); | ||
386 | } | ||
387 | |||
388 | |||
389 | /** | ||
390 | * Transmit a GET request (and if successful, start to receive | ||
391 | * the response). | ||
392 | */ | ||
393 | static size_t | ||
394 | transmit_get (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | ||
395 | { | ||
396 | struct GNUNET_MessageHeader *hdr; | ||
397 | size_t slen1; | ||
398 | size_t slen2; | ||
399 | uint16_t msize; | ||
400 | |||
401 | if (buf == NULL) | ||
402 | { | ||
403 | /* timeout / error */ | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
405 | _("Transmission of request for statistics failed!\n")); | ||
406 | finish (handle, GNUNET_SYSERR); | ||
407 | return 0; | ||
408 | } | ||
409 | slen1 = strlen (handle->current->subsystem) + 1; | ||
410 | slen2 = strlen (handle->current->name) + 1; | ||
411 | msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); | ||
412 | GNUNET_assert (msize <= size); | ||
413 | hdr = (struct GNUNET_MessageHeader *) buf; | ||
414 | hdr->size = htons (msize); | ||
415 | hdr->type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_GET); | ||
416 | GNUNET_assert (slen1 + slen2 == | ||
417 | GNUNET_STRINGS_buffer_fill ((char *) &hdr[1], | ||
418 | slen1 + slen2, | ||
419 | 2, | ||
420 | handle->current->subsystem, | ||
421 | handle->current->name)); | ||
422 | GNUNET_CLIENT_receive (handle->client, | ||
423 | &receive_stats, | ||
424 | handle, | ||
425 | GNUNET_TIME_absolute_get_remaining (handle->current-> | ||
426 | timeout)); | ||
427 | return msize; | ||
428 | } | ||
429 | |||
430 | |||
431 | |||
432 | /** | ||
433 | * Transmit a SET/UPDATE request. | ||
434 | */ | ||
435 | static size_t | ||
436 | transmit_set (struct GNUNET_STATISTICS_Handle *handle, size_t size, void *buf) | ||
437 | { | ||
438 | struct GNUNET_STATISTICS_SetMessage *r; | ||
439 | size_t slen; | ||
440 | size_t nlen; | ||
441 | size_t nsize; | ||
442 | |||
443 | if (NULL == buf) | ||
444 | { | ||
445 | finish (handle, GNUNET_SYSERR); | ||
446 | return 0; | ||
447 | } | ||
448 | |||
449 | slen = strlen (handle->current->subsystem) + 1; | ||
450 | nlen = strlen (handle->current->name) + 1; | ||
451 | nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; | ||
452 | if (size < nsize) | ||
453 | { | ||
454 | GNUNET_break (0); | ||
455 | finish (handle, GNUNET_SYSERR); | ||
456 | return 0; | ||
457 | } | ||
458 | r = buf; | ||
459 | r->header.size = htons (nsize); | ||
460 | r->header.type = htons (GNUNET_MESSAGE_TYPE_STATISTICS_SET); | ||
461 | r->flags = 0; | ||
462 | r->value = GNUNET_htonll (handle->current->value); | ||
463 | if (handle->current->make_persistent) | ||
464 | r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_PERSISTENT); | ||
465 | if (handle->current->type == ACTION_UPDATE) | ||
466 | r->flags |= htonl (GNUNET_STATISTICS_SETFLAG_RELATIVE); | ||
467 | GNUNET_assert (slen + nlen == | ||
468 | GNUNET_STRINGS_buffer_fill ((char *) &r[1], | ||
469 | slen + nlen, | ||
470 | 2, | ||
471 | handle->current->subsystem, | ||
472 | handle->current->name)); | ||
473 | finish (handle, GNUNET_OK); | ||
474 | return nsize; | ||
475 | } | ||
476 | |||
477 | |||
478 | static size_t | ||
479 | transmit_action (void *cls, size_t size, void *buf) | ||
480 | { | ||
481 | struct GNUNET_STATISTICS_Handle *handle = cls; | ||
482 | size_t ret; | ||
483 | |||
484 | switch (handle->current->type) | ||
485 | { | ||
486 | case ACTION_GET: | ||
487 | ret = transmit_get (handle, size, buf); | ||
488 | break; | ||
489 | case ACTION_SET: | ||
490 | case ACTION_UPDATE: | ||
491 | ret = transmit_set (handle, size, buf); | ||
492 | break; | ||
493 | } | ||
494 | return ret; | ||
495 | } | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Schedule the next action to be performed. | ||
500 | */ | ||
501 | static void | ||
502 | schedule_action (struct GNUNET_STATISTICS_Handle *h) | ||
503 | { | ||
504 | struct GNUNET_TIME_Relative timeout; | ||
505 | |||
506 | if (h->current != NULL) | ||
507 | return; /* action already pending */ | ||
508 | if (GNUNET_YES != try_connect (h)) | ||
509 | { | ||
510 | finish (h, GNUNET_SYSERR); | ||
511 | return; | ||
512 | } | ||
513 | |||
514 | /* schedule next action */ | ||
515 | h->current = h->action_head; | ||
516 | if (NULL == h->current) | ||
517 | { | ||
518 | /* no pending network action, check destroy! */ | ||
519 | if (h->do_destroy != GNUNET_YES) | ||
520 | return; | ||
521 | do_destroy (h); | ||
522 | return; | ||
523 | } | ||
524 | h->action_head = h->action_head->next; | ||
525 | if (NULL == h->action_head) | ||
526 | h->action_tail = NULL; | ||
527 | h->current->next = NULL; | ||
528 | |||
529 | timeout = GNUNET_TIME_absolute_get_remaining (h->current->timeout); | ||
530 | if (NULL == | ||
531 | GNUNET_CLIENT_notify_transmit_ready (h->client, | ||
532 | h->current->msize, | ||
533 | timeout, &transmit_action, h)) | ||
534 | { | ||
535 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
536 | "Failed to transmit request to statistics service.\n"); | ||
537 | finish (h, GNUNET_SYSERR); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | |||
542 | static void | ||
543 | insert_ai (struct GNUNET_STATISTICS_Handle *h, struct ActionItem *ai) | ||
544 | { | ||
545 | if (h->action_tail == NULL) | ||
546 | { | ||
547 | h->action_head = ai; | ||
548 | h->action_tail = ai; | ||
549 | schedule_action (h); | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | h->action_tail->next = ai; | ||
554 | h->action_tail = ai; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | |||
559 | /** | ||
560 | * Get statistic from the peer. | ||
561 | * | ||
562 | * @param handle identification of the statistics service | ||
563 | * @param subsystem limit to the specified subsystem, NULL for our subsystem | ||
564 | * @param name name of the statistic value, NULL for all values | ||
565 | * @param timeout after how long should we give up (and call | ||
566 | * cont with an error code)? | ||
567 | * @param cont continuation to call when done (can be NULL) | ||
568 | * @param proc function to call on each value | ||
569 | * @param cls closure for cont and proc | ||
570 | */ | ||
571 | void | ||
572 | GNUNET_STATISTICS_get (struct GNUNET_STATISTICS_Handle *handle, | ||
573 | const char *subsystem, | ||
574 | const char *name, | ||
575 | struct GNUNET_TIME_Relative timeout, | ||
576 | GNUNET_STATISTICS_Callback cont, | ||
577 | GNUNET_STATISTICS_Iterator proc, void *cls) | ||
578 | { | ||
579 | size_t slen1; | ||
580 | size_t slen2; | ||
581 | struct ActionItem *ai; | ||
582 | |||
583 | GNUNET_assert (handle != NULL); | ||
584 | GNUNET_assert (proc != NULL); | ||
585 | if (GNUNET_YES != try_connect (handle)) | ||
586 | { | ||
587 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
588 | "Failed to connect to statistics service, can not get value `%s:%s'.\n", | ||
589 | strlen (subsystem) ? subsystem : "*", | ||
590 | strlen (name) ? name : "*"); | ||
591 | cont (cls, GNUNET_SYSERR); | ||
592 | return; | ||
593 | } | ||
594 | if (subsystem == NULL) | ||
595 | subsystem = ""; | ||
596 | if (name == NULL) | ||
597 | name = ""; | ||
598 | slen1 = strlen (subsystem); | ||
599 | slen2 = strlen (name); | ||
600 | GNUNET_assert (slen1 + slen2 + sizeof (struct GNUNET_MessageHeader) < | ||
601 | GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
602 | ai = GNUNET_malloc (sizeof (struct ActionItem)); | ||
603 | ai->subsystem = GNUNET_strdup (subsystem); | ||
604 | ai->name = GNUNET_strdup (name); | ||
605 | ai->cont = cont; | ||
606 | ai->proc = proc; | ||
607 | ai->cls = cls; | ||
608 | ai->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
609 | ai->type = ACTION_GET; | ||
610 | ai->msize = slen1 + slen2 + sizeof (struct GNUNET_MessageHeader); | ||
611 | insert_ai (handle, ai); | ||
612 | } | ||
613 | |||
614 | |||
615 | static void | ||
616 | add_setter_action (struct GNUNET_STATISTICS_Handle *h, | ||
617 | const char *name, | ||
618 | int make_persistent, | ||
619 | unsigned long long value, enum ActionType type) | ||
620 | { | ||
621 | struct ActionItem *ai; | ||
622 | size_t slen; | ||
623 | size_t nlen; | ||
624 | size_t nsize; | ||
625 | |||
626 | GNUNET_assert (h != NULL); | ||
627 | GNUNET_assert (name != NULL); | ||
628 | if (GNUNET_YES != try_connect (h)) | ||
629 | return; | ||
630 | slen = strlen (h->subsystem) + 1; | ||
631 | nlen = strlen (name) + 1; | ||
632 | nsize = sizeof (struct GNUNET_STATISTICS_SetMessage) + slen + nlen; | ||
633 | if (nsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
634 | { | ||
635 | GNUNET_break (0); | ||
636 | return; | ||
637 | } | ||
638 | ai = GNUNET_malloc (sizeof (struct ActionItem)); | ||
639 | ai->subsystem = GNUNET_strdup (h->subsystem); | ||
640 | ai->name = GNUNET_strdup (name); | ||
641 | ai->timeout = GNUNET_TIME_relative_to_absolute (SET_TRANSMIT_TIMEOUT); | ||
642 | ai->make_persistent = make_persistent; | ||
643 | ai->msize = nsize; | ||
644 | ai->value = value; | ||
645 | ai->type = type; | ||
646 | insert_ai (h, ai); | ||
647 | schedule_action (h); | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Set statistic value for the peer. Will always use our | ||
653 | * subsystem (the argument used when "handle" was created). | ||
654 | * | ||
655 | * @param handle identification of the statistics service | ||
656 | * @param name name of the statistic value | ||
657 | * @param value new value to set | ||
658 | * @param make_persistent should the value be kept across restarts? | ||
659 | */ | ||
660 | void | ||
661 | GNUNET_STATISTICS_set (struct GNUNET_STATISTICS_Handle *handle, | ||
662 | const char *name, | ||
663 | unsigned long long value, int make_persistent) | ||
664 | { | ||
665 | add_setter_action (handle, name, make_persistent, value, ACTION_SET); | ||
666 | } | ||
667 | |||
668 | |||
669 | /** | ||
670 | * Set statistic value for the peer. Will always use our | ||
671 | * subsystem (the argument used when "handle" was created). | ||
672 | * | ||
673 | * @param handle identification of the statistics service | ||
674 | * @param name name of the statistic value | ||
675 | * @param delta change in value (added to existing value) | ||
676 | * @param make_persistent should the value be kept across restarts? | ||
677 | */ | ||
678 | void | ||
679 | GNUNET_STATISTICS_update (struct GNUNET_STATISTICS_Handle *handle, | ||
680 | const char *name, | ||
681 | long long delta, int make_persistent) | ||
682 | { | ||
683 | add_setter_action (handle, name, make_persistent, | ||
684 | (unsigned long long) delta, ACTION_UPDATE); | ||
685 | } | ||
686 | |||
687 | |||
688 | /* end of statistics_api.c */ | ||