Ejemplo n.º 1
0
/**
 * Send a result code back to the client.
 *
 * @param client client that should receive the result code
 * @param result_code code to transmit
 * @param emsg error message to include (or NULL for none)
 */
static void
send_result_code (struct GNUNET_SERVICE_Client *client,
		  uint32_t result_code,
		  const char *emsg)
{
  struct ResultCodeMessage *rcm;
  struct GNUNET_MQ_Envelope *env;
  size_t elen;

  if (NULL == emsg)
    elen = 0;
  else
    elen = strlen (emsg) + 1;
  env = GNUNET_MQ_msg_extra (rcm,
                             elen,
                             GNUNET_MESSAGE_TYPE_IDENTITY_RESULT_CODE);
  rcm->result_code = htonl (result_code);
  if (0 < elen)
    GNUNET_memcpy (&rcm[1], emsg, elen);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Sending result %d (%s) to client\n",
              (int) result_code,
              emsg);
  GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env);
}
Ejemplo n.º 2
0
/**
 * Handler for START message from client, sends information
 * about all identities to the client immediately and
 * adds the client to the notification context for future
 * updates.
 *
 * @param cls unused
 * @param client who sent the message
 * @param message the message received
 */
static void
handle_start_message (void *cls,
                      const struct GNUNET_MessageHeader *message)
{
  struct UpdateMessage *ume;
  struct GNUNET_SERVICE_Client *client = cls;
  struct GNUNET_MQ_Envelope *env;
  struct Ego *ego;

  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Received START message from client\n");
  GNUNET_SERVICE_client_mark_monitor (client);
  GNUNET_SERVICE_client_disable_continue_warning (client);
  GNUNET_notification_context_add (nc,
                                   GNUNET_SERVICE_client_get_mq(client));
  for (ego = ego_head; NULL != ego; ego = ego->next)
  {
    env = create_update_message (ego);
    GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(client), env);
  }
  env = GNUNET_MQ_msg_extra (ume,
                             0,
                             GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
  ume->end_of_list = htons (GNUNET_YES);
  ume->name_len = htons (0);
  GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq(client), env);
  GNUNET_SERVICE_client_continue (client);
}
Ejemplo n.º 3
0
/**
 * Remove an element to the given set.  After the element has been
 * removed (in the sense of the request being transmitted to the set
 * service), @a cont will be called.  Multiple calls to
 * GNUNET_SET_remove_element() can be queued
 *
 * @param set set to remove element from
 * @param element element to remove from the set
 * @param cont continuation called after the element has been removed
 * @param cont_cls closure for @a cont
 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the
 *         set is invalid (e.g. the set service crashed)
 */
int
GNUNET_SET_remove_element (struct GNUNET_SET_Handle *set,
                           const struct GNUNET_SET_Element *element,
                           GNUNET_SET_Continuation cont,
                           void *cont_cls)
{
  struct GNUNET_MQ_Envelope *mqm;
  struct GNUNET_SET_ElementMessage *msg;

  if (GNUNET_YES == set->invalid)
  {
    if (NULL != cont)
      cont (cont_cls);
    return GNUNET_SYSERR;
  }
  mqm = GNUNET_MQ_msg_extra (msg,
                             element->size,
                             GNUNET_MESSAGE_TYPE_SET_REMOVE);
  msg->element_type = htons (element->element_type);
  memcpy (&msg[1],
          element->data,
          element->size);
  GNUNET_MQ_notify_sent (mqm,
                         cont, cont_cls);
  GNUNET_MQ_send (set->mq, mqm);
  return GNUNET_OK;
}
Ejemplo n.º 4
0
static void
send_message (struct GNUNET_MQ_Handle *mq,
	      int32_t num)
{
  struct GNUNET_MQ_Envelope *env;
  struct TestMessage *hdr;
  unsigned int s;

  GNUNET_assert (NULL != mq);
  GNUNET_assert (tr_n < TOTAL_MSGS);
  s = get_size (tr_n);
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
	      "Sending message %u of size %u\n",
	      tr_n,
	      s);
  env = GNUNET_MQ_msg_extra (hdr,
			     s - sizeof (struct TestMessage),
			     MTYPE);
  hdr->num = htonl (tr_n);
  memset (&hdr[1],
	  tr_n,
	  s - sizeof (struct TestMessage));
  tr_n++;
  GNUNET_SCHEDULER_cancel (err_task);
  err_task =
      GNUNET_SCHEDULER_add_delayed (TIMEOUT,
                                    &terminate_task_error,
				    NULL);
  total_bytes += s;
  GNUNET_MQ_send (mq,
		  env);
}
Ejemplo n.º 5
0
/**
 * Perform an asynchronous lookup operation on the GNS.
 *
 * @param handle handle to the GNS service
 * @param name the name to look up
 * @param zone the zone to start the resolution in
 * @param type the record type to look up
 * @param options local options for the lookup
 * @param shorten_zone_key the private key of the shorten zone (can be NULL)
 * @param proc processor to call on result
 * @param proc_cls closure for @a proc
 * @return handle to the get request
 */
struct GNUNET_GNS_LookupRequest*
GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
                   const char *name,
                   const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
                   uint32_t type,
                   enum GNUNET_GNS_LocalOptions options,
                   const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone_key,
                   GNUNET_GNS_LookupResultProcessor proc,
                   void *proc_cls)
{
    /* IPC to shorten gns names, return shorten_handle */
    struct LookupMessage *lookup_msg;
    struct GNUNET_GNS_LookupRequest *lr;
    size_t nlen;

    if (NULL == name)
    {
        GNUNET_break (0);
        return NULL;
    }
    LOG (GNUNET_ERROR_TYPE_DEBUG,
         "Trying to lookup `%s' in GNS\n",
         name);
    nlen = strlen (name) + 1;
    if (nlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*lr))
    {
        GNUNET_break (0);
        return NULL;
    }
    lr = GNUNET_new (struct GNUNET_GNS_LookupRequest);
    lr->gns_handle = handle;
    lr->lookup_proc = proc;
    lr->proc_cls = proc_cls;
    lr->r_id = handle->r_id_gen++;
    lr->env = GNUNET_MQ_msg_extra (lookup_msg,
                                   nlen,
                                   GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
    lookup_msg->id = htonl (lr->r_id);
    lookup_msg->options = htons ((uint16_t) options);
    lookup_msg->zone = *zone;
    lookup_msg->type = htonl (type);
    if (NULL != shorten_zone_key)
    {
        lookup_msg->have_key = htons (GNUNET_YES);
        lookup_msg->shorten_key = *shorten_zone_key;
    }
    GNUNET_memcpy (&lookup_msg[1],
                   name,
                   nlen);
    GNUNET_CONTAINER_DLL_insert (handle->lookup_head,
                                 handle->lookup_tail,
                                 lr);
    if (NULL != handle->mq)
        GNUNET_MQ_send_copy (handle->mq,
                             lr->env);
    return lr;
}
Ejemplo n.º 6
0
/**
 * Handler for client's SHOW_TUNNEL request.
 *
 * @param cls Identification of the client.
 * @param msg The actual message.
 */
static void
handle_show_tunnel (void *cls,
                    const struct GNUNET_CADET_LocalInfo *msg)
{
  struct CadetClient *c = cls;
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_CADET_LocalInfoTunnel *resp;
  struct CadetTunnel *t;
  struct CadetPeer *p;
  unsigned int ch_n;
  unsigned int c_n;

  p = GCP_get (&msg->peer,
               GNUNET_NO);
  t = GCP_get_tunnel (p,
                      GNUNET_NO);
  if (NULL == t)
  {
    /* We don't know the tunnel */
    struct GNUNET_MQ_Envelope *env;
    struct GNUNET_CADET_LocalInfoTunnel *warn;

    LOG (GNUNET_ERROR_TYPE_INFO,
         "Tunnel to %s unknown\n",
         GNUNET_i2s_full (&msg->peer));
    env = GNUNET_MQ_msg (warn,
                         GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
    warn->destination = msg->peer;
    GNUNET_MQ_send (c->mq,
                    env);
    GNUNET_SERVICE_client_continue (c->client);
    return;
  }

  /* Initialize context */
  ch_n = GCT_count_channels (t);
  c_n = GCT_count_any_connections (t);
  env = GNUNET_MQ_msg_extra (resp,
                             c_n * sizeof (struct GNUNET_CADET_ConnectionTunnelIdentifier) +
                             ch_n * sizeof (struct GCT_ChannelTunnelNumber),
                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_TUNNEL);
  resp->destination = msg->peer;
  /* Do not reorder! #iter_channel needs counters in HBO! */
  GCT_iterate_connections (t,
                           &iter_connection,
                           resp);
  GCT_iterate_channels (t,
                        &iter_channel,
                        resp);
  resp->connections = htonl (resp->connections);
  resp->channels = htonl (resp->channels);
  resp->cstate = htons (GCT_get_cstate (t));
  resp->estate = htons (GCT_get_estate (t));
  GNUNET_MQ_send (c->mq,
                  env);
  GNUNET_SERVICE_client_continue (c->client);
}
Ejemplo n.º 7
0
/**
 * Function to send a failure reponse for controller link operation
 *
 * @param client the client to send the message to
 * @param operation_id the operation ID of the controller link request
 * @param cfg the configuration with which the delegated controller is started.
 *          Can be NULL if the delegated controller is not started but just
 *          linked to.
 * @param emsg set to an error message explaining why the controller link
 *          failed.  Setting this to NULL signifies success.  !This should be
 *          NULL if cfg is set!
 */
static void
send_controller_link_response (struct GNUNET_SERVICE_Client *client,
                               uint64_t operation_id,
                               const struct GNUNET_CONFIGURATION_Handle *cfg,
                               const char *emsg)
{
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_TESTBED_ControllerLinkResponse *msg;
  char *xconfig;
  size_t config_size;
  size_t xconfig_size;
  uint16_t msize;

  GNUNET_assert ((NULL == cfg) || (NULL == emsg));
  xconfig = NULL;
  xconfig_size = 0;
  config_size = 0;
  msize = 0;
  if (NULL != cfg)
  {
    xconfig = GNUNET_TESTBED_compress_cfg_ (cfg,
                                            &config_size,
                                            &xconfig_size);
    msize += xconfig_size;
  }
  if (NULL != emsg)
    msize += strlen (emsg);
  env = GNUNET_MQ_msg_extra (msg,
                             msize,
                             GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS_RESULT);
  if (NULL == emsg)
    msg->success = htons (GNUNET_YES);
  msg->operation_id = GNUNET_htonll (operation_id);
  msg->config_size = htons ((uint16_t) config_size);
  if (NULL != xconfig)
  {
    GNUNET_memcpy (&msg[1],
                   xconfig,
                   xconfig_size);
    GNUNET_free (xconfig);
  }
  if (NULL != emsg)
    GNUNET_memcpy (&msg[1],
                   emsg,
                   strlen (emsg));
  GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
                  env);
}
/**
 * Sends an already built message on a tunnel, encrypting it and
 * choosing the best connection if not provided.
 *
 * @param message Message to send. Function modifies it.
 * @param t Tunnel on which this message is transmitted.
 * @param cont Continuation to call once message is really sent.
 * @param cont_cls Closure for @c cont.
 * @return Handle to cancel message. NULL if @c cont is NULL.
 */
struct CadetTunnelQueueEntry *
GCT_send (struct CadetTunnel *t,
          const struct GNUNET_MessageHeader *message,
          GNUNET_SCHEDULER_TaskCallback cont,
          void *cont_cls)
{
  struct CadetTunnelQueueEntry *tq;
  uint16_t payload_size;
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_CADET_Encrypted *ax_msg;

  /* FIXME: what about KX not yet being ready? (see "is_ready()" check in old code!) */

  payload_size = ntohs (message->size);
  env = GNUNET_MQ_msg_extra (ax_msg,
                             payload_size,
                             GNUNET_MESSAGE_TYPE_CADET_ENCRYPTED);
  t_ax_encrypt (t,
                &ax_msg[1],
                message,
                payload_size);
  ax_msg->Ns = htonl (t->ax.Ns++);
  ax_msg->PNs = htonl (t->ax.PNs);
  GNUNET_CRYPTO_ecdhe_key_get_public (t->ax.DHRs,
                                      &ax_msg->DHRs);
  t_h_encrypt (t,
               ax_msg);
  t_hmac (&ax_msg->Ns,
          AX_HEADER_SIZE + payload_size,
          0,
          &t->ax.HKs,
          &ax_msg->hmac);
  // ax_msg->pid = htonl (GCC_get_pid (c, fwd));  // FIXME: connection flow-control not (re)implemented yet!

  tq = GNUNET_malloc (sizeof (*tq));
  tq->t = t;
  tq->env = env;
  tq->cid = &ax_msg->cid;
  tq->cont = cont;
  tq->cont_cls = cont_cls;
  GNUNET_CONTAINER_DLL_insert_tail (t->tq_head,
                                    t->tq_tail,
                                    tq);
  trigger_transmissions (t);
  return tq;
}
Ejemplo n.º 9
0
/**
 * Create an update message with information about the current state of an ego.
 *
 * @param ego ego to create message for
 * @return corresponding update message
 */
static struct GNUNET_MQ_Envelope *
create_update_message (struct Ego *ego)
{
  struct UpdateMessage *um;
  struct GNUNET_MQ_Envelope *env;
  size_t name_len;

  name_len = (NULL == ego->identifier) ? 0 : (strlen (ego->identifier) + 1);
  env = GNUNET_MQ_msg_extra (um,
                             name_len,
                             GNUNET_MESSAGE_TYPE_IDENTITY_UPDATE);
  um->name_len = htons (name_len);
  um->end_of_list = htons (GNUNET_NO);
  um->private_key = *ego->pk;
  GNUNET_memcpy (&um[1], ego->identifier, name_len);
  return env;
}
Ejemplo n.º 10
0
/**
 * Creates a MQ envelope for a single record
 *
 * @param sub_system sub system string
 * @param peer Peer identity (can be NULL)
 * @param key record key string (can be NULL)
 * @param value record value BLOB (can be NULL)
 * @param value_size record value size in bytes (set to 0 if value is NULL)
 * @param expiry time after which the record expires
 * @param options options specific to the storage operation
 * @param msg_type message type to be set in header
 * @return pointer to record message struct
 */
struct GNUNET_MQ_Envelope *
PEERSTORE_create_record_mq_envelope (const char *sub_system,
                                     const struct GNUNET_PeerIdentity *peer,
                                     const char *key,
                                     const void *value,
                                     size_t value_size,
                                     struct GNUNET_TIME_Absolute *expiry,
                                     enum GNUNET_PEERSTORE_StoreOption options,
                                     uint16_t msg_type)
{
  struct StoreRecordMessage *srm;
  struct GNUNET_MQ_Envelope *ev;
  size_t ss_size;
  size_t key_size;
  size_t msg_size;
  void *dummy;

  GNUNET_assert (NULL != sub_system);
  ss_size = strlen (sub_system) + 1;
  if (NULL == key)
    key_size = 0;
  else
    key_size = strlen (key) + 1;
  msg_size = ss_size + key_size + value_size;
  ev = GNUNET_MQ_msg_extra (srm, msg_size, msg_type);
  srm->key_size = htons (key_size);
  if (NULL != expiry)
    srm->expiry = *expiry;
  if (NULL == peer)
    srm->peer_set = htons (GNUNET_NO);
  else
  {
    srm->peer_set = htons (GNUNET_YES);
    srm->peer = *peer;
  }
  srm->sub_system_size = htons (ss_size);
  srm->value_size = htons (value_size);
  srm->options = htonl (options);
  dummy = &srm[1];
  GNUNET_memcpy (dummy, sub_system, ss_size);
  dummy += ss_size;
  GNUNET_memcpy (dummy, key, key_size);
  dummy += key_size;
  GNUNET_memcpy (dummy, value, value_size);
  return ev;
}
Ejemplo n.º 11
0
/**
 * Create a set default message with information about the current state of an ego.
 *
 * @param ego ego to create message for
 * @param servicename name of the service to provide in the message
 * @return corresponding set default message
 */
static struct GNUNET_MQ_Envelope *
create_set_default_message (struct Ego *ego,
                            const char *servicename)
{
  struct SetDefaultMessage *sdm;
  struct GNUNET_MQ_Envelope *env;
  size_t name_len;

  name_len = (NULL == servicename) ? 0 : (strlen (servicename) + 1);
  env = GNUNET_MQ_msg_extra (sdm,
                             name_len,
                             GNUNET_MESSAGE_TYPE_IDENTITY_SET_DEFAULT);
  sdm->name_len = htons (name_len);
  sdm->reserved = htons (0);
  sdm->private_key = *ego->pk;
  GNUNET_memcpy (&sdm[1], servicename, name_len);
  return env;
}
Ejemplo n.º 12
0
/**
 * Generate and transmit the `struct AddressAddMessage` for the given
 * address record.
 *
 * @param sh the scheduling handle to use for transmission
 * @param ar the address to inform the ATS service about
 */
static void
send_add_address_message (struct GNUNET_ATS_SchedulingHandle *sh,
                          const struct GNUNET_ATS_AddressRecord *ar)
{
  struct GNUNET_MQ_Envelope *ev;
  struct AddressAddMessage *m;
  char *pm;
  size_t namelen;
  size_t msize;

  if (NULL == sh->mq)
    return; /* disconnected, skip for now */
  GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != ar->properties.scope);
  namelen = strlen (ar->address->transport_name) + 1;
  msize = ar->address->address_length + namelen;
  ev = GNUNET_MQ_msg_extra (m, msize, GNUNET_MESSAGE_TYPE_ATS_ADDRESS_ADD);
  m->peer = ar->address->peer;
  m->address_length = htons (ar->address->address_length);
  m->address_local_info = htonl ((uint32_t) ar->address->local_info);
  m->plugin_name_length = htons (namelen);
  m->session_id = htonl (ar->slot);
  m->properties = ar->properties;

  LOG (GNUNET_ERROR_TYPE_DEBUG,
       "Adding address for peer `%s', plugin `%s', session %p slot %u\n",
       GNUNET_i2s (&ar->address->peer),
       ar->address->transport_name,
       ar->session,
       ar->slot);
  pm = (char *) &m[1];
  memcpy (pm,
          ar->address->address,
          ar->address->address_length);
  if (NULL != ar->address->transport_name)
    memcpy (&pm[ar->address->address_length],
            ar->address->transport_name,
            namelen);
  GNUNET_MQ_send (sh->mq, ev);
}
Ejemplo n.º 13
0
/**
 * Function to handle an audio message incoming over cadet
 *
 * @param cls closure, NULL
 * @param channel the channel over which the message arrived
 * @param channel_ctx the channel context, can be NULL
 *                    or point to the `struct Channel`
 * @param message the incoming message
 * @return #GNUNET_OK
 */
static int
handle_cadet_audio_message (void *cls,
                            struct GNUNET_CADET_Channel *channel,
                            void **channel_ctx,
                            const struct GNUNET_MessageHeader *message)
{
  struct Channel *ch = *channel_ctx;
  const struct CadetAudioMessage *msg;
  size_t msize = ntohs (message->size) - sizeof (struct CadetAudioMessage);
  struct GNUNET_MQ_Envelope *env;
  struct ClientAudioMessage *cam;

  msg = (const struct CadetAudioMessage *) message;
  GNUNET_CADET_receive_done (channel);
  if ( (GNUNET_YES == ch->suspended_local) ||
       (GNUNET_YES == ch->suspended_remote) )
  {
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Received %u bytes of AUDIO data on suspended channel CID %u; dropping\n",
                (unsigned int) msize,
                ch->cid);
    return GNUNET_OK;
  }
  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
              "Forwarding %u bytes of AUDIO data to client CID %u\n",
              (unsigned int) msize,
              ch->cid);
  env = GNUNET_MQ_msg_extra (cam,
                             msize,
                             GNUNET_MESSAGE_TYPE_CONVERSATION_CS_AUDIO);
  cam->cid = ch->cid;
  GNUNET_memcpy (&cam[1],
                 &msg[1],
                 msize);
  GNUNET_MQ_send (ch->line->mq,
                  env);
  return GNUNET_OK;
}
Ejemplo n.º 14
0
/**
 * Iterator over all paths of a peer to build an InfoPeer message.
 * Message contains blocks of peers, first not included.
 *
 * @param cls message queue for transmission
 * @param path Path itself
 * @param off offset of the peer on @a path
 * @return #GNUNET_YES if should keep iterating.
 *         #GNUNET_NO otherwise.
 */
static int
path_info_iterator (void *cls,
                    struct CadetPeerPath *path,
                    unsigned int off)
{
  struct GNUNET_MQ_Handle *mq = cls;
  struct GNUNET_MQ_Envelope *env;
  struct GNUNET_MessageHeader *resp;
  struct GNUNET_PeerIdentity *id;
  uint16_t path_size;
  unsigned int i;
  unsigned int path_length;

  path_length = GCPP_get_length (path);
  path_size = sizeof (struct GNUNET_PeerIdentity) * (path_length - 1);
  if (sizeof (*resp) + path_size > UINT16_MAX)
  {
    LOG (GNUNET_ERROR_TYPE_WARNING,
         "Path of %u entries is too long for info message\n",
         path_length);
    return GNUNET_YES;
  }
  env = GNUNET_MQ_msg_extra (resp,
                             path_size,
                             GNUNET_MESSAGE_TYPE_CADET_LOCAL_INFO_PEER);
  id = (struct GNUNET_PeerIdentity *) &resp[1];

  /* Don't copy first peer.  First peer is always the local one.  Last
   * peer is always the destination (leave as 0, EOL).
   */
  for (i = 0; i < off; i++)
    id[i] = *GCP_get_id (GCPP_get_peer_at_offset (path,
                                                  i + 1));
  GNUNET_MQ_send (mq,
                  env);
  return GNUNET_YES;
}
Ejemplo n.º 15
0
/**
 * Function to handle audio data from the client
 *
 * @param cls the `struct Line` the message is about
 * @param msg the message from the client
 */
static void
handle_client_audio_message (void *cls,
                             const struct ClientAudioMessage *msg)
{
  struct Line *line = cls;
  struct ClientAudioMessage *mam;
  struct Channel *ch;
  size_t size;

  size = ntohs (msg->header.size) - sizeof (struct ClientAudioMessage);
  ch = find_channel_by_line (line,
                             msg->cid);
  if (NULL == ch)
  {
    /* could have been destroyed asynchronously, ignore message */
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Channel %u not found\n",
                msg->cid);
    GNUNET_SERVICE_client_continue (line->client);
    return;
  }

  switch (ch->status)
  {
  case CS_CALLEE_INIT:
  case CS_CALLEE_RINGING:
  case CS_CALLER_CALLING:
    GNUNET_break (0);
    GNUNET_SERVICE_client_drop (line->client);
    return;
  case CS_CALLEE_CONNECTED:
  case CS_CALLER_CONNECTED:
    /* common case, handled below */
    break;
  case CS_CALLEE_SHUTDOWN:
  case CS_CALLER_SHUTDOWN:
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
                "Cadet audio channel in shutdown; audio data dropped\n");
    GNUNET_SERVICE_client_continue (line->client);
    return;
  }
  if (GNUNET_YES == ch->suspended_local)
  {
    GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
                "This channel is suspended locally\n");
    GNUNET_SERVICE_client_drop (line->client);
    return;
  }
  if (NULL != ch->env)
  {
    /* NOTE: we may want to not do this and instead combine the data */
    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
                "Bandwidth insufficient; dropping previous audio data segment\n");
    GNUNET_MQ_send_cancel (ch->env);
    ch->env = NULL;
  }

  ch->env = GNUNET_MQ_msg_extra (mam,
                                 size,
                                 GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_AUDIO);
  GNUNET_memcpy (&mam[1],
                 &msg[1],
                 size);
  /* FIXME: set options for unreliable transmission */
  GNUNET_MQ_notify_sent (ch->env,
                         &channel_audio_sent_notify,
                         ch);
  GNUNET_MQ_send (ch->mq,
                  ch->env);
  GNUNET_SERVICE_client_continue (line->client);
}