diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-08-05 08:18:52 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-08-05 08:18:52 +0000 |
commit | 6b0266fa3464b54f37ec1e1f2ac0725b318b0027 (patch) | |
tree | 5c9243cb0b8d59872c70ee28fdf7284b4b7b4f8f /src/transport/gnunet-service-transport_clients.c | |
parent | 857cb6a5341bc27cf1997fc48c2df173c4380fd2 (diff) | |
download | gnunet-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.c | 389 |
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 | */ | ||
52 | struct 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 | */ | ||
69 | struct 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 | */ | ||
115 | static struct TransportClient *clients_head; | ||
116 | |||
117 | /** | ||
118 | * Tail of linked list of all clients to this service. | ||
119 | */ | ||
120 | static 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 | */ | ||
129 | static struct TransportClient * | ||
130 | lookup_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 | */ | ||
151 | static struct TransportClient * | ||
152 | setup_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 | */ | ||
175 | static size_t | ||
176 | transmit_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 | */ | ||
240 | static void | ||
241 | unicast (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 | */ | ||
289 | static void | ||
290 | client_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 @@ | |||
35 | void | 331 | void |
36 | GST_clients_start (struct GNUNET_SERVER_Handle *server) | 332 | GST_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) | |||
44 | void | 342 | void |
45 | GST_clients_stop () | 343 | GST_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 | */ | ||
358 | static void | ||
359 | notify_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 | */ |
60 | void | 392 | void |
61 | GST_clients_handle_init (void *cls, | 393 | GST_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 (¬ify_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 | */ |
151 | void | 511 | void |
152 | GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, | 512 | GST_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 | */ |
166 | void | 529 | void |
167 | GST_clients_unicast (struct GNUNET_SERVER_Client *client, | 530 | GST_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 | ||