include element type in hash
[oweals/gnunet.git] / src / core / core_api_monitor_peers.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-2014 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 3, 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., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file core/core_api_monitor_peers.c
23  * @brief implementation of the peer_iterate function
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  */
27 #include "platform.h"
28 #include "gnunet_core_service.h"
29 #include "core.h"
30
31
32 /**
33  * Handle to a CORE monitoring operation.
34  */
35 struct GNUNET_CORE_MonitorHandle
36 {
37
38   /**
39    * Our configuration.
40    */
41   const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43   /**
44    * Our connection to the service.
45    */
46   struct GNUNET_CLIENT_Connection *client;
47
48   /**
49    * Handle for transmitting a request.
50    */
51   struct GNUNET_CLIENT_TransmitHandle *th;
52
53   /**
54    * Function called with the peer.
55    */
56   GNUNET_CORE_MonitorCallback peer_cb;
57
58   /**
59    * Closure for @e peer_cb.
60    */
61   void *peer_cb_cls;
62
63 };
64
65
66 /**
67  * Transmits the monitor request to the CORE service.
68  *
69  * Function is called to notify a client about the socket begin ready
70  * to queue more data.  @a buf will be NULL and @a size zero if the
71  * socket was closed for writing in the meantime.
72  *
73  * @param cls closure, our `struct GNUNET_CORE_MonitorHandle *`
74  * @param size number of bytes available in @a buf
75  * @param buf where the callee should write the message
76  * @return number of bytes written to @a buf
77  */
78 static size_t
79 transmit_monitor_request (void *cls,
80                           size_t size,
81                           void *buf);
82
83
84 /**
85  * Protocol error, reconnect to CORE service and notify
86  * client.
87  *
88  * @param mh monitoring session to reconnect to CORE
89  */
90 static void
91 reconnect (struct GNUNET_CORE_MonitorHandle *mh)
92 {
93   GNUNET_CLIENT_disconnect (mh->client);
94   /* FIXME: use backoff? */
95   mh->client = GNUNET_CLIENT_connect ("core", mh->cfg);
96   GNUNET_assert (NULL != mh->client);
97   mh->th =
98     GNUNET_CLIENT_notify_transmit_ready (mh->client,
99                                          sizeof (struct GNUNET_MessageHeader),
100                                          GNUNET_TIME_UNIT_FOREVER_REL,
101                                          GNUNET_YES,
102                                          &transmit_monitor_request, mh);
103   /* notify callback about reconnect */
104   mh->peer_cb (mh->peer_cb_cls,
105                NULL,
106                GNUNET_CORE_KX_CORE_DISCONNECT,
107                GNUNET_TIME_UNIT_FOREVER_ABS);
108 }
109
110
111 /**
112  * Receive reply from CORE service with information about a peer.
113  *
114  * @param cls our `struct  GNUNET_CORE_MonitorHandle *`
115  * @param msg NULL on error or last entry
116  */
117 static void
118 receive_info (void *cls,
119               const struct GNUNET_MessageHeader *msg)
120 {
121   struct GNUNET_CORE_MonitorHandle *mh = cls;
122   const struct MonitorNotifyMessage *mon_message;
123   uint16_t msize;
124
125   if (NULL == msg)
126   {
127     reconnect (mh);
128     return;
129   }
130   msize = ntohs (msg->size);
131   /* Handle incorrect message type or size, disconnect and clean up */
132   if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY) ||
133       (sizeof (struct MonitorNotifyMessage) != msize))
134   {
135     GNUNET_break (0);
136     reconnect (mh);
137     return;
138   }
139   mon_message = (const struct MonitorNotifyMessage *) msg;
140   GNUNET_CLIENT_receive (mh->client,
141                          &receive_info, mh,
142                          GNUNET_TIME_UNIT_FOREVER_REL);
143   mh->peer_cb (mh->peer_cb_cls,
144                &mon_message->peer,
145                (enum GNUNET_CORE_KxState) ntohl (mon_message->state),
146                GNUNET_TIME_absolute_ntoh (mon_message->timeout));
147 }
148
149
150 /**
151  * Transmits the monitor request to the CORE service.
152  *
153  * Function is called to notify a client about the socket begin ready
154  * to queue more data.  @a buf will be NULL and @a size zero if the
155  * socket was closed for writing in the meantime.
156  *
157  * @param cls closure, our `struct GNUNET_CORE_MonitorHandle *`
158  * @param size number of bytes available in @a buf
159  * @param buf where the callee should write the message
160  * @return number of bytes written to @a buf
161  */
162 static size_t
163 transmit_monitor_request (void *cls,
164                           size_t size,
165                           void *buf)
166 {
167   struct GNUNET_CORE_MonitorHandle *mh = cls;
168   struct GNUNET_MessageHeader *msg;
169   int msize;
170
171   mh->th = NULL;
172   msize = sizeof (struct GNUNET_MessageHeader);
173   if ((size < msize) || (NULL == buf))
174   {
175     reconnect (mh);
176     return 0;
177   }
178   msg = (struct GNUNET_MessageHeader *) buf;
179   msg->size = htons (msize);
180   msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS);
181   GNUNET_CLIENT_receive (mh->client,
182                          &receive_info, mh,
183                          GNUNET_TIME_UNIT_FOREVER_REL);
184   return msize;
185 }
186
187
188 /**
189  * Monitor connectivity and KX status of all peers known to CORE.
190  * Calls @a peer_cb with the current status for each connected peer,
191  * and then once with NULL to indicate that all peers that are
192  * currently active have been handled.  After that, the iteration
193  * continues until it is cancelled.  Normal users of the CORE API are
194  * not expected to use this function.  It is different in that it
195  * truly lists all connections (including those where the KX is in
196  * progress), not just those relevant to the application.  This
197  * function is used by special applications for diagnostics.
198  *
199  * @param cfg configuration handle
200  * @param peer_cb function to call with the peer information
201  * @param peer_cb_cls closure for @a peer_cb
202  * @return NULL on error
203  */
204 struct GNUNET_CORE_MonitorHandle *
205 GNUNET_CORE_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
206                            GNUNET_CORE_MonitorCallback peer_cb,
207                            void *peer_cb_cls)
208 {
209   struct GNUNET_CORE_MonitorHandle *mh;
210   struct GNUNET_CLIENT_Connection *client;
211
212   GNUNET_assert (NULL != peer_cb);
213   client = GNUNET_CLIENT_connect ("core", cfg);
214   if (NULL == client)
215     return NULL;
216   mh = GNUNET_new (struct GNUNET_CORE_MonitorHandle);
217   mh->cfg = cfg;
218   mh->client = client;
219   mh->peer_cb = peer_cb;
220   mh->peer_cb_cls = peer_cb_cls;
221   mh->th =
222     GNUNET_CLIENT_notify_transmit_ready (client,
223                                          sizeof (struct GNUNET_MessageHeader),
224                                          GNUNET_TIME_UNIT_FOREVER_REL,
225                                          GNUNET_YES,
226                                          &transmit_monitor_request, mh);
227   return mh;
228 }
229
230
231 /**
232  * Stop monitoring CORE activity.
233  *
234  * @param mh monitor to stop
235  */
236 void
237 GNUNET_CORE_monitor_stop (struct GNUNET_CORE_MonitorHandle *mh)
238 {
239   if (NULL != mh->th)
240   {
241     GNUNET_CLIENT_notify_transmit_ready_cancel (mh->th);
242     mh->th = NULL;
243   }
244   if (NULL != mh->client)
245   {
246     GNUNET_CLIENT_disconnect (mh->client);
247     mh->client = NULL;
248   }
249   GNUNET_free (mh);
250 }
251
252
253 /* end of core_api_monitor_peers.c */