some fixes to the pt/vpn testcase.
[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   uint16_t msize;
82
83   if (NULL == msg)
84   {
85     /* core died, failure */
86     cth->peer_cb (cth->cb_cls, NULL);
87     GNUNET_CORE_is_peer_connected_cancel (cth);
88     return;
89   }
90   if ((ntohs (msg->type) == GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END) &&
91       (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)))
92   {
93     /* end of transmissions */
94     cth->peer_cb (cth->cb_cls, NULL);
95     GNUNET_CORE_is_peer_connected_cancel (cth);
96     return;
97   }
98   msize = ntohs (msg->size);
99   /* Handle incorrect message type or size, disconnect and clean up */
100   if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT) ||
101       (msize < sizeof (struct ConnectNotifyMessage)))
102   {
103     GNUNET_break (0);
104     cth->peer_cb (cth->cb_cls, NULL);
105     GNUNET_CORE_is_peer_connected_cancel (cth);
106     return;
107   }
108   connect_message = (const struct ConnectNotifyMessage *) msg;
109   if (msize != sizeof (struct ConnectNotifyMessage))
110   {
111     GNUNET_break (0);
112     cth->peer_cb (cth->cb_cls, NULL);
113     GNUNET_CORE_is_peer_connected_cancel (cth);
114     return;
115   }
116   /* Normal case */
117   cth->peer_cb (cth->cb_cls, &connect_message->peer);
118   GNUNET_CLIENT_receive (cth->client, &receive_connect_info,
119                          cth, GNUNET_TIME_UNIT_FOREVER_REL);
120 }
121
122
123 /**
124  * Function called to notify a client about the socket
125  * begin ready to queue more data.  "buf" will be
126  * NULL and "size" zero if the socket was closed for
127  * writing in the meantime.
128  *
129  * @param cls closure
130  * @param size number of bytes available in buf
131  * @param buf where the callee should write the message
132  * @return number of bytes written to buf
133  */
134 static size_t
135 transmit_is_connected_request (void *cls, size_t size, void *buf)
136 {
137   struct GNUNET_CORE_ConnectTestHandle *cth = cls;
138   struct GNUNET_MessageHeader *msg;
139   unsigned int msize;
140
141   cth->th = NULL;
142   msize =
143     sizeof (struct GNUNET_MessageHeader) +
144     sizeof (struct GNUNET_PeerIdentity);
145   if ( (NULL == buf) || (0 == size) )
146   {
147     cth->peer_cb (cth->cb_cls, NULL);
148     GNUNET_CLIENT_disconnect (cth->client);
149     GNUNET_free (cth);
150     return 0;
151   }
152   GNUNET_assert (size >= msize);
153   msg = (struct GNUNET_MessageHeader *) buf;
154   msg->size = htons (msize);
155   msg->type = htons (GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED);
156   memcpy (&msg[1], &cth->peer, sizeof (struct GNUNET_PeerIdentity));
157   GNUNET_CLIENT_receive (cth->client, &receive_connect_info, cth,
158                          GNUNET_TIME_UNIT_FOREVER_REL);
159   return msize;
160 }
161
162
163 /**
164  * Iterate over all currently connected peers.
165  * Calls peer_cb with each connected peer, and then
166  * once with NULL to indicate that all peers have
167  * been handled.
168  *
169  * @param cfg configuration to use
170  * @param peer the specific peer to check for
171  * @param peer_cb function to call with the peer information
172  * @param cb_cls closure for peer_cb
173  *
174  * @return GNUNET_OK if iterating, GNUNET_SYSERR on error
175  */
176 struct GNUNET_CORE_ConnectTestHandle *
177 GNUNET_CORE_is_peer_connected (const struct GNUNET_CONFIGURATION_Handle *cfg,
178                                const struct GNUNET_PeerIdentity *peer,
179                                GNUNET_CORE_ConnectEventHandler peer_cb,
180                                void *cb_cls)
181 {
182   struct GNUNET_CORE_ConnectTestHandle *cth;
183   struct GNUNET_CLIENT_Connection *client;
184
185   GNUNET_assert (NULL != peer);
186   GNUNET_assert (NULL != peer_cb);
187   client = GNUNET_CLIENT_connect ("core", cfg);
188   if (NULL == client)
189     return NULL;
190   cth = GNUNET_malloc (sizeof (struct GNUNET_CORE_ConnectTestHandle));
191   cth->peer = *peer;
192   cth->client = client;
193   cth->peer_cb = peer_cb;
194   cth->cb_cls = cb_cls;
195   cth->th =
196     GNUNET_CLIENT_notify_transmit_ready (client,
197                                          sizeof (struct GNUNET_MessageHeader) +
198                                          sizeof (struct GNUNET_PeerIdentity),
199                                          GNUNET_TIME_UNIT_FOREVER_REL,
200                                          GNUNET_YES, &transmit_is_connected_request, cth);
201   GNUNET_assert (NULL != cth->th);
202   return cth;
203 }
204
205
206 /**
207  * Abort 'is_connected' test operation.
208  *
209  * @param cth handle for operation to cancel
210  */
211 void
212 GNUNET_CORE_is_peer_connected_cancel (struct GNUNET_CORE_ConnectTestHandle *cth)
213 {
214   if (NULL != cth->th)
215   {
216     GNUNET_CLIENT_notify_transmit_ready_cancel (cth->th);
217     cth->th = NULL;
218   }
219   GNUNET_CLIENT_disconnect (cth->client);
220   GNUNET_free (cth);
221 }
222
223
224 /* end of core_api_is_connected.c */