#include "gnunet_time_lib.h"
+/**
+ * Entry in list of messages pending to be transmitted.
+ */
struct PendingMessageList
{
+ /**
+ * This is a linked list.
+ */
struct PendingMessageList *next;
+ /**
+ * Message to transmit (allocated at the end of this
+ * struct, do not free)
+ */
const struct GNUNET_MessageHeader *msg;
+ /**
+ * Can this message be dropped?
+ */
int can_drop;
};
+/**
+ * Lists of clients we manage for notifications.
+ */
struct ClientList
{
+ /**
+ * This is a linked list.
+ */
struct ClientList *next;
+ /**
+ * Overall context this client belongs to.
+ */
struct GNUNET_SERVER_NotificationContext *nc;
+ /**
+ * Handle to the client.
+ */
struct GNUNET_SERVER_Client *client;
+ /**
+ * Handle for pending transmission request to the client (or NULL).
+ */
struct GNUNET_CONNECTION_TransmitHandle *th;
+ /**
+ * Head of linked list of requests queued for transmission.
+ */
struct PendingMessageList *pending_head;
+ /**
+ * Tail of linked list of requests queued for transmission.
+ */
struct PendingMessageList *pending_tail;
+ /**
+ * Number of messages currently in the list.
+ */
unsigned int num_pending;
};
struct GNUNET_SERVER_NotificationContext
{
+ /**
+ * Server we do notifications for.
+ */
struct GNUNET_SERVER_Handle *server;
+ /**
+ * List of clients receiving notifications.
+ */
struct ClientList *clients;
+ /**
+ * Maximum number of optional messages to queue per client.
+ */
unsigned int queue_length;
};
+/**
+ * Client has disconnected, clean up.
+ *
+ * @param cls our 'struct GNUNET_SERVER_NotificationContext *'
+ * @param client handle of client that disconnected
+ */
static void
handle_client_disconnect (void *cls,
struct GNUNET_SERVER_Client *client)
struct ClientList *prev;
struct PendingMessageList *pml;
+ if (client == NULL)
+ {
+ nc->server = NULL;
+ return;
+ }
prev = NULL;
pos = nc->clients;
while (NULL != pos)
pos->pending_head = pml->next;
GNUNET_free (pml);
}
+ GNUNET_SERVER_client_drop (client);
+ if (pos->th != NULL)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
+ pos->th = NULL;
+ }
GNUNET_free (pos);
}
while (NULL != (pos = nc->clients))
{
nc->clients = pos->next;
- GNUNET_SERVER_receive_done (pos->client, GNUNET_NO);
GNUNET_SERVER_client_drop (pos->client);
+ GNUNET_SERVER_receive_done (pos->client, GNUNET_NO);
while (NULL != (pml = pos->pending_head))
{
pos->pending_head = pml->next;
}
GNUNET_free (pos);
}
- GNUNET_SERVER_disconnect_notify_cancel (nc->server,
- &handle_client_disconnect,
- nc);
+ if (nc->server != NULL)
+ GNUNET_SERVER_disconnect_notify_cancel (nc->server,
+ &handle_client_disconnect,
+ nc);
GNUNET_free (nc);
}
cl->next = nc->clients;
cl->nc = nc;
cl->client = client;
+ GNUNET_SERVER_client_keep (client);
nc->clients = cl;
}
ret += msize;
size -= msize;
GNUNET_free (pml);
+ cl->num_pending--;
}
if (cl->pending_head != NULL)
cl->th = GNUNET_SERVER_notify_transmit_ready (cl->client,
/* FIXME: consider checking for other messages in the
queue that are 'droppable' */
}
+ client->num_pending++;
size = ntohs (msg->size);
pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size);
pml->msg = (const struct GNUNET_MessageHeader*) &pml[1];