/** * Request a list of running services. * * @param h handle to ARM * @param timeout how long to wait before failing for good * @param cont callback to invoke after request is sent or is not sent * @param cont_cls closure for callback */ void GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ServiceListCallback cont, void *cont_cls) { struct ARMControlMessage *cm; struct GNUNET_ARM_Message *msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting LIST from ARM service with timeout: %s\n", GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES)); cm = GNUNET_new (struct ARMControlMessage); cm->h = h; cm->list_cont = cont; cm->cont_cls = cont_cls; cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message)); msg->header.size = htons (sizeof (struct GNUNET_ARM_Message)); msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); msg->reserved = htonl (0); cm->msg = msg; GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, h->control_pending_tail, cm); cm->timeout_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (cm->timeout), &control_message_timeout, cm); trigger_next_request (h, GNUNET_NO); }
/** * Send a control message to the peer asking for transmission * of the message in the given peer record. * * @param pr peer to request transmission to */ static void request_next_transmission (struct PeerRecord *pr) { struct GNUNET_CORE_Handle *h = pr->ch; struct ControlMessage *cm; struct SendMessageRequest *smr; struct GNUNET_CORE_TransmitHandle *th; if (pr->timeout_task != GNUNET_SCHEDULER_NO_TASK) { GNUNET_SCHEDULER_cancel (pr->timeout_task); pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; } th = &pr->th; if (NULL == th->peer) { trigger_next_request (h, GNUNET_NO); return; } if (th->cm != NULL) return; /* already done */ GNUNET_assert (pr->prev == NULL); GNUNET_assert (pr->next == NULL); pr->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (th->timeout), &transmission_timeout, pr); cm = GNUNET_malloc (sizeof (struct ControlMessage) + sizeof (struct SendMessageRequest)); th->cm = cm; cm->th = th; smr = (struct SendMessageRequest *) &cm[1]; smr->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); smr->header.size = htons (sizeof (struct SendMessageRequest)); smr->priority = htonl ((uint32_t) th->priority); smr->deadline = GNUNET_TIME_absolute_hton (th->timeout); smr->peer = pr->peer; smr->reserved = htonl (0); smr->size = htons (th->msize); smr->smr_id = htons (th->smr_id = pr->smr_id_gen++); GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, h->control_pending_tail, cm); LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding SEND REQUEST for peer `%s' to message queue\n", GNUNET_i2s (&pr->peer)); trigger_next_request (h, GNUNET_NO); }
/** * Our current client connection went down. Clean it up * and try to reconnect! * * @param h our handle to the core service */ static void reconnect (struct GNUNET_CORE_Handle *h) { struct ControlMessage *cm; struct InitMessage *init; uint32_t opt; uint16_t msize; uint16_t *ts; unsigned int hpos; GNUNET_assert (NULL == h->client); GNUNET_assert (GNUNET_YES == h->currently_down); GNUNET_assert (NULL != h->cfg); h->client = GNUNET_CLIENT_connect ("core", h->cfg); if (NULL == h->client) { reconnect_later (h); return; } msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage); cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize); cm->cont = &init_done_task; cm->cont_cls = h; init = (struct InitMessage *) &cm[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT); init->header.size = htons (msize); opt = 0; if (h->inbound_notify != NULL) { if (h->inbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND; } if (h->outbound_notify != NULL) { if (h->outbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND; } LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service, monitoring messages of type %u\n", opt); init->options = htonl (opt); ts = (uint16_t *) & init[1]; for (hpos = 0; hpos < h->hcnt; hpos++) ts[hpos] = htons (h->handlers[hpos].type); GNUNET_CONTAINER_DLL_insert (h->control_pending_head, h->control_pending_tail, cm); trigger_next_request (h, GNUNET_YES); }
/** * Obtain statistics and/or change preferences for the given peer. * * @param h core handle * @param peer identifies the peer * @param amount reserve N bytes for receiving, negative * amounts can be used to undo a (recent) reservation; * @param preference increase incoming traffic share preference by this amount; * in the absence of "amount" reservations, we use this * preference value to assign proportional bandwidth shares * to all connected peers * @param info function to call with the resulting configuration information * @param info_cls closure for info * @return NULL on error */ struct GNUNET_ATS_InformationRequestContext * GNUNET_ATS_peer_change_preference (struct GNUNET_ATS_SchedulingHandle *h, const struct GNUNET_PeerIdentity *peer, int32_t amount, uint64_t preference, GNUNET_ATS_PeerConfigurationInfoCallback info, void *info_cls) { struct GNUNET_ATS_InformationRequestContext *irc; struct PeerRecord *pr; struct RequestInfoMessage *rim; struct ControlMessage *cm; pr = GNUNET_CONTAINER_multihashmap_get (h->peers, &peer->hashPubKey); if (NULL == pr) { /* attempt to change preference on peer that is not connected */ GNUNET_assert (0); return NULL; } if (pr->pcic != NULL) { /* second change before first one is done */ GNUNET_break (0); return NULL; } irc = GNUNET_malloc (sizeof (struct GNUNET_ATS_InformationRequestContext)); irc->h = h; irc->pr = pr; cm = GNUNET_malloc (sizeof (struct ControlMessage) + sizeof (struct RequestInfoMessage)); cm->cont = &change_preference_send_continuation; cm->cont_cls = irc; irc->cm = cm; rim = (struct RequestInfoMessage *) &cm[1]; rim->header.size = htons (sizeof (struct RequestInfoMessage)); rim->header.type = htons (GNUNET_MESSAGE_TYPE_ATS_REQUEST_INFO); rim->rim_id = htonl (pr->rim_id = h->rim_id_gen++); rim->reserved = htonl (0); rim->reserve_inbound = htonl (amount); rim->preference_change = GNUNET_htonll (preference); rim->peer = *peer; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Queueing CHANGE PREFERENCE request for peer `%s' with RIM %u\n", GNUNET_i2s (peer), (unsigned int) pr->rim_id); GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, h->control_pending_tail, cm); pr->pcic = info; pr->pcic_cls = info_cls; pr->pcic_ptr = irc; /* for free'ing irc */ if (NULL != h->client) trigger_next_request (h, GNUNET_NO); return irc; }
/** * Start or stop a service. * * @param h handle to ARM * @param service_name name of the service * @param timeout how long to wait before failing for good * @param cb callback to invoke when service is ready * @param cb_cls closure for callback * @param type type of the request */ static void change_service (struct GNUNET_ARM_Handle *h, const char *service_name, struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cb, void *cb_cls, uint16_t type) { struct ARMControlMessage *cm; size_t slen; struct GNUNET_ARM_Message *msg; slen = strlen (service_name) + 1; if (slen + sizeof (struct GNUNET_ARM_Message) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); if (cb != NULL) cb (cb_cls, GNUNET_ARM_REQUEST_TOO_LONG, NULL, 0); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting %s of service `%s'.\n", (GNUNET_MESSAGE_TYPE_ARM_START == type) ? "start" : "termination", service_name); cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); cm->h = h; cm->result_cont = cb; cm->cont_cls = cb_cls; cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); memcpy (&cm[1], service_name, slen); msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message) + slen); msg->header.size = htons (sizeof (struct GNUNET_ARM_Message) + slen); msg->header.type = htons (type); msg->reserved = htonl (0); memcpy (&msg[1], service_name, slen); cm->msg = msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Inserting a control message into the queue. Timeout is %s\n", GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (cm->timeout), GNUNET_NO)); GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, h->control_pending_tail, cm); cm->timeout_task_id = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining (cm->timeout), &control_message_timeout, cm); trigger_next_request (h, GNUNET_NO); }
/** * Connect to arm. * * @param h arm handle * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ static int reconnect_arm (struct GNUNET_ARM_Handle *h) { GNUNET_assert (NULL == h->client); GNUNET_assert (GNUNET_YES == h->currently_down); h->client = GNUNET_CLIENT_connect ("arm", h->cfg); if (NULL == h->client) { LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned NULL\n"); if (NULL != h->conn_status) h->conn_status (h->conn_status_cls, GNUNET_SYSERR); return GNUNET_SYSERR; } LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); trigger_next_request (h, GNUNET_YES); return GNUNET_OK; }
/** * The given request hit its timeout. Remove from the * doubly-linked list and call the respective continuation. * * @param cls the transmit handle of the request that timed out * @param tc context, can be NULL (!) */ static void transmission_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct PeerRecord *pr = cls; struct GNUNET_CORE_Handle *h = pr->ch; struct GNUNET_CORE_TransmitHandle *th; pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; if (GNUNET_SCHEDULER_NO_TASK != pr->ntr_task) { GNUNET_SCHEDULER_cancel (pr->ntr_task); pr->ntr_task = GNUNET_SCHEDULER_NO_TASK; } th = &pr->th; th->peer = NULL; if ((NULL != pr->prev) || (NULL != pr->next) || (pr == h->ready_peer_head)) { /* the request that was 'approved' by core was * canceled before it could be transmitted; remove * us from the 'ready' list */ GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); } if (NULL != th->cm) { /* we're currently in the control queue, remove */ GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, th->cm); GNUNET_free (th->cm); } LOG (GNUNET_ERROR_TYPE_DEBUG, "Signalling timeout of request for transmission to peer `%s' via CORE\n", GNUNET_i2s (&pr->peer)); trigger_next_request (h, GNUNET_NO); GNUNET_assert (0 == th->get_message (th->get_message_cls, 0, NULL)); }
/** * Handler for notification messages received from the core. * * @param cls our `struct GNUNET_CORE_Handle` * @param msg the message received from the core service */ static void main_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) { struct GNUNET_CORE_Handle *h = cls; const struct InitReplyMessage *m; const struct ConnectNotifyMessage *cnm; const struct DisconnectNotifyMessage *dnm; const struct NotifyTrafficMessage *ntm; const struct GNUNET_MessageHeader *em; const struct SendMessageReady *smr; const struct GNUNET_CORE_MessageHandler *mh; GNUNET_CORE_StartupCallback init; struct PeerRecord *pr; struct GNUNET_CORE_TransmitHandle *th; unsigned int hpos; int trigger; uint16_t msize; uint16_t et; if (NULL == msg) { LOG (GNUNET_ERROR_TYPE_INFO, _("Client was disconnected from core service, trying to reconnect.\n")); reconnect_later (h); return; } msize = ntohs (msg->size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Processing message of type %u and size %u from core service\n", ntohs (msg->type), msize); switch (ntohs (msg->type)) { case GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY: if (ntohs (msg->size) != sizeof (struct InitReplyMessage)) { GNUNET_break (0); reconnect_later (h); return; } m = (const struct InitReplyMessage *) msg; GNUNET_break (0 == ntohl (m->reserved)); /* start our message processing loop */ if (GNUNET_YES == h->currently_down) { h->currently_down = GNUNET_NO; trigger_next_request (h, GNUNET_NO); } h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; h->me = m->my_identity; if (NULL != (init = h->init)) { /* mark so we don't call init on reconnect */ h->init = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connected to core service of peer `%s'.\n", GNUNET_i2s (&h->me)); init (h->cls, &h->me); } else { LOG (GNUNET_ERROR_TYPE_DEBUG, "Successfully reconnected to core service.\n"); } /* fake 'connect to self' */ pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &h->me); GNUNET_assert (NULL == pr); pr = GNUNET_new (struct PeerRecord); pr->peer = h->me; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_put (h->peers, &h->me, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); if (NULL != h->connects) h->connects (h->cls, &h->me); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT: if (msize < sizeof (struct ConnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } cnm = (const struct ConnectNotifyMessage *) msg; if (msize != sizeof (struct ConnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about connection from `%s'.\n", GNUNET_i2s (&cnm->peer)); if (0 == memcmp (&h->me, &cnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connect to self!? */ GNUNET_break (0); return; } pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer); if (NULL != pr) { GNUNET_break (0); reconnect_later (h); return; } pr = GNUNET_new (struct PeerRecord); pr->peer = cnm->peer; pr->ch = h; GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multipeermap_put (h->peers, &cnm->peer, pr, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); if (NULL != h->connects) h->connects (h->cls, &cnm->peer); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT: if (msize != sizeof (struct DisconnectNotifyMessage)) { GNUNET_break (0); reconnect_later (h); return; } dnm = (const struct DisconnectNotifyMessage *) msg; if (0 == memcmp (&h->me, &dnm->peer, sizeof (struct GNUNET_PeerIdentity))) { /* connection to self!? */ GNUNET_break (0); return; } GNUNET_break (0 == ntohl (dnm->reserved)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about disconnect from `%s'.\n", GNUNET_i2s (&dnm->peer)); pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } trigger = ((pr->prev != NULL) || (pr->next != NULL) || (h->ready_peer_head == pr)); disconnect_and_free_peer_entry (h, &dnm->peer, pr); if (trigger) trigger_next_request (h, GNUNET_NO); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; if ((msize < sizeof (struct NotifyTrafficMessage) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } em = (const struct GNUNET_MessageHeader *) &ntm[1]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u and size %u from peer `%4s'\n", ntohs (em->type), ntohs (em->size), GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->inbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage))) { GNUNET_break (0); reconnect_later (h); return; } et = ntohs (em->type); for (hpos = 0; hpos < h->hcnt; hpos++) { mh = &h->handlers[hpos]; if (mh->type != et) continue; if ((mh->expected_size != ntohs (em->size)) && (mh->expected_size != 0)) { LOG (GNUNET_ERROR_TYPE_ERROR, "Unexpected message size %u for message of type %u from peer `%4s'\n", htons (em->size), mh->type, GNUNET_i2s (&ntm->peer)); GNUNET_break_op (0); continue; } pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } if (GNUNET_OK != h->handlers[hpos].callback (h->cls, &ntm->peer, em)) { /* error in processing, do not process other messages! */ break; } } if (NULL != h->inbound_notify) h->inbound_notify (h->cls, &ntm->peer, em); break; case GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND: if (msize < sizeof (struct NotifyTrafficMessage)) { GNUNET_break (0); reconnect_later (h); return; } ntm = (const struct NotifyTrafficMessage *) msg; if ((msize < sizeof (struct NotifyTrafficMessage) + sizeof (struct GNUNET_MessageHeader)) ) { GNUNET_break (0); reconnect_later (h); return; } em = (const struct GNUNET_MessageHeader *) &ntm[1]; LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission to `%s'.\n", GNUNET_i2s (&ntm->peer)); if ((GNUNET_NO == h->outbound_hdr_only) && (msize != ntohs (em->size) + sizeof (struct NotifyTrafficMessage))) { GNUNET_break (0); reconnect_later (h); return; } if (NULL == h->outbound_notify) { GNUNET_break (0); break; } h->outbound_notify (h->cls, &ntm->peer, em); break; case GNUNET_MESSAGE_TYPE_CORE_SEND_READY: if (msize != sizeof (struct SendMessageReady)) { GNUNET_break (0); reconnect_later (h); return; } smr = (const struct SendMessageReady *) msg; pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer); if (NULL == pr) { GNUNET_break (0); reconnect_later (h); return; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Received notification about transmission readiness to `%s'.\n", GNUNET_i2s (&smr->peer)); if (NULL == pr->th.peer) { /* request must have been cancelled between the original request * and the response from core, ignore core's readiness */ break; } th = &pr->th; if (ntohs (smr->smr_id) != th->smr_id) { /* READY message is for expired or cancelled message, * ignore! (we should have already sent another request) */ break; } if ((NULL != pr->prev) || (NULL != pr->next) || (h->ready_peer_head == pr)) { /* we should not already be on the ready list... */ GNUNET_break (0); reconnect_later (h); return; } GNUNET_CONTAINER_DLL_insert (h->ready_peer_head, h->ready_peer_tail, pr); trigger_next_request (h, GNUNET_NO); break; default: reconnect_later (h); return; } GNUNET_CLIENT_receive (h->client, &main_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); }
/** * Transmit the next message to the core service. * * @param cls closure with the `struct GNUNET_CORE_Handle` * @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_message (void *cls, size_t size, void *buf) { struct GNUNET_CORE_Handle *h = cls; struct ControlMessage *cm; struct GNUNET_CORE_TransmitHandle *th; struct PeerRecord *pr; struct SendMessage *sm; const struct GNUNET_MessageHeader *hdr; uint16_t msize; size_t ret; GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK); h->cth = NULL; if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, initiating reconnect\n"); reconnect_later (h); return 0; } /* first check for control messages */ if (NULL != (cm = h->control_pending_head)) { hdr = (const struct GNUNET_MessageHeader *) &cm[1]; msize = ntohs (hdr->size); if (size < msize) { trigger_next_request (h, GNUNET_NO); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting control message with %u bytes of type %u to core.\n", (unsigned int) msize, (unsigned int) ntohs (hdr->type)); memcpy (buf, hdr, msize); GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, cm); if (NULL != cm->th) cm->th->cm = NULL; if (NULL != cm->cont) cm->cont (cm->cont_cls, GNUNET_OK); GNUNET_free (cm); trigger_next_request (h, GNUNET_NO); return msize; } /* now check for 'ready' P2P messages */ if (NULL == (pr = h->ready_peer_head)) return 0; GNUNET_assert (NULL != pr->th.peer); th = &pr->th; if (size < th->msize + sizeof (struct SendMessage)) { trigger_next_request (h, GNUNET_NO); return 0; } GNUNET_CONTAINER_DLL_remove (h->ready_peer_head, h->ready_peer_tail, pr); th->peer = NULL; if (GNUNET_SCHEDULER_NO_TASK != pr->timeout_task) { GNUNET_SCHEDULER_cancel (pr->timeout_task); pr->timeout_task = GNUNET_SCHEDULER_NO_TASK; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting SEND request to `%s' with %u bytes.\n", GNUNET_i2s (&pr->peer), (unsigned int) th->msize); sm = (struct SendMessage *) buf; sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND); sm->priority = htonl ((uint32_t) th->priority); sm->deadline = GNUNET_TIME_absolute_hton (th->timeout); sm->peer = pr->peer; sm->cork = htonl ((uint32_t) th->cork); sm->reserved = htonl (0); ret = th->get_message (th->get_message_cls, size - sizeof (struct SendMessage), &sm[1]); LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting SEND request to `%s' yielded %u bytes.\n", GNUNET_i2s (&pr->peer), ret); if (0 == ret) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Size of clients message to peer %s is 0!\n", GNUNET_i2s (&pr->peer)); /* client decided to send nothing! */ request_next_transmission (pr); return 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Produced SEND message to core with %u bytes payload\n", (unsigned int) ret); GNUNET_assert (ret >= sizeof (struct GNUNET_MessageHeader)); if (ret + sizeof (struct SendMessage) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); request_next_transmission (pr); return 0; } ret += sizeof (struct SendMessage); sm->header.size = htons (ret); GNUNET_assert (ret <= size); request_next_transmission (pr); return ret; }
/** * Transmit the next message to the arm service. * * @param cls closure with the `struct GNUNET_ARM_Handle` * @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_arm_message (void *cls, size_t size, void *buf) { struct GNUNET_ARM_Handle *h = cls; struct ARMControlMessage *cm; struct GNUNET_ARM_Message *arm_msg; uint64_t request_id; int notify_connection; uint16_t msize; notify_connection = GNUNET_NO; LOG (GNUNET_ERROR_TYPE_DEBUG, "transmit_arm_message is running with %p buffer of size %lu. ARM is known to be %s\n", buf, size, h->currently_down ? "unconnected" : "connected"); GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task); h->cth = NULL; if ((GNUNET_YES == h->currently_down) && (NULL != buf)) { h->currently_down = GNUNET_NO; notify_connection = GNUNET_YES; h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; GNUNET_CLIENT_receive (h->client, &client_notify_handler, h, GNUNET_TIME_UNIT_FOREVER_REL); } if (NULL == buf) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmission failed, initiating reconnect\n"); reconnect_arm_later (h); return 0; } if (NULL == (cm = h->control_pending_head)) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue is empty, not sending anything\n"); msize = 0; goto end; } GNUNET_assert (NULL != cm->msg); msize = ntohs (cm->msg->header.size); if (size < msize) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Request is too big (%u < %u), not sending it\n", size, msize); trigger_next_request (h, GNUNET_NO); msize = 0; goto end; } arm_msg = cm->msg; if (0 == h->request_id_counter) h->request_id_counter++; request_id = h->request_id_counter++; LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting control message with %u bytes of type %u to arm with id %llu\n", (unsigned int) msize, (unsigned int) ntohs (cm->msg->header.type), request_id); arm_msg->reserved = htonl (0); arm_msg->request_id = GNUNET_htonll (request_id); memcpy (buf, cm->msg, msize); /* Otherwise we won't be able to find it later! */ arm_msg->request_id = request_id; GNUNET_CONTAINER_DLL_remove (h->control_pending_head, h->control_pending_tail, cm); GNUNET_CONTAINER_DLL_insert_tail (h->control_sent_head, h->control_sent_tail, cm); /* Don't free msg, keep it around (kind of wasteful, but then we don't * really have many messages to handle, and it'll be freed when it times * out anyway. */ trigger_next_request (h, GNUNET_NO); end: if ((GNUNET_YES == notify_connection) && (NULL != h->conn_status)) h->conn_status (h->conn_status_cls, GNUNET_YES); return msize; }