예제 #1
0
/**
 * 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);
}
예제 #3
0
/**
 * 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;
}
예제 #4
0
파일: service.c 프로젝트: tg-x/gnunet
/**
 * 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);
}
예제 #5
0
/**
 * 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);
}
예제 #6
0
파일: mq.c 프로젝트: tg-x/gnunet
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);
}
예제 #7
0
/**
 * 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);
  }
}
예제 #8
0
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;
}
예제 #10
0
/**
 * 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);
}
예제 #12
0
/**
 * 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,
                                                      &copy_msg, cc));
}
예제 #13
0
/**
 * 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);
}