-fix logging, revert to break instead of assert
[oweals/gnunet.git] / src / core / core_api_is_connected.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010, 2012 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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file core/core_api_is_connected.c
23  * @brief implementation of the 'GNUNET_CORE_is_peer_connected function
24  * @author Christian Grothoff
25  * @author Nathan Evans
26  *
27  * TODO:
28  * - define nice structs for the IPC messages in core.h
29  * - consider NOT always sending the 'END' message -- it is redundant!
30  */
31 #include "platform.h"
32 #include "gnunet_core_service.h"
33 #include "core.h"
34
35
36 /**
37  * Closure for 'transmit_is_connected_request"
38  */
39 struct GNUNET_CORE_ConnectTestHandle
40 {
41  
42   /**
43    * Our connection to the service.
44    */
45   struct GNUNET_CLIENT_Connection *client;
46
47   /**
48    * Handle for transmitting a request.
49    */
50   struct GNUNET_CLIENT_TransmitHandle *th;
51
52   /**
53    * Function called with the peer.
54    */
55   GNUNET_CORE_ConnectEventHandler peer_cb;
56
57   /**
58    * Peer to check for.
59    */
60   struct GNUNET_PeerIdentity peer;
61
62   /**
63    * Closure for peer_cb.
64    */
65   void *cb_cls;
66
67 };
68
69
70 /**
71  * Receive reply from core service with information about a peer.
72  *
73  * @param cls our 'struct  GNUNET_CORE_RequestContext *'
74  * @param msg NULL on error or last entry
75  */
76 static void
77 receive_connect_info (void *cls, const struct GNUNET_MessageHeader *msg)
78 {
79   struct GNUNET_CORE_ConnectTestHandle *cth = cls;
80   const struct ConnectNotifyMessage *connect_message;
81   uint32_t ats_count;
82   uint16_t msize;
83
84   if (NULL == msg)
85   {
86     /* core died, failure */
87     cth->peer_cb (cth->cb_cls, NULL, NULL, 0);
88     GNUNET_CORE_is_peer_connected_cancel (cth);
89     return;
90   }
91   if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) &&
92       (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)))
93   {
94     /* end of transmissions */
95     cth->peer_cb (cth->cb_cls, NULL, NULL, 0);
96     GNUNET_CORE_is_peer_connected_cancel (cth);
97     return;
98   }
99   msize = ntohs (msg->size);
100   /* Handle incorrect message type or size, disconnect and clean up */
101   if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) ||
102       (msize < sizeof (struct ConnectNotifyMessage)))
103   {
104     GNUNET_break (0);
105     cth->peer_cb (cth->cb_cls, NULL, NULL, 0);
106     GNUNET_CORE_is_peer_connected_cancel (cth);
107     return;
108   }
109   connect_message = (const struct ConnectNotifyMessage *) msg;
110   ats_count = ntohl (connect_message->ats_count);
111   if (msize !=
112       sizeof (struct ConnectNotifyMessage) +
113       ats_count * sizeof (struct GNUNET_ATS_Information))
114   {
115     GNUNET_break (0);
116     cth->peer_cb (cth->cb_cls, NULL, NULL, 0);
117     GNUNET_CORE_is_peer_connected_cancel (cth);
118     return;
119   }
120   /* Normal case */
121   cth->peer_cb (cth->cb_cls, &connect_message->peer,
122                 (const struct GNUNET_ATS_Information *)
123                 &connect_message[1], ats_count);
124   GNUNET_CLIENT_receive (cth->client, &receive_connect_info,
125                          cth, GNUNET_TIME_UNIT_FOREVER_REL);
126 }
127
128
129 /**
130  * Function called to notify a client about the socket
131  * begin ready to queue more data.  "buf" will be
132  * NULL and "size" zero if the socket was closed for
133  * writing in the meantime.
134  *
135  * @param cls closure
136  * @param size number of bytes available in buf
137  * @param buf where the callee should write the message
138  * @return number of bytes written to buf
139  */
140 static size_t
141 transmit_is_connected_request (void *cls, size_t size, void *buf)
142 {
143   struct GNUNET_CORE_ConnectTestHandle *cth = cls;
144   struct GNUNET_MessageHeader *msg;
145   unsigned int msize;
146
147   cth->th = NULL;
148   msize =
149     sizeof (struct GNUNET_MessageHeader) +
150     sizeof (struct GNUNET_PeerIdentity);
151   if ( (NULL == buf) || (0 == size) )
152   {
153     cth->peer_cb (cth->cb_cls,
154                   NULL,
155                   NULL, 0);
156     GNUNET_CLIENT_disconnect (cth->client);
157     GNUNET_free (cth);
158     return 0;
159   }
160   GNUNET_assert (size >= msize);
161   msg = (struct GNUNET_MessageHeader *) buf;
162   msg->size = htons (msize);
163   msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED);
164   memcpy (&msg[1], &cth->peer, sizeof (struct GNUNET_PeerIdentity));
165   GNUNET_CLIENT_receive (cth->client, &receive_connect_info, cth,
166                          GNUNET_TIME_UNIT_FOREVER_REL);
167   return msize;
168 }
169
170
171 /**
172  * Iterate over all currently connected peers.
173  * Calls peer_cb with each connected peer, and then
174  * once with NULL to indicate that all peers have
175  * been handled.
176  *
177  * @param cfg configuration to use
178  * @param peer the specific peer to check for
179  * @param peer_cb function to call with the peer information
180  * @param cb_cls closure for peer_cb
181  *
182  * @return GNUNET_OK if iterating, GNUNET_SYSERR on error
183  */
184 struct GNUNET_CORE_ConnectTestHandle *
185 GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg,
186                                const struct GNUNET_PeerIdentity *peer,
187                                GNUNET_CORE_ConnectEventHandler peer_cb,
188                                void *cb_cls)
189 {
190   struct GNUNET_CORE_ConnectTestHandle *cth;
191   struct GNUNET_CLIENT_Connection *client;
192
193   GNUNET_assert (NULL != peer);
194   GNUNET_assert (NULL != peer_cb);
195   client = GNUNET_CLIENT_connect ("core", cfg);
196   if (NULL == client)
197     return NULL;
198   cth = GNUNET_malloc (sizeof (struct GNUNET_CORE_ConnectTestHandle));
199   cth->peer = *peer;
200   cth->client = client;
201   cth->peer_cb = peer_cb;
202   cth->cb_cls = cb_cls;
203   cth->th =
204     GNUNET_CLIENT_notify_transmit_ready (client,
205                                          sizeof (struct GNUNET_MessageHeader) +
206                                          sizeof (struct GNUNET_PeerIdentity),
207                                          GNUNET_TIME_UNIT_FOREVER_REL,
208                                          GNUNET_YES, &transmit_is_connected_request, cth);
209   GNUNET_assert (NULL != cth->th);
210   return cth;
211 }
212
213
214 /**
215  * Abort 'is_connected' test operation.
216  *
217  * @param cth handle for operation to cancel
218  */
219 void
220 GNUNET_CORE_is_peer_connected_cancel (struct GNUNET_CORE_ConnectTestHandle *cth)
221 {
222   if (NULL != cth->th)
223   {
224     GNUNET_CLIENT_notify_transmit_ready_cancel (cth->th);
225     cth->th = NULL;
226   }
227   GNUNET_CLIENT_disconnect (cth->client);
228   GNUNET_free (cth);
229 }
230
231
232 /* end of core_api_is_connected.c */