aboutsummaryrefslogtreecommitdiff
path: root/src/transport/gnunet-service-transport_clients.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-08-05 08:18:52 +0000
committerChristian Grothoff <christian@grothoff.org>2011-08-05 08:18:52 +0000
commit6b0266fa3464b54f37ec1e1f2ac0725b318b0027 (patch)
tree5c9243cb0b8d59872c70ee28fdf7284b4b7b4f8f /src/transport/gnunet-service-transport_clients.c
parent857cb6a5341bc27cf1997fc48c2df173c4380fd2 (diff)
downloadgnunet-6b0266fa3464b54f37ec1e1f2ac0725b318b0027.tar.gz
gnunet-6b0266fa3464b54f37ec1e1f2ac0725b318b0027.zip
more client code
Diffstat (limited to 'src/transport/gnunet-service-transport_clients.c')
-rw-r--r--src/transport/gnunet-service-transport_clients.c389
1 files changed, 379 insertions, 10 deletions
diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c
index aabd1f225..97939bbf7 100644
--- a/src/transport/gnunet-service-transport_clients.c
+++ b/src/transport/gnunet-service-transport_clients.c
@@ -25,6 +25,302 @@
25 */ 25 */
26#include "platform.h" 26#include "platform.h"
27#include "gnunet-service-transport_clients.h" 27#include "gnunet-service-transport_clients.h"
28#include "gnunet-service-transport_hello.h"
29#include "gnunet-service-transport_neighbours.h"
30#include "gnunet-service-transport.h"
31#include "transport.h"
32
33/**
34 * How many messages can we have pending for a given client process
35 * before we start to drop incoming messages? We typically should
36 * have only one client and so this would be the primary buffer for
37 * messages, so the number should be chosen rather generously.
38 *
39 * The expectation here is that most of the time the queue is large
40 * enough so that a drop is virtually never required. Note that
41 * this value must be about as large as 'TOTAL_MSGS' in the
42 * 'test_transport_api_reliability.c', otherwise that testcase may
43 * fail.
44 */
45#define MAX_PENDING (128 * 1024)
46
47
48/**
49 * Linked list of messages to be transmitted to the client. Each
50 * entry is followed by the actual message.
51 */
52struct ClientMessageQueueEntry
53{
54 /**
55 * This is a doubly-linked list.
56 */
57 struct ClientMessageQueueEntry *next;
58
59 /**
60 * This is a doubly-linked list.
61 */
62 struct ClientMessageQueueEntry *prev;
63};
64
65
66/**
67 * Client connected to the transport service.
68 */
69struct TransportClient
70{
71
72 /**
73 * This is a doubly-linked list.
74 */
75 struct TransportClient *next;
76
77 /**
78 * This is a doubly-linked list.
79 */
80 struct TransportClient *prev;
81
82 /**
83 * Handle to the client.
84 */
85 struct GNUNET_SERVER_Client *client;
86
87 /**
88 * Linked list of messages yet to be transmitted to
89 * the client.
90 */
91 struct ClientMessageQueueEntry *message_queue_head;
92
93 /**
94 * Tail of linked list of messages yet to be transmitted to the
95 * client.
96 */
97 struct ClientMessageQueueEntry *message_queue_tail;
98
99 /**
100 * Current transmit request handle.
101 */
102 struct GNUNET_CONNECTION_TransmitHandle *th;
103
104 /**
105 * Length of the list of messages pending for this client.
106 */
107 unsigned int message_count;
108
109};
110
111
112/**
113 * Head of linked list of all clients to this service.
114 */
115static struct TransportClient *clients_head;
116
117/**
118 * Tail of linked list of all clients to this service.
119 */
120static struct TransportClient *clients_tail;
121
122
123/**
124 * Find the internal handle associated with the given client handle
125 *
126 * @param client server's client handle to look up
127 * @return internal client handle
128 */
129static struct TransportClient *
130lookup_client (struct GNUNET_SERVER_Client *client)
131{
132 struct TransportClient *tc;
133
134 tc = clients_head;
135 while (tc != NULL)
136 {
137 if (tc->client == client)
138 return tc;
139 tc = tc->next;
140 }
141 return NULL;
142}
143
144
145/**
146 * Create the internal handle for the given server client handle
147 *
148 * @param client server's client handle to create our internal handle for
149 * @return fresh internal client handle
150 */
151static struct TransportClient *
152setup_client (struct GNUNET_SERVER_Client *client)
153{
154 struct TransportClient *tc;
155
156 tc = GNUNET_malloc (sizeof (struct TransportClient));
157 tc->client = client;
158 GNUNET_CONTAINER_DLL_insert (clients_head,
159 clients_tail,
160 tc);
161 return tc;
162}
163
164
165/**
166 * Function called to notify a client about the socket being ready to
167 * queue more data. "buf" will be NULL and "size" zero if the socket
168 * was closed for writing in the meantime.
169 *
170 * @param cls closure
171 * @param size number of bytes available in buf
172 * @param buf where the callee should write the message
173 * @return number of bytes written to buf
174 */
175static size_t
176transmit_to_client_callback (void *cls,
177 size_t size,
178 void *buf)
179{
180 struct TransportClient *tc = cls;
181 struct ClientMessageQueueEntry *q;
182 const struct GNUNET_MessageHeader *msg;
183 char *cbuf;
184 uint16_t msize;
185 size_t tsize;
186
187 tc->th = NULL;
188 if (buf == NULL)
189 {
190#if DEBUG_TRANSPORT
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Transmission to client failed, closing connection.\n");
193#endif
194 return 0;
195 }
196 cbuf = buf;
197 tsize = 0;
198 while (NULL != (q = tc->message_queue_head))
199 {
200 msg = (const struct GNUNET_MessageHeader *) &q[1];
201 msize = ntohs (msg->size);
202 if (msize + tsize > size)
203 break;
204#if DEBUG_TRANSPORT
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 "Transmitting message of type %u to client.\n",
207 ntohs (msg->type));
208#endif
209 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
210 tc->message_queue_tail,
211 q);
212 tc->message_count--;
213 memcpy (&cbuf[tsize],
214 msg,
215 msize);
216 GNUNET_free (q);
217 tsize += msize;
218 }
219 if (NULL != q)
220 {
221 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
222 tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client,
223 msize,
224 GNUNET_TIME_UNIT_FOREVER_REL,
225 &transmit_to_client_callback,
226 tc);
227 GNUNET_assert (tc->th != NULL);
228 }
229 return tsize;
230}
231
232
233/**
234 * Queue the given message for transmission to the given client
235 *
236 * @param client target of the message
237 * @param msg message to transmit
238 * @param may_drop GNUNET_YES if the message can be dropped
239 */
240static void
241unicast (struct TransportClient *tc,
242 const struct GNUNET_MessageHeader *msg,
243 int may_drop)
244{
245 struct ClientMessageQueueEntry *q;
246 uint16_t msize;
247
248 if ( (tc->message_count >= MAX_PENDING) &&
249 (GNUNET_YES == may_drop) )
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
252 _("Dropping message of type %u and size %u, have %u/%u messages pending\n"),
253 ntohs (msg->type),
254 ntohs (msg->size),
255 tc->message_count,
256 MAX_PENDING);
257 GNUNET_STATISTICS_update (GST_stats,
258 gettext_noop ("# messages dropped due to slow client"),
259 1,
260 GNUNET_NO);
261 return;
262 }
263 msize = ntohs (msg->size);
264 GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
265 q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
266 memcpy (&q[1], msg, msize);
267 GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
268 tc->message_queue_tail,
269 q);
270 tc->message_count++;
271 if (tc->th != NULL)
272 return;
273 tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client,
274 msize,
275 GNUNET_TIME_UNIT_FOREVER_REL,
276 &transmit_to_client_callback,
277 tc);
278 GNUNET_assert (tc->th != NULL);
279}
280
281
282/**
283 * Called whenever a client is disconnected. Frees our
284 * resources associated with that client.
285 *
286 * @param cls closure
287 * @param client identification of the client
288 */
289static void
290client_disconnect_notification (void *cls,
291 struct GNUNET_SERVER_Client *client)
292{
293 struct TransportClient *tc;
294 struct ClientMessageQueueEntry *mqe;
295
296 if (client == NULL)
297 return;
298 tc = lookup_client (client);
299 if (tc == NULL)
300 return;
301#if DEBUG_TRANSPORT
302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
303 "Client disconnected, cleaning up.\n");
304#endif
305 while (NULL != (mqe = tc->message_queue_head))
306 {
307 GNUNET_CONTAINER_DLL_remove (tc->message_queue_head,
308 tc->message_queue_tail,
309 mqe);
310 tc->message_count--;
311 GNUNET_free (mqe);
312 }
313 GNUNET_CONTAINER_DLL_remove (clients_head,
314 clients_tail,
315 tc);
316 if (tc->th != NULL)
317 {
318 GNUNET_CONNECTION_notify_transmit_ready_cancel (tc->th);
319 tc->th = NULL;
320 }
321 GNUNET_break (0 == tc->message_count);
322 GNUNET_free (tc);
323}
28 324
29 325
30/** 326/**
@@ -35,6 +331,8 @@
35void 331void
36GST_clients_start (struct GNUNET_SERVER_Handle *server) 332GST_clients_start (struct GNUNET_SERVER_Handle *server)
37{ 333{
334 GNUNET_SERVER_disconnect_notify (server,
335 &client_disconnect_notification, NULL);
38} 336}
39 337
40 338
@@ -44,24 +342,86 @@ GST_clients_start (struct GNUNET_SERVER_Handle *server)
44void 342void
45GST_clients_stop () 343GST_clients_stop ()
46{ 344{
345 /* nothing to do */
47} 346}
48 347
49 348
349/**
350 * Function called for each of our connected neighbours. Notify the
351 * client about the existing neighbour.
352 *
353 * @param cls the 'struct TransportClient' to notify
354 * @param peer identity of the neighbour
355 * @param ats performance data
356 * @param ats_count number of entries in ats (excluding 0-termination)
357 */
358static void
359notify_client_about_neighbour (void *cls,
360 const struct GNUNET_PeerIdentity *peer,
361 const struct GNUNET_TRANSPORT_ATS_Information *ats,
362 uint32_t ats_count)
363{
364 struct TransportClient *tc = cls;
365 struct ConnectInfoMessage *cim;
366 size_t size;
367
368 size = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
369 GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
370 cim = GNUNET_malloc (size);
371 cim->header.size = htons (size);
372 cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
373 cim->ats_count = htonl(ats_count);
374 cim->id = *peer;
375 memcpy (&cim->ats,
376 ats,
377 ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
378 unicast (tc, &cim->header, GNUNET_NO);
379 GNUNET_free (cim);
380}
381
50 382
51/** 383/**
52 * Initialize a normal client. We got an init message from this 384 * Initialize a normal client. We got a start message from this
53 * client, add him to the list of clients for broadcasting of inbound 385 * client, add him to the list of clients for broadcasting of inbound
54 * messages. 386 * messages.
55 * 387 *
56 * @param cls unused 388 * @param cls unused
57 * @param client the client 389 * @param client the client
58 * @param message the init message that was sent 390 * @param message the start message that was sent
59 */ 391 */
60void 392void
61GST_clients_handle_init (void *cls, 393GST_clients_handle_start (void *cls,
62 struct GNUNET_SERVER_Client *client, 394 struct GNUNET_SERVER_Client *client,
63 const struct GNUNET_MessageHeader *message) 395 const struct GNUNET_MessageHeader *message)
64{ 396{
397 const struct StartMessage *start;
398 struct TransportClient *tc;
399
400 tc = lookup_client (client);
401 if (tc != NULL)
402 {
403 /* got 'start' twice from the same client, not allowed */
404 GNUNET_break (0);
405 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
406 return;
407 }
408 start = (const struct StartMessage*) message;
409 if ( (GNUNET_NO != ntohl (start->do_check)) &&
410 (0 != memcmp (&start->self,
411 &GST_my_identity,
412 sizeof (struct GNUNET_PeerIdentity))) )
413 {
414 /* client thinks this is a different peer, reject */
415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
416 _("Rejecting control connection from peer `%s', which is not me!\n"),
417 GNUNET_i2s (&start->self));
418 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
419 return;
420 }
421 tc = setup_client (client);
422 unicast (tc, GST_hello_get(), GNUNET_NO);
423 GST_neighbours_iterate (&notify_client_about_neighbour, tc);
424 GNUNET_SERVER_receive_done (client, GNUNET_OK);
65} 425}
66 426
67 427
@@ -146,13 +506,16 @@ GST_clients_handle_address_iterate (void *cls,
146 * Broadcast the given message to all of our clients. 506 * Broadcast the given message to all of our clients.
147 * 507 *
148 * @param msg message to broadcast 508 * @param msg message to broadcast
149 * @param candrop GNUNET_YES if the message can be dropped 509 * @param may_drop GNUNET_YES if the message can be dropped
150 */ 510 */
151void 511void
152GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, 512GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
153 int candrop) 513 int may_drop)
154{ 514{
155 515 struct TransportClient *tc;
516
517 for (tc = clients_head; tc != NULL; tc = tc->next)
518 unicast (tc, msg, may_drop);
156} 519}
157 520
158 521
@@ -161,13 +524,19 @@ GST_clients_broadcast (const struct GNUNET_MessageHeader *msg,
161 * 524 *
162 * @param client target of the message 525 * @param client target of the message
163 * @param msg message to transmit 526 * @param msg message to transmit
164 * @param candrop GNUNET_YES if the message can be dropped 527 * @param may_drop GNUNET_YES if the message can be dropped
165 */ 528 */
166void 529void
167GST_clients_unicast (struct GNUNET_SERVER_Client *client, 530GST_clients_unicast (struct GNUNET_SERVER_Client *client,
168 const struct GNUNET_MessageHeader *msg, 531 const struct GNUNET_MessageHeader *msg,
169 int candrop) 532 int may_drop)
170{ 533{
534 struct TransportClient *tc;
535
536 tc = lookup_client (client);
537 if (NULL == tc)
538 tc = setup_client (client);
539 unicast (tc, msg, may_drop);
171} 540}
172 541
173 542