cecda0ebe8a9d0e938d75e0bfdf0551d659c88ba
[oweals/gnunet.git] / src / nse / nse_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5      GNUnet is free software: you can redistribute it and/or modify it
6      under the terms of the GNU Affero General Public License as published
7      by the Free Software Foundation, either version 3 of the License,
8      or (at your 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      Affero General Public License for more details.
14     
15      You should have received a copy of the GNU Affero General Public License
16      along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /**
20  * @file nse/nse_api.c
21  * @brief api to get information from the network size estimation service
22  * @author Nathan Evans
23  */
24 #include "platform.h"
25 #include "gnunet_constants.h"
26 #include "gnunet_arm_service.h"
27 #include "gnunet_hello_lib.h"
28 #include "gnunet_protocols.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_nse_service.h"
31 #include "nse.h"
32
33 #define LOG(kind,...) GNUNET_log_from (kind, "nse-api",__VA_ARGS__)
34
35 /**
36  * Handle for talking with the NSE service.
37  */
38 struct GNUNET_NSE_Handle
39 {
40   /**
41    * Configuration to use.
42    */
43   const struct GNUNET_CONFIGURATION_Handle *cfg;
44
45   /**
46    * Message queue (if available).
47    */
48   struct GNUNET_MQ_Handle *mq;
49
50   /**
51    * Task doing exponential back-off trying to reconnect.
52    */
53   struct GNUNET_SCHEDULER_Task *reconnect_task;
54
55   /**
56    * Time for next connect retry.
57    */
58   struct GNUNET_TIME_Relative reconnect_delay;
59
60   /**
61    * Callback function to call when message is received.
62    */
63   GNUNET_NSE_Callback recv_cb;
64
65   /**
66    * Closure to pass to @e recv_cb callback.
67    */
68   void *recv_cb_cls;
69
70 };
71
72
73 /**
74  * Try again to connect to network size estimation service.
75  *
76  * @param cls closure with the `struct GNUNET_NSE_Handle *`
77  */
78 static void
79 reconnect (void *cls);
80
81
82 /**
83  * Generic error handler, called with the appropriate
84  * error code and the same closure specified at the creation of
85  * the message queue.
86  * Not every message queue implementation supports an error handler.
87  *
88  * @param cls closure with the `struct GNUNET_NSE_Handle *`
89  * @param error error code
90  */
91 static void
92 mq_error_handler (void *cls,
93                   enum GNUNET_MQ_Error error)
94 {
95   struct GNUNET_NSE_Handle *h = cls;
96
97   GNUNET_MQ_destroy (h->mq);
98   h->mq = NULL;
99   h->reconnect_task
100     = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
101                                     &reconnect,
102                                     h);
103   h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
104 }
105
106
107 /**
108  * Type of a function to call when we receive a message
109  * from the service.
110  *
111  * @param cls closure
112  * @param client_msg message received
113  */
114 static void
115 handle_estimate (void *cls,
116                  const struct GNUNET_NSE_ClientMessage *client_msg)
117 {
118   struct GNUNET_NSE_Handle *h = cls;
119
120   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
121   h->recv_cb (h->recv_cb_cls,
122               GNUNET_TIME_absolute_ntoh (client_msg->timestamp),
123               GNUNET_ntoh_double (client_msg->size_estimate),
124               GNUNET_ntoh_double (client_msg->std_deviation));
125 }
126
127
128 /**
129  * Try again to connect to network size estimation service.
130  *
131  * @param cls the `struct GNUNET_NSE_Handle *`
132  */
133 static void
134 reconnect (void *cls)
135 {
136   struct GNUNET_NSE_Handle *h = cls;
137   struct GNUNET_MQ_MessageHandler handlers[] = {
138     GNUNET_MQ_hd_fixed_size (estimate,
139                              GNUNET_MESSAGE_TYPE_NSE_ESTIMATE,
140                              struct GNUNET_NSE_ClientMessage,
141                              h),
142     GNUNET_MQ_handler_end ()
143   };
144   struct GNUNET_MessageHeader *msg;
145   struct GNUNET_MQ_Envelope *env;
146
147   h->reconnect_task = NULL;
148   LOG (GNUNET_ERROR_TYPE_DEBUG,
149        "Connecting to network size estimation service.\n");
150   GNUNET_assert (NULL == h->mq);
151   h->mq = GNUNET_CLIENT_connect (h->cfg,
152                                  "nse",
153                                  handlers,
154                                  &mq_error_handler,
155                                  h);
156   if (NULL == h->mq)
157     return;
158   env = GNUNET_MQ_msg (msg,
159                        GNUNET_MESSAGE_TYPE_NSE_START);
160   GNUNET_MQ_send (h->mq,
161                   env);
162 }
163
164
165 /**
166  * Connect to the network size estimation service.
167  *
168  * @param cfg the configuration to use
169  * @param func funtion to call with network size estimate
170  * @param func_cls closure to pass to @a func
171  * @return handle to use
172  */
173 struct GNUNET_NSE_Handle *
174 GNUNET_NSE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
175                     GNUNET_NSE_Callback func,
176                     void *func_cls)
177 {
178   struct GNUNET_NSE_Handle *h;
179
180   GNUNET_assert (NULL != func);
181   h = GNUNET_new (struct GNUNET_NSE_Handle);
182   h->cfg = cfg;
183   h->recv_cb = func;
184   h->recv_cb_cls = func_cls;
185   h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
186   reconnect (h);
187   if (NULL == h->mq)
188   {
189     GNUNET_free (h);
190     return NULL;
191   }
192   return h;
193 }
194
195
196 /**
197  * Disconnect from network size estimation service
198  *
199  * @param h handle to destroy
200  */
201 void
202 GNUNET_NSE_disconnect (struct GNUNET_NSE_Handle *h)
203 {
204   if (NULL != h->reconnect_task)
205   {
206     GNUNET_SCHEDULER_cancel (h->reconnect_task);
207     h->reconnect_task = NULL;
208   }
209   if (NULL != h->mq)
210   {
211     GNUNET_MQ_destroy (h->mq);
212     h->mq = NULL;
213   }
214   GNUNET_free (h);
215 }
216
217 /* end of nse_api.c */