diff options
author | Christian Grothoff <christian@grothoff.org> | 2010-01-22 14:20:31 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2010-01-22 14:20:31 +0000 |
commit | 0bcccf6577555ed605e12a02ee09ffa8595b8a51 (patch) | |
tree | 5ebcee438aa620a303649552cf9d547e848ddf29 /src/util/server_nc.c | |
parent | 1e83b104b323d90664e90af7a12166308ba6ee7a (diff) | |
download | gnunet-0bcccf6577555ed605e12a02ee09ffa8595b8a51.tar.gz gnunet-0bcccf6577555ed605e12a02ee09ffa8595b8a51.zip |
finishing nc implementation
Diffstat (limited to 'src/util/server_nc.c')
-rw-r--r-- | src/util/server_nc.c | 137 |
1 files changed, 132 insertions, 5 deletions
diff --git a/src/util/server_nc.c b/src/util/server_nc.c index 89e59b799..e9c2f5a38 100644 --- a/src/util/server_nc.c +++ b/src/util/server_nc.c | |||
@@ -50,11 +50,15 @@ struct ClientList | |||
50 | 50 | ||
51 | struct ClientList *next; | 51 | struct ClientList *next; |
52 | 52 | ||
53 | struct GNUNET_SERVER_NotificationContext *nc; | ||
54 | |||
53 | struct GNUNET_SERVER_Client *client; | 55 | struct GNUNET_SERVER_Client *client; |
54 | 56 | ||
55 | struct GNUNET_CONNECTION_TransmitHandle *th; | 57 | struct GNUNET_CONNECTION_TransmitHandle *th; |
56 | 58 | ||
57 | struct PendingMessageList *pending; | 59 | struct PendingMessageList *pending_head; |
60 | |||
61 | struct PendingMessageList *pending_tail; | ||
58 | 62 | ||
59 | unsigned int num_pending; | 63 | unsigned int num_pending; |
60 | 64 | ||
@@ -105,9 +109,9 @@ handle_client_disconnect (void *cls, | |||
105 | nc->clients = pos->next; | 109 | nc->clients = pos->next; |
106 | else | 110 | else |
107 | prev->next = pos->next; | 111 | prev->next = pos->next; |
108 | while (NULL != (pml = pos->pending)) | 112 | while (NULL != (pml = pos->pending_head)) |
109 | { | 113 | { |
110 | pos->pending = pml->next; | 114 | pos->pending_head = pml->next; |
111 | GNUNET_free (pml); | 115 | GNUNET_free (pml); |
112 | } | 116 | } |
113 | GNUNET_free (pos); | 117 | GNUNET_free (pos); |
@@ -155,9 +159,9 @@ GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationCon | |||
155 | nc->clients = pos->next; | 159 | nc->clients = pos->next; |
156 | GNUNET_SERVER_receive_done (pos->client, GNUNET_NO); | 160 | GNUNET_SERVER_receive_done (pos->client, GNUNET_NO); |
157 | GNUNET_SERVER_client_drop (pos->client); | 161 | GNUNET_SERVER_client_drop (pos->client); |
158 | while (NULL != (pml = pos->pending)) | 162 | while (NULL != (pml = pos->pending_head)) |
159 | { | 163 | { |
160 | pos->pending = pml->next; | 164 | pos->pending_head = pml->next; |
161 | GNUNET_free (pml); | 165 | GNUNET_free (pml); |
162 | } | 166 | } |
163 | GNUNET_free (pos); | 167 | GNUNET_free (pos); |
@@ -179,10 +183,114 @@ void | |||
179 | GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, | 183 | GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, |
180 | struct GNUNET_SERVER_Client *client) | 184 | struct GNUNET_SERVER_Client *client) |
181 | { | 185 | { |
186 | struct ClientList *cl; | ||
187 | |||
188 | cl = GNUNET_malloc (sizeof (struct ClientList)); | ||
189 | cl->next = nc->clients; | ||
190 | cl->nc = nc; | ||
191 | cl->client = client; | ||
192 | nc->clients = cl; | ||
182 | } | 193 | } |
183 | 194 | ||
184 | 195 | ||
185 | /** | 196 | /** |
197 | * Function called to notify a client about the socket begin ready to | ||
198 | * queue more data. "buf" will be NULL and "size" zero if the socket | ||
199 | * was closed for writing in the meantime. | ||
200 | * | ||
201 | * @param cls the 'struct ClientList *' | ||
202 | * @param size number of bytes available in buf | ||
203 | * @param buf where the callee should write the message | ||
204 | * @return number of bytes written to buf | ||
205 | */ | ||
206 | static size_t | ||
207 | transmit_message (void *cls, | ||
208 | size_t size, | ||
209 | void *buf) | ||
210 | { | ||
211 | struct ClientList *cl = cls; | ||
212 | char *cbuf = buf; | ||
213 | struct PendingMessageList *pml; | ||
214 | uint16_t msize; | ||
215 | size_t ret; | ||
216 | |||
217 | cl->th = NULL; | ||
218 | if (buf == NULL) | ||
219 | { | ||
220 | /* 'cl' should be freed via disconnect notification shortly */ | ||
221 | return 0; | ||
222 | } | ||
223 | ret = 0; | ||
224 | while (cl->pending_head != NULL) | ||
225 | { | ||
226 | pml = cl->pending_head; | ||
227 | cl->pending_head = pml->next; | ||
228 | if (pml->next == NULL) | ||
229 | cl->pending_tail = NULL; | ||
230 | msize = ntohs (pml->msg->size); | ||
231 | if (size < msize) | ||
232 | break; | ||
233 | memcpy (&cbuf[ret], pml->msg, msize); | ||
234 | ret += msize; | ||
235 | size -= msize; | ||
236 | GNUNET_free (pml); | ||
237 | } | ||
238 | if (cl->pending_head != NULL) | ||
239 | cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client, | ||
240 | ntohs (cl->pending_head->msg->size), | ||
241 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
242 | &transmit_message, | ||
243 | cl); | ||
244 | return ret; | ||
245 | } | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Send a message to a particular client. | ||
250 | * | ||
251 | * @param nc context to modify | ||
252 | * @param client client to transmit to | ||
253 | * @param msg message to send | ||
254 | * @param can_drop can this message be dropped due to queue length limitations | ||
255 | */ | ||
256 | static void | ||
257 | do_unicast (struct GNUNET_SERVER_NotificationContext *nc, | ||
258 | struct ClientList *client, | ||
259 | const struct GNUNET_MessageHeader *msg, | ||
260 | int can_drop) | ||
261 | { | ||
262 | struct PendingMessageList *pml; | ||
263 | uint16_t size; | ||
264 | |||
265 | if ( (client->num_pending > nc->queue_length) && | ||
266 | (GNUNET_YES == can_drop) ) | ||
267 | return; /* drop! */ | ||
268 | if (client->num_pending > nc->queue_length) | ||
269 | { | ||
270 | /* FIXME: consider checking for other messages in the | ||
271 | queue that are 'droppable' */ | ||
272 | } | ||
273 | size = ntohs (msg->size); | ||
274 | pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size); | ||
275 | pml->msg = (const struct GNUNET_MessageHeader*) &pml[1]; | ||
276 | pml->can_drop = can_drop; | ||
277 | memcpy (&pml[1], msg, size); | ||
278 | /* append */ | ||
279 | if (client->pending_tail != NULL) | ||
280 | client->pending_tail->next = pml; | ||
281 | else | ||
282 | client->pending_head = pml; | ||
283 | client->pending_tail = pml; | ||
284 | if (client->th == NULL) | ||
285 | client->th = GNUNET_SERVER_notify_transmit_ready (client->client, | ||
286 | ntohs (client->pending_head->msg->size), | ||
287 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
288 | &transmit_message, | ||
289 | client); | ||
290 | } | ||
291 | |||
292 | |||
293 | /** | ||
186 | * Send a message to a particular client; must have | 294 | * Send a message to a particular client; must have |
187 | * already been added to the notification context. | 295 | * already been added to the notification context. |
188 | * | 296 | * |
@@ -197,6 +305,17 @@ GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationCon | |||
197 | const struct GNUNET_MessageHeader *msg, | 305 | const struct GNUNET_MessageHeader *msg, |
198 | int can_drop) | 306 | int can_drop) |
199 | { | 307 | { |
308 | struct ClientList *pos; | ||
309 | |||
310 | pos = nc->clients; | ||
311 | while (NULL != pos) | ||
312 | { | ||
313 | if (pos->client == client) | ||
314 | break; | ||
315 | pos = pos->next; | ||
316 | } | ||
317 | GNUNET_assert (pos != NULL); | ||
318 | do_unicast (nc, pos, msg, can_drop); | ||
200 | } | 319 | } |
201 | 320 | ||
202 | 321 | ||
@@ -212,6 +331,14 @@ GNUNET_SERVER_notification_context_broadcast (struct GNUNET_SERVER_NotificationC | |||
212 | const struct GNUNET_MessageHeader *msg, | 331 | const struct GNUNET_MessageHeader *msg, |
213 | int can_drop) | 332 | int can_drop) |
214 | { | 333 | { |
334 | struct ClientList *pos; | ||
335 | |||
336 | pos = nc->clients; | ||
337 | while (NULL != pos) | ||
338 | { | ||
339 | do_unicast (nc, pos, msg, can_drop); | ||
340 | pos = pos->next; | ||
341 | } | ||
215 | } | 342 | } |
216 | 343 | ||
217 | 344 | ||