/** * 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); }
/** * 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); }
/** * 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; }
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); }
/** * 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; }
/** * 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); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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); }
/** * 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; }
/** * 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; }
/** * 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); }