Esempio n. 1
0
/**
 * 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);
}
Esempio n. 2
0
/**
 * 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);
}
Esempio n. 3
0
/**
 * 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;
}
Esempio n. 5
0
/**
 * 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);
}
Esempio n. 6
0
/**
 * 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;
}
Esempio n. 7
0
/**
 * 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));
}
Esempio n. 8
0
/**
 * 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);
}
Esempio n. 9
0
/**
 * 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;
}
Esempio n. 10
0
/**
 * 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;
}