/** * Queues a message in send queue for sending to the service * * @param client the client to whom the queued message has to be sent * @param msg the message to queue */ void GST_queue_message (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg) { struct MessageQueue *mq_entry; uint16_t type; uint16_t size; type = ntohs (msg->type); size = ntohs (msg->size); GNUNET_assert ((GNUNET_MESSAGE_TYPE_TESTBED_INIT <= type) && (GNUNET_MESSAGE_TYPE_TESTBED_MAX > type)); mq_entry = GNUNET_new (struct MessageQueue); mq_entry->msg = msg; mq_entry->client = client; GNUNET_SERVER_client_keep (client); LOG_DEBUG ("Queueing message of type %u, size %u for sending\n", type, ntohs (msg->size)); GNUNET_CONTAINER_DLL_insert_tail (mq_head, mq_tail, mq_entry); if (NULL == transmit_handle) transmit_handle = GNUNET_SERVER_notify_transmit_ready (client, size, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_ready_notify, NULL); }
/** * Transmit the given message to the client. * * @param client target of the message * @param msg message to transmit, will be freed! */ static void transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg) { struct TransmitCallbackContext *tcc; if (GNUNET_YES == cleaning_done) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Shutdown in progress, aborting transmission.\n")); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); return; } tcc = GNUNET_new (struct TransmitCallbackContext); tcc->msg = msg; tcc->client = client; if (NULL == (tcc->th = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_callback, tcc))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); GNUNET_free (tcc); return; } GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc); }
/** * Function called to notify a client about the connection begin ready to queue * more data. "buf" will be NULL and "size" zero if the connection was closed * for writing in the meantime. * * @param cls NULL * @param size number of bytes available in buf * @param buf where the callee should write the message * @return number of bytes written to buf */ static size_t transmit_ready_notify (void *cls, size_t size, void *buf) { struct MessageQueue *mq_entry; transmit_handle = NULL; mq_entry = mq_head; GNUNET_assert (NULL != mq_entry); if (0 == size) return 0; GNUNET_assert (ntohs (mq_entry->msg->size) <= size); size = ntohs (mq_entry->msg->size); memcpy (buf, mq_entry->msg, size); GNUNET_free (mq_entry->msg); GNUNET_SERVER_client_drop (mq_entry->client); GNUNET_CONTAINER_DLL_remove (mq_head, mq_tail, mq_entry); GNUNET_free (mq_entry); mq_entry = mq_head; if (NULL != mq_entry) transmit_handle = GNUNET_SERVER_notify_transmit_ready (mq_entry->client, ntohs (mq_entry->msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_ready_notify, NULL); return size; }
/** * Handler for TEST message. * * @param cls closure (refers to service) * @param client identification of the client * @param message the actual message */ static void handle_test (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { /* simply bounce message back to acknowledge */ if (NULL == GNUNET_SERVER_notify_transmit_ready (client, sizeof (struct GNUNET_MessageHeader), GNUNET_TIME_UNIT_FOREVER_REL, &write_test, client)) GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); }
/** * Handle LIST-message. * * @param cls closure (always NULL) * @param client identification of the client * @param message the actual message */ static void handle_list (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct GNUNET_ARM_ListResultMessage *msg; size_t string_list_size; size_t total_size; struct ServiceList *sl; uint16_t count; if (NULL == client) return; count = 0; string_list_size = 0; /* first count the running processes get their name's size */ for (sl = running_head; sl != NULL; sl = sl->next) { if (sl->proc != NULL) { string_list_size += strlen (sl->name); string_list_size += strlen (sl->binary); string_list_size += 4; count++; } } total_size = sizeof (struct GNUNET_ARM_ListResultMessage) + string_list_size; msg = GNUNET_malloc (total_size); msg->header.size = total_size; msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT; msg->count = count; char *pos = (char *)&msg[1]; for (sl = running_head; sl != NULL; sl = sl->next) { if (sl->proc != NULL) { size_t s = strlen (sl->name) + strlen (sl->binary) + 4; GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary); pos += s; } } GNUNET_SERVER_notify_transmit_ready (client, msg->header.size, GNUNET_TIME_UNIT_FOREVER_REL, &write_list_result, msg); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
static void server_client_send_impl (struct GNUNET_MQ_Handle *mq, const struct GNUNET_MessageHeader *msg, void *impl_state) { struct ServerClientSocketState *state = impl_state; GNUNET_assert (NULL != mq); GNUNET_assert (NULL != state); state->th = GNUNET_SERVER_notify_transmit_ready (state->client, ntohs (msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_queued, mq); }
/** * Execute a transmission context. If there is * an error in the transmission, the #GNUNET_SERVER_receive_done() * method will be called with an error code (#GNUNET_SYSERR), * otherwise with #GNUNET_OK. * * @param tc transmission context to use * @param timeout when to time out and abort the transmission */ void GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, struct GNUNET_TIME_Relative timeout) { tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total), timeout, &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } }
static void recv_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { GNUNET_assert (ok == 2); ok = 3; argclient = client; GNUNET_SERVER_client_keep (argclient); GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); GNUNET_assert (MY_TYPE == ntohs (message->type)); GNUNET_assert (NULL != GNUNET_SERVER_notify_transmit_ready (client, ntohs (message->size), TIMEOUT, &reply_msg, NULL)); }
/** * Function called to notify a client about the socket being ready to * queue more data. "buf" will be NULL and "size" zero if the socket * was closed for writing in the meantime. * * @param cls closure * @param size number of bytes available in @a buf * @param buf where the callee should write the message * @return number of bytes written to @a buf */ static size_t transmit_to_client_callback (void *cls, size_t size, void *buf) { struct TransportClient *tc = cls; struct ClientMessageQueueEntry *q; const struct GNUNET_MessageHeader *msg; char *cbuf; uint16_t msize; size_t tsize; tc->th = NULL; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission to client failed, closing connection.\n"); return 0; } cbuf = buf; tsize = 0; while (NULL != (q = tc->message_queue_head)) { msg = (const struct GNUNET_MessageHeader *) &q[1]; msize = ntohs (msg->size); if (msize + tsize > size) break; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting message of type %u to client %p.\n", ntohs (msg->type), tc); GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail, q); tc->message_count--; memcpy (&cbuf[tsize], msg, msize); GNUNET_free (q); tsize += msize; } if (NULL != q) { GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client_callback, tc); GNUNET_assert (NULL != tc->th); } return tsize; }
/** * Signal our client that we will start or stop the * service. * * @param client who is being signalled * @param name name of the service * @param result message type to send * @return NULL if it was not found */ static void signal_result (struct GNUNET_SERVER_Client *client, const char *name, enum GNUNET_ARM_ProcessStatus result) { enum GNUNET_ARM_ProcessStatus *res; if (NULL == client) return; /* FIXME: this is not super-clean yet... */ res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus)); *res = result; GNUNET_SERVER_notify_transmit_ready (client, sizeof (struct GNUNET_ARM_ResultMessage), GNUNET_TIME_UNIT_FOREVER_REL, &write_result, res); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
/** * Queue the given message for transmission to the given client * * @param tc target of the message * @param msg message to transmit * @param may_drop #GNUNET_YES if the message can be dropped */ static void unicast (struct TransportClient *tc, const struct GNUNET_MessageHeader *msg, int may_drop) { struct ClientMessageQueueEntry *q; uint16_t msize; if (NULL == msg) { GNUNET_break (0); return; } if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop)) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Dropping message of type %u and size %u, have %u/%u messages pending\n"), ntohs (msg->type), ntohs (msg->size), tc->message_count, MAX_PENDING); GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# messages dropped due to slow client"), 1, GNUNET_NO); return; } msize = ntohs (msg->size); GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); memcpy (&q[1], msg, msize); GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head, tc->message_queue_tail, q); tc->message_count++; if (NULL != tc->th) return; tc->th = GNUNET_SERVER_notify_transmit_ready (tc->client, msize, GNUNET_TIME_UNIT_FOREVER_REL, &transmit_to_client_callback, tc); GNUNET_assert (NULL != tc->th); }
/** * Callback that just bounces the message back to the sender. */ static void echo_cb (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct CopyContext *cc; struct GNUNET_MessageHeader *cpy; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving message from client, bouncing back\n"); GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); cc = GNUNET_new (struct CopyContext); cc->client = client; cpy = GNUNET_malloc (ntohs (message->size)); memcpy (cpy, message, ntohs (message->size)); cc->cpy = cpy; GNUNET_assert (NULL != GNUNET_SERVER_notify_transmit_ready (client, ntohs (message->size), GNUNET_TIME_UNIT_SECONDS, ©_msg, cc)); }
/** * Helper function for incremental transmission of the response. */ static size_t transmit_response (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_TransmitContext *tc = cls; size_t msize; if (NULL == buf) { GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); return 0; } if (tc->total - tc->off > size) msize = size; else msize = tc->total - tc->off; memcpy (buf, &tc->buf[tc->off], msize); tc->off += msize; if (tc->total == tc->off) { GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); GNUNET_SERVER_client_drop (tc->client); GNUNET_free_non_null (tc->buf); GNUNET_free (tc); } else { if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total - tc->off), GNUNET_TIME_absolute_get_remaining (tc->timeout), &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } } return msize; }
/** * Task run to check for messages that need to be sent to a client. * * @param client a ClientList, containing the client and any messages to be sent to it */ static void process_pending_messages (struct ClientList *client) { if ((client->pending_head == NULL) || (client->transmit_handle != NULL)) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Not asking for transmission to %p now: %s\n", client->client_handle, client->pending_head == NULL ? "no more messages" : "request already pending"); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Asking for transmission of %u bytes to client %p\n", ntohs (client->pending_head->msg->size), client->client_handle); client->transmit_handle = GNUNET_SERVER_notify_transmit_ready (client->client_handle, ntohs (client->pending_head-> msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &send_reply_to_client, client); }