/** * 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; }
/** * Bob generates the response message to be sent to Alice. * * @param s the associated requesting session with Alice */ static void transmit_bobs_cryptodata_message (struct BobServiceSession *s) { struct EccBobCryptodataMessage *msg; struct GNUNET_MQ_Envelope *e; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending response to Alice\n"); e = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_SCALARPRODUCT_ECC_BOB_CRYPTODATA); msg->contained_element_count = htonl (2); if (NULL != s->prod_g_i_b_i) GNUNET_CRYPTO_ecc_point_to_bin (edc, s->prod_g_i_b_i, &msg->prod_g_i_b_i); if (NULL != s->prod_h_i_b_i) GNUNET_CRYPTO_ecc_point_to_bin (edc, s->prod_h_i_b_i, &msg->prod_h_i_b_i); GNUNET_MQ_notify_sent (e, &bob_cadet_done_cb, s); GNUNET_MQ_send (s->cadet->cadet_mq, e); }
static void test_mq (struct GNUNET_CLIENT_Connection *client) { struct GNUNET_MQ_Handle *mq; struct GNUNET_MQ_Envelope *mqm; /* FIXME: test handling responses */ mq = GNUNET_MQ_queue_for_connection_client (client, NULL, NULL, NULL); mqm = GNUNET_MQ_msg_header (MY_TYPE); GNUNET_MQ_send (mq, mqm); mqm = GNUNET_MQ_msg_header (MY_TYPE); GNUNET_MQ_notify_sent (mqm, send_trap_cb, NULL); GNUNET_MQ_send (mq, mqm); GNUNET_MQ_send_cancel (mqm); mqm = GNUNET_MQ_msg_header (MY_TYPE); GNUNET_MQ_notify_sent (mqm, send_cb, NULL); GNUNET_MQ_send (mq, mqm); }
/** * @brief Send a message to another peer. * * Keeps track about pending messages so they can be properly removed when the * peer is destroyed. * * @param peer receeiver of the message * @param ev envelope of the message * @param type type of the message */ void Peers_send_message (const struct GNUNET_PeerIdentity *peer, struct GNUNET_MQ_Envelope *ev, const char *type) { struct PendingMessage *pending_msg; struct GNUNET_MQ_Handle *mq; pending_msg = insert_pending_message (peer, ev, type); mq = get_mq (peer); GNUNET_MQ_notify_sent (ev, mq_notify_sent_cb, pending_msg); GNUNET_MQ_send (mq, ev); }
/** * Issue a check whether peer is live * * @param peer_ctx the context of the peer */ static void check_peer_live (struct PeerContext *peer_ctx) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Get informed about peer %s getting live\n", GNUNET_i2s (&peer_ctx->peer_id)); struct GNUNET_MQ_Handle *mq; struct GNUNET_MQ_Envelope *ev; ev = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_RPS_PP_CHECK_LIVE); peer_ctx->liveliness_check_pending = GNUNET_new (struct PendingMessage); peer_ctx->liveliness_check_pending->ev = ev; peer_ctx->liveliness_check_pending->peer_ctx = peer_ctx; peer_ctx->liveliness_check_pending->type = "Check liveliness"; mq = get_mq (&peer_ctx->peer_id); GNUNET_MQ_notify_sent (ev, mq_liveliness_check_successful, peer_ctx); GNUNET_MQ_send (mq, ev); }
/** * Store a new entry in the PEERSTORE. * Note that stored entries can be lost in some cases * such as power failure. * * @param h Handle to the PEERSTORE service * @param sub_system name of the sub system * @param peer Peer Identity * @param key entry key * @param value entry value BLOB * @param size size of @e value * @param expiry absolute time after which the entry is (possibly) deleted * @param options options specific to the storage operation * @param cont Continuation function after the store request is sent * @param cont_cls Closure for @a cont */ struct GNUNET_PEERSTORE_StoreContext * GNUNET_PEERSTORE_store (struct GNUNET_PEERSTORE_Handle *h, const char *sub_system, const struct GNUNET_PeerIdentity *peer, const char *key, const void *value, size_t size, struct GNUNET_TIME_Absolute expiry, enum GNUNET_PEERSTORE_StoreOption options, GNUNET_PEERSTORE_Continuation cont, void *cont_cls) { struct GNUNET_MQ_Envelope *ev; struct GNUNET_PEERSTORE_StoreContext *sc; LOG (GNUNET_ERROR_TYPE_DEBUG, "Storing value (size: %lu) for subsytem `%s', peer `%s', key `%s'\n", size, sub_system, GNUNET_i2s (peer), key); ev = PEERSTORE_create_record_mq_envelope (sub_system, peer, key, value, size, &expiry, options, GNUNET_MESSAGE_TYPE_PEERSTORE_STORE); sc = GNUNET_new (struct GNUNET_PEERSTORE_StoreContext); sc->sub_system = GNUNET_strdup (sub_system); sc->peer = *peer; sc->key = GNUNET_strdup (key); sc->value = GNUNET_memdup (value, size); sc->size = size; sc->expiry = expiry; sc->options = options; sc->cont = cont; sc->cont_cls = cont_cls; sc->h = h; GNUNET_CONTAINER_DLL_insert_tail (h->store_head, h->store_tail, sc); GNUNET_MQ_notify_sent (ev, &store_request_sent, sc); GNUNET_MQ_send (h->mq, ev); return sc; }
/** * 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); }
/** * Function to handle a hangup request message from the client * * @param cls the `struct Line` the hangup is for * @param msg the message from the client */ static void handle_client_hangup_message (void *cls, const struct ClientPhoneHangupMessage *msg) { struct Line *line = cls; struct GNUNET_MQ_Envelope *e; struct CadetPhoneHangupMessage *mhum; struct Channel *ch; for (ch = line->channel_head; NULL != ch; ch = ch->next) if (msg->cid == ch->cid) break; 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; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received HANGUP for channel %u which is in state %d\n", msg->cid, ch->status); switch (ch->status) { case CS_CALLEE_INIT: GNUNET_break (0); GNUNET_SERVICE_client_drop (line->client); return; case CS_CALLEE_RINGING: ch->status = CS_CALLEE_SHUTDOWN; break; case CS_CALLEE_CONNECTED: ch->status = CS_CALLEE_SHUTDOWN; break; case CS_CALLEE_SHUTDOWN: /* maybe the other peer closed asynchronously... */ GNUNET_SERVICE_client_continue (line->client); return; case CS_CALLER_CALLING: ch->status = CS_CALLER_SHUTDOWN; break; case CS_CALLER_CONNECTED: ch->status = CS_CALLER_SHUTDOWN; break; case CS_CALLER_SHUTDOWN: /* maybe the other peer closed asynchronously... */ GNUNET_SERVICE_client_continue (line->client); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending HANG_UP message via cadet\n"); e = GNUNET_MQ_msg (mhum, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_HANG_UP); GNUNET_MQ_notify_sent (e, &mq_done_finish_caller_shutdown, ch); GNUNET_MQ_send (ch->mq, e); GNUNET_SERVICE_client_continue (line->client); }
/** * Figure out when and how to transmit to the given peer. * * @param cls the `struct PeerPlan` */ static void schedule_peer_transmission (void *cls) { struct PeerPlan *pp = cls; struct GSF_RequestPlan *rp; struct GNUNET_TIME_Relative delay; if (NULL != pp->task) { pp->task = NULL; } else { GNUNET_assert (NULL != pp->env); pp->env = NULL; } /* move ready requests to priority queue */ while ((NULL != (rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap))) && (0 == GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission).rel_value_us)) { GNUNET_assert (rp == GNUNET_CONTAINER_heap_remove_root (pp->delay_heap)); rp->hn = GNUNET_CONTAINER_heap_insert (pp->priority_heap, rp, rp->priority); } if (0 == GNUNET_CONTAINER_heap_get_size (pp->priority_heap)) { /* priority heap (still) empty, check for delay... */ rp = GNUNET_CONTAINER_heap_peek (pp->delay_heap); if (NULL == rp) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No active requests for plan %p.\n", pp); return; /* both queues empty */ } delay = GNUNET_TIME_absolute_get_remaining (rp->earliest_transmission); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sleeping for %s before retrying requests on plan %p.\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), pp); GNUNET_STATISTICS_set (GSF_stats, gettext_noop ("# delay heap timeout (ms)"), delay.rel_value_us / 1000LL, GNUNET_NO); pp->task = GNUNET_SCHEDULER_add_delayed (delay, &schedule_peer_transmission, pp); return; } #if INSANE_STATISTICS GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query plans executed"), 1, GNUNET_NO); #endif /* process from priority heap */ rp = GNUNET_CONTAINER_heap_remove_root (pp->priority_heap); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing query plan %p\n", rp); GNUNET_assert (NULL != rp); rp->hn = NULL; rp->last_transmission = GNUNET_TIME_absolute_get (); rp->transmission_counter++; total_delay++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Executing plan %p executed %u times, planning retransmission\n", rp, rp->transmission_counter); GNUNET_assert (NULL == pp->env); pp->env = GSF_pending_request_get_message_ (get_latest (rp)); GNUNET_MQ_notify_sent (pp->env, &schedule_peer_transmission, pp); GSF_peer_transmit_ (pp->cp, GNUNET_YES, rp->priority, pp->env); GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# query messages sent to other peers"), 1, GNUNET_NO); plan (pp, rp); }
/** * Close the existing connection to PEERSTORE and reconnect. * * @param h handle to the service */ static void reconnect (struct GNUNET_PEERSTORE_Handle *h) { struct GNUNET_PEERSTORE_IterateContext *ic; struct GNUNET_PEERSTORE_IterateContext *next; GNUNET_PEERSTORE_Processor icb; void *icb_cls; struct GNUNET_PEERSTORE_StoreContext *sc; struct GNUNET_MQ_Envelope *ev; LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting...\n"); for (ic = h->iterate_head; NULL != ic; ic = next) { next = ic->next; if (GNUNET_YES == ic->iterating) { icb = ic->callback; icb_cls = ic->callback_cls; GNUNET_PEERSTORE_iterate_cancel (ic); if (NULL != icb) icb (icb_cls, NULL, "Iteration canceled due to reconnection"); } } if (NULL != h->mq) { GNUNET_MQ_destroy (h->mq); h->mq = NULL; } if (NULL != h->client) { GNUNET_CLIENT_disconnect (h->client); h->client = NULL; } h->client = GNUNET_CLIENT_connect ("peerstore", h->cfg); GNUNET_assert (NULL != h->client); h->mq = GNUNET_MQ_queue_for_connection_client (h->client, mq_handlers, &handle_client_error, h); LOG (GNUNET_ERROR_TYPE_DEBUG, "Resending pending requests after reconnect.\n"); if (NULL != h->watches) GNUNET_CONTAINER_multihashmap_iterate (h->watches, &rewatch_it, h); for (ic = h->iterate_head; NULL != ic; ic = ic->next) { ev = PEERSTORE_create_record_mq_envelope (ic->sub_system, &ic->peer, ic->key, NULL, 0, NULL, 0, GNUNET_MESSAGE_TYPE_PEERSTORE_ITERATE); GNUNET_MQ_send (h->mq, ev); ic->timeout_task = GNUNET_SCHEDULER_add_delayed (ic->timeout, &iterate_timeout, ic); } for (sc = h->store_head; NULL != sc; sc = sc->next) { ev = PEERSTORE_create_record_mq_envelope (sc->sub_system, &sc->peer, sc->key, sc->value, sc->size, &sc->expiry, sc->options, GNUNET_MESSAGE_TYPE_PEERSTORE_STORE); GNUNET_MQ_notify_sent (ev, &store_request_sent, sc); GNUNET_MQ_send (h->mq, ev); } }