aboutsummaryrefslogtreecommitdiff
path: root/src/util/server_nc.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2010-01-22 14:20:31 +0000
committerChristian Grothoff <christian@grothoff.org>2010-01-22 14:20:31 +0000
commit0bcccf6577555ed605e12a02ee09ffa8595b8a51 (patch)
tree5ebcee438aa620a303649552cf9d547e848ddf29 /src/util/server_nc.c
parent1e83b104b323d90664e90af7a12166308ba6ee7a (diff)
downloadgnunet-0bcccf6577555ed605e12a02ee09ffa8595b8a51.tar.gz
gnunet-0bcccf6577555ed605e12a02ee09ffa8595b8a51.zip
finishing nc implementation
Diffstat (limited to 'src/util/server_nc.c')
-rw-r--r--src/util/server_nc.c137
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
179GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, 183GNUNET_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 */
206static size_t
207transmit_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 */
256static void
257do_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