/** * Output information of validation entries to the given client. * * @param cls the 'struct IterationContext' * @param peer identity of the neighbour * @param address the address * @param last_validation point in time when last validation was performed * @param valid_until point in time how long address is valid * @param next_validation point in time when next validation will be performed * @param state state of validation notification */ static void send_validation_information (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute last_validation, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute next_validation, enum GNUNET_TRANSPORT_ValidationState state) { struct IterationContext *pc = cls; struct ValidationIterateResponseMessage *msg; if ( (GNUNET_YES == pc->all) || (0 == memcmp (peer, &pc->id, sizeof (pc->id))) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending information about for validation entry for peer `%s' using address `%s'\n", GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "<none>"); msg = compose_validation_iterate_response_message (peer, address); msg->last_validation = GNUNET_TIME_absolute_hton(last_validation); msg->valid_until = GNUNET_TIME_absolute_hton(valid_until); msg->next_validation = GNUNET_TIME_absolute_hton(next_validation); msg->state = htonl ((uint32_t) state); GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header); GNUNET_free (msg); } }
static size_t node_experiment_start_cb (void *cls, size_t bufsize, void *buf) { struct NodeComCtx *e_ctx = cls; struct GED_start_message *msg; size_t name_len; size_t size; if (NULL == buf) return 0; name_len = strlen(e_ctx->e->name) + 1; size = sizeof (struct GED_start_message) + name_len; msg = GNUNET_malloc (size); msg->header.size = htons (size); msg->header.type = htons (GNUNET_MESSAGE_TYPE_EXPERIMENTATION_START); msg->issuer = e_ctx->e->issuer; msg->version_nbo = GNUNET_TIME_absolute_hton(e_ctx->e->version); msg->len_name = htonl (name_len); memcpy (&msg[1], e_ctx->e->name, name_len); memcpy (buf, msg, size); GNUNET_free (msg); return size; }
/** * Broadcast the new active address to all clients monitoring the peer. * * @param peer peer this update is about (never NULL) * @param address address, NULL on disconnect * @param state the current state of the peer * @param state_timeout the time out for the state */ void GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, enum GNUNET_TRANSPORT_PeerState state, struct GNUNET_TIME_Absolute state_timeout) { struct PeerIterateResponseMessage *msg; struct MonitoringClient *mc; static struct GNUNET_PeerIdentity all_zeros; msg = compose_address_iterate_response_message (peer, address); msg->state = htonl (state); msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout); mc = peer_monitoring_clients_head; while (mc != NULL) { if ((0 == memcmp (&mc->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) || (0 == memcmp (&mc->peer, peer, sizeof (struct GNUNET_PeerIdentity)))) { GNUNET_SERVER_notification_context_unicast (peer_nc, mc->client, &msg->header, GNUNET_NO); } mc = mc->next; } GNUNET_free (msg); }
/** * Setup a flood message in our history array at the given * slot offset for the given timestamp. * * @param slot index to use * @param ts timestamp to use */ static void setup_flood_message (unsigned int slot, struct GNUNET_TIME_Absolute ts) { struct GNUNET_NSE_FloodMessage *fm; uint32_t matching_bits; matching_bits = get_matching_bits (ts, &my_identity); fm = &size_estimate_messages[slot]; fm->header.size = htons (sizeof (struct GNUNET_NSE_FloodMessage)); fm->header.type = htons (GNUNET_MESSAGE_TYPE_NSE_P2P_FLOOD); fm->hop_count = htonl (0); fm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_NSE_SEND); fm->purpose.size = htonl (sizeof (struct GNUNET_NSE_FloodMessage) - sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_EddsaSignature)); fm->matching_bits = htonl (matching_bits); fm->timestamp = GNUNET_TIME_absolute_hton (ts); fm->origin = my_identity; fm->proof_of_work = my_proof; if (nse_work_required > 0) GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (my_private_key, &fm->purpose, &fm->signature)); else memset (&fm->signature, 0, sizeof (fm->signature)); }
/** * Output information of neighbours to the given client. * * @param cls the 'struct PeerIterationContext' * @param peer identity of the neighbour * @param address the address * @param state current state this peer is in * @param state_timeout timeout for the current state of the peer * @param bandwidth_in inbound quota in NBO * @param bandwidth_out outbound quota in NBO */ static void send_peer_information (void *cls, const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, enum GNUNET_TRANSPORT_PeerState state, struct GNUNET_TIME_Absolute state_timeout, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) { struct IterationContext *pc = cls; struct PeerIterateResponseMessage *msg; if ( (GNUNET_YES == pc->all) || (0 == memcmp (peer, &pc->id, sizeof (pc->id))) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending information about `%s' using address `%s' in state `%s'\n", GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "<none>", GNUNET_TRANSPORT_ps2s (state)); msg = compose_address_iterate_response_message (peer, address); msg->state = htonl (state); msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout); GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header); GNUNET_free (msg); } }
/** * Perform a PUT operation storing data in the DHT. FIXME: we should * change the protocol to get a confirmation for the PUT from the DHT * and call 'cont' only after getting the confirmation; otherwise, the * client has no good way of telling if the 'PUT' message actually got * to the DHT service! * * @param handle handle to DHT service * @param key the key to store under * @param desired_replication_level estimate of how many * nearest peers this request should reach * @param options routing options for this message * @param type type of the value * @param size number of bytes in data; must be less than 64k * @param data the data to store * @param exp desired expiration time for the value * @param timeout how long to wait for transmission of this request * @param cont continuation to call when done (transmitting request to service) * You must not call #GNUNET_DHT_disconnect in this continuation * @param cont_cls closure for @a cont */ struct GNUNET_DHT_PutHandle * GNUNET_DHT_put (struct GNUNET_DHT_Handle *handle, const struct GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, enum GNUNET_BLOCK_Type type, size_t size, const void *data, struct GNUNET_TIME_Absolute exp, struct GNUNET_TIME_Relative timeout, GNUNET_DHT_PutContinuation cont, void *cont_cls) { struct GNUNET_DHT_ClientPutMessage *put_msg; size_t msize; struct PendingMessage *pending; struct GNUNET_DHT_PutHandle *ph; msize = sizeof (struct GNUNET_DHT_ClientPutMessage) + size; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return NULL; } ph = GNUNET_new (struct GNUNET_DHT_PutHandle); ph->dht_handle = handle; ph->timeout_task = GNUNET_SCHEDULER_add_delayed (timeout, &timeout_put_request, ph); ph->cont = cont; ph->cont_cls = cont_cls; ph->unique_id = ++handle->uid_gen; pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); ph->pending = pending; put_msg = (struct GNUNET_DHT_ClientPutMessage *) &pending[1]; pending->msg = &put_msg->header; pending->handle = handle; pending->cont = &mark_put_message_gone; pending->cont_cls = ph; pending->free_on_send = GNUNET_YES; put_msg->header.size = htons (msize); put_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_PUT); put_msg->type = htonl (type); put_msg->options = htonl ((uint32_t) options); put_msg->desired_replication_level = htonl (desired_replication_level); put_msg->unique_id = ph->unique_id; put_msg->expiration = GNUNET_TIME_absolute_hton (exp); put_msg->key = *key; memcpy (&put_msg[1], data, size); GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; GNUNET_CONTAINER_DLL_insert_tail (handle->put_head, handle->put_tail, ph); process_pending_messages (handle); return ph; }
/** * Process a datum that was stored in the datastore. * * @param cls closure with the struct StreamClient which sent the query * @param key key for the content * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param expiration expiration time for the content * @param uid unique identifier for the datum; * maybe 0 if no unique identifier is available */ static void handle_datastore_reply (void *cls, const struct GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid) { struct StreamClient *sc = cls; size_t msize = size + sizeof (struct StreamReplyMessage); char buf[msize] GNUNET_ALIGN; struct StreamReplyMessage *srm = (struct StreamReplyMessage *) buf; sc->qe = NULL; if (GNUNET_BLOCK_TYPE_FS_ONDEMAND == type) { if (GNUNET_OK != GNUNET_FS_handle_on_demand_block (key, size, data, type, priority, anonymity, expiration, uid, &handle_datastore_reply, sc)) { continue_reading (sc); } return; } if (msize > GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_break (0); continue_reading (sc); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting transmission of %u byte reply via stream\n", (unsigned int) size); srm->header.size = htons ((uint16_t) msize); srm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_STREAM_REPLY); srm->type = htonl (type); srm->expiration = GNUNET_TIME_absolute_hton (expiration); memcpy (&srm[1], data, size); sc->reply_size = msize; sc->wh = GNUNET_STREAM_write (sc->socket, buf, msize, GNUNET_TIME_UNIT_FOREVER_REL, &write_continuation, sc); if (NULL == sc->wh) { terminate_stream (sc); return; } }
/** * Transmit a send-message request to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendMessageContext' * @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_send_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_SendMessageContext *smc = cls; struct TransmitRequestMessage *msg_to_send; size_t msg_size; if (NULL == buf) { #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not transmit a chat message\n"); #endif return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting a chat message to the service\n"); #endif msg_size = strlen (smc->message) + sizeof (struct TransmitRequestMessage); GNUNET_assert (size >= msg_size); msg_to_send = buf; msg_to_send->header.size = htons (msg_size); msg_to_send->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_TRANSMIT_REQUEST); msg_to_send->msg_options = htonl (smc->options); msg_to_send->sequence_number = htonl (smc->sequence_number); msg_to_send->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); msg_to_send->reserved = htonl (0); if (NULL == smc->receiver) memset (&msg_to_send->target, 0, sizeof (GNUNET_HashCode)); else GNUNET_CRYPTO_hash (smc->receiver, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &msg_to_send->target); memcpy (&msg_to_send[1], smc->message, strlen (smc->message)); /** * Client don't encode private messages since public keys of other members are * stored on the service side. */ if (smc->options & GNUNET_CHAT_MSG_AUTHENTICATED) { msg_to_send->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_MESSAGE); msg_to_send->purpose.size = htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (smc->chat_room->my_private_key, &msg_to_send->purpose, &msg_to_send->signature)); } GNUNET_free (smc->message); GNUNET_free (smc); return msg_size; }
/** * Sign name and records * * @param key the private key * @param expire block expiration * @param name the name * @param rd record data * @param rd_count number of records * * @return the signature */ struct GNUNET_CRYPTO_RsaSignature * GNUNET_NAMESTORE_create_signature (const struct GNUNET_CRYPTO_RsaPrivateKey *key, struct GNUNET_TIME_Absolute expire, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, unsigned int rd_count) { struct GNUNET_CRYPTO_RsaSignature *sig; struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO expire_nbo; size_t rd_ser_len; size_t name_len; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; char * name_tmp; char * rd_tmp; int res; uint32_t sig_len; if (NULL == name) { GNUNET_break (0); return NULL; } sig = GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaSignature)); name_len = strlen (name) + 1; expire_nbo = GNUNET_TIME_absolute_hton (expire); rd_ser_len = GNUNET_NAMESTORE_records_get_size (rd_count, rd); { char rd_ser[rd_ser_len]; GNUNET_assert (rd_ser_len == GNUNET_NAMESTORE_records_serialize (rd_count, rd, rd_ser_len, rd_ser)); sig_len = sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len; sig_purpose = GNUNET_malloc (sig_len); sig_purpose->size = htonl (sig_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); name_tmp = (char *) &expire_tmp[1]; memcpy (name_tmp, name, name_len); rd_tmp = &name_tmp[name_len]; memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_sign (key, sig_purpose, sig); GNUNET_free (sig_purpose); } if (GNUNET_OK != res) { GNUNET_break (0); GNUNET_free (sig); return NULL; } return sig; }
/** * Store an item in the datastore. If the item is already present, * the priorities are summed up and the higher expiration time and * lower anonymity level is used. * * @param h handle to the datastore * @param rid reservation ID to use (from "reserve"); use 0 if no * prior reservation was made * @param key key for the value * @param size number of bytes in data * @param data content stored * @param type type of the content * @param priority priority of the content * @param anonymity anonymity-level for the content * @param replication how often should the content be replicated to other peers? * @param expiration expiration time for the content * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout timeout for the operation * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_put (struct GNUNET_DATASTORE_Handle *h, uint32_t rid, const struct GNUNET_HashCode * key, size_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct DataMessage *dm; size_t msize; union QueueContext qc; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to put %u bytes of data under key `%s' for %llu ms\n", size, GNUNET_h2s (key), GNUNET_TIME_absolute_get_remaining (expiration).rel_value); msize = sizeof (struct DataMessage) + size; GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for PUT\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# PUT requests executed"), 1, GNUNET_NO); dm = (struct DataMessage *) &qe[1]; dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_PUT); dm->header.size = htons (msize); dm->rid = htonl (rid); dm->size = htonl ((uint32_t) size); dm->type = htonl (type); dm->priority = htonl (priority); dm->anonymity = htonl (anonymity); dm->replication = htonl (replication); dm->reserved = htonl (0); dm->uid = GNUNET_htonll (0); dm->expiration = GNUNET_TIME_absolute_hton (expiration); dm->key = *key; memcpy (&dm[1], data, size); process_queue (h); return qe; }
/** * Broadcast the new validation changes to all clients monitoring the peer. * * @param peer peer this update is about (never NULL) * @param address address, NULL on disconnect * @param last_validation point in time when last validation was performed * @param valid_until point in time how long address is valid * @param next_validation point in time when next validation will be performed * @param state state of validation notification */ void GST_clients_broadcast_validation_notification ( const struct GNUNET_PeerIdentity *peer, const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute last_validation, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute next_validation, enum GNUNET_TRANSPORT_ValidationState state) { struct ValidationIterateResponseMessage *msg; struct MonitoringClient *mc; static struct GNUNET_PeerIdentity all_zeros; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending information about for validation entry for peer `%s' using address `%s'\n", GNUNET_i2s(peer), (address != NULL) ? GST_plugins_a2s (address) : "<none>"); msg = compose_validation_iterate_response_message (peer, address); msg->last_validation = GNUNET_TIME_absolute_hton(last_validation); msg->valid_until = GNUNET_TIME_absolute_hton(valid_until); msg->next_validation = GNUNET_TIME_absolute_hton(next_validation); msg->state = htonl ((uint32_t) state); mc = val_monitoring_clients_head; while (mc != NULL) { if ((0 == memcmp (&mc->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity))) || (0 == memcmp (&mc->peer, peer, sizeof (struct GNUNET_PeerIdentity)))) { GNUNET_SERVER_notification_context_unicast (val_nc, mc->client, &msg->header, GNUNET_NO); } mc = mc->next; } GNUNET_free (msg); }
/** * Check if a signature is valid. This API is used by the GNS Block * to validate signatures received from the network. * * @param public_key public key of the zone * @param expire block expiration * @param name name that is being mapped (at most 255 characters long) * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @return GNUNET_OK if the signature is valid */ int GNUNET_NAMESTORE_verify_signature (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key, const struct GNUNET_TIME_Absolute expire, const char *name, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature) { int res = GNUNET_SYSERR; size_t rd_ser_len = 0; size_t name_len = 0; char * name_tmp; char * rd_tmp; struct GNUNET_CRYPTO_RsaSignaturePurpose *sig_purpose; struct GNUNET_TIME_AbsoluteNBO *expire_tmp; struct GNUNET_TIME_AbsoluteNBO expire_nbo = GNUNET_TIME_absolute_hton(expire); GNUNET_assert (public_key != NULL); GNUNET_assert (name != NULL); GNUNET_assert (rd != NULL); GNUNET_assert (signature != NULL); rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); name_len = strlen (name) + 1; if (name_len > 256) { GNUNET_break (0); return GNUNET_SYSERR; } sig_purpose = GNUNET_malloc(sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + rd_ser_len + name_len); sig_purpose->size = htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose)+ rd_ser_len + name_len); sig_purpose->purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); expire_tmp = (struct GNUNET_TIME_AbsoluteNBO *) &sig_purpose[1]; name_tmp = (char *) &expire_tmp[1]; rd_tmp = &name_tmp[name_len]; memcpy (expire_tmp, &expire_nbo, sizeof (struct GNUNET_TIME_AbsoluteNBO)); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); res = GNUNET_CRYPTO_rsa_verify(GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN, sig_purpose, signature, public_key); GNUNET_free (sig_purpose); return res; }
/** * Transmit a confirmation receipt to the chat service. * * @param cls closure, pointer to the 'struct GNUNET_CHAT_SendReceiptContext' * @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_acknowledge_request (void *cls, size_t size, void *buf) { struct GNUNET_CHAT_SendReceiptContext *src = cls; struct ConfirmationReceiptMessage *receipt; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pub_key; uint16_t msg_len; size_t msg_size; if (NULL == buf) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not transmit confirmation receipt\n")); return 0; } #if DEBUG_CHAT GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting confirmation receipt to the service\n"); #endif msg_size = sizeof (struct ConfirmationReceiptMessage); GNUNET_assert (size >= msg_size); receipt = buf; receipt->header.size = htons (msg_size); receipt->header.type = htons (GNUNET_MESSAGE_TYPE_CHAT_CONFIRMATION_RECEIPT); receipt->reserved = htonl (0); receipt->sequence_number = src->received_msg->sequence_number; receipt->reserved2 = htonl (0); receipt->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); GNUNET_CRYPTO_rsa_key_get_public (src->chat_room->my_private_key, &pub_key); GNUNET_CRYPTO_hash (&pub_key, sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded), &receipt->target); receipt->author = src->received_msg->sender; receipt->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CHAT_RECEIPT); receipt->purpose.size = htonl (msg_size - sizeof (struct GNUNET_MessageHeader) - sizeof (uint32_t) - sizeof (struct GNUNET_CRYPTO_RsaSignature)); msg_len = ntohs (src->received_msg->header.size) - sizeof (struct ReceiveNotificationMessage); GNUNET_CRYPTO_hash (&src->received_msg[1], msg_len, &receipt->content); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_rsa_sign (src->chat_room->my_private_key, &receipt->purpose, &receipt->signature)); GNUNET_free (src->received_msg); GNUNET_free (src); return msg_size; }
/** * Explicitly remove some content from the database. * The "cont"inuation will be called with status * "GNUNET_OK" if content was removed, "GNUNET_NO" * if no matching entry was found and "GNUNET_SYSERR" * on all other types of errors. * * @param h handle to the datastore * @param key key for the value * @param size number of bytes in data * @param data content stored * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_remove (struct GNUNET_DATASTORE_Handle *h, const struct GNUNET_HashCode * key, size_t size, const void *data, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct DataMessage *dm; size_t msize; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to remove %u bytes under key `%s'\n", size, GNUNET_h2s (key)); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; msize = sizeof (struct DataMessage) + size; GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE); qe = make_queue_entry (h, msize, queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for REMOVE\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# REMOVE requests executed"), 1, GNUNET_NO); dm = (struct DataMessage *) &qe[1]; dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_REMOVE); dm->header.size = htons (msize); dm->rid = htonl (0); dm->size = htonl (size); dm->type = htonl (0); dm->priority = htonl (0); dm->anonymity = htonl (0); dm->uid = GNUNET_htonll (0); dm->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_ZERO_ABS); dm->key = *key; memcpy (&dm[1], data, size); process_queue (h); return qe; }
/** * 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); }
/** * Function to handle call request from the client * * @param cls the `struct Line` the message is about * @param msg the message from the client */ static void handle_client_call_message (void *cls, const struct ClientCallMessage *msg) { struct Line *line = cls; struct Channel *ch; struct GNUNET_MQ_Envelope *e; struct CadetPhoneRingMessage *ring; struct CadetPhoneRingInfoPS rs; line->line_port = msg->line_port; rs.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_CONVERSATION_RING); rs.purpose.size = htonl (sizeof (struct CadetPhoneRingInfoPS)); rs.line_port = line->line_port; rs.target_peer = msg->target; rs.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (RING_TIMEOUT)); ch = GNUNET_new (struct Channel); ch->line = line; GNUNET_CONTAINER_DLL_insert (line->channel_head, line->channel_tail, ch); ch->status = CS_CALLER_CALLING; ch->channel = GNUNET_CADET_channel_create (cadet, ch, &msg->target, &msg->line_port, GNUNET_CADET_OPTION_RELIABLE); ch->mq = GNUNET_CADET_mq_create (ch->channel); e = GNUNET_MQ_msg (ring, GNUNET_MESSAGE_TYPE_CONVERSATION_CADET_PHONE_RING); GNUNET_CRYPTO_ecdsa_key_get_public (&msg->caller_id, &ring->caller_id); ring->expiration_time = rs.expiration_time; GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_ecdsa_sign (&msg->caller_id, &rs.purpose, &ring->signature)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending RING message via CADET\n"); GNUNET_MQ_send (ch->mq, e); GNUNET_SERVICE_client_continue (line->client); }
/** * Transmit a status code to the client. * * @param client receiver of the response * @param code status code * @param msg optional error message (can be NULL) */ static void transmit_status (struct GNUNET_SERVER_Client *client, int code, const char *msg) { struct StatusMessage *sm; size_t slen; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message with value %d and message `%s'\n", "STATUS", code, msg != NULL ? msg : "(none)"); slen = (msg == NULL) ? 0 : strlen (msg) + 1; sm = GNUNET_malloc (sizeof (struct StatusMessage) + slen); sm->header.size = htons (sizeof (struct StatusMessage) + slen); sm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_STATUS); sm->status = htonl (code); sm->min_expiration = GNUNET_TIME_absolute_hton (min_expiration); if (slen > 0) memcpy (&sm[1], msg, slen); transmit (client, &sm->header); }
/** * Store an item in the datastore. * * @param cls closure (our `struct Plugin`) * @param key key to store @a data under * @param size number of bytes in @a data * @param data data to store * @param type type of the value * @param discard_time when to discard the value in any case * @param path_info_len number of entries in @a path_info * @param path_info a path through the network * @return 0 if duplicate, -1 on error, number of bytes used otherwise */ static ssize_t postgres_plugin_put (void *cls, const struct GNUNET_HashCode *key, size_t size, const char *data, enum GNUNET_BLOCK_Type type, struct GNUNET_TIME_Absolute discard_time, unsigned int path_info_len, const struct GNUNET_PeerIdentity *path_info) { struct Plugin *plugin = cls; PGresult *ret; uint32_t btype = htonl (type); uint64_t bexpi = GNUNET_TIME_absolute_hton (discard_time).abs_value_us__; const char *paramValues[] = { (const char *) &btype, (const char *) &bexpi, (const char *) key, (const char *) data, (const char *) path_info }; int paramLengths[] = { sizeof (btype), sizeof (bexpi), sizeof (struct GNUNET_HashCode), size, path_info_len * sizeof (struct GNUNET_PeerIdentity) }; const int paramFormats[] = { 1, 1, 1, 1, 1 }; ret = PQexecPrepared (plugin->dbh, "put", 5, paramValues, paramLengths, paramFormats, 1); if (GNUNET_OK != GNUNET_POSTGRES_check_result (plugin->dbh, ret, PGRES_COMMAND_OK, "PQexecPrepared", "put")) return -1; plugin->num_items++; PQclear (ret); return size + OVERHEAD; }
/** * Update a value in the datastore. * * @param h handle to the datastore * @param uid identifier for the value * @param priority how much to increase the priority of the value * @param expiration new expiration value should be MAX of existing and this argument * @param queue_priority ranking of this request in the priority queue * @param max_queue_size at what queue size should this request be dropped * (if other requests of higher priority are in the queue) * @param timeout how long to wait at most for a response * @param cont continuation to call when done * @param cont_cls closure for cont * @return NULL if the entry was not queued, otherwise a handle that can be used to * cancel; note that even if NULL is returned, the callback will be invoked * (or rather, will already have been invoked) */ struct GNUNET_DATASTORE_QueueEntry * GNUNET_DATASTORE_update (struct GNUNET_DATASTORE_Handle *h, uint64_t uid, uint32_t priority, struct GNUNET_TIME_Absolute expiration, unsigned int queue_priority, unsigned int max_queue_size, struct GNUNET_TIME_Relative timeout, GNUNET_DATASTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_DATASTORE_QueueEntry *qe; struct UpdateMessage *um; union QueueContext qc; if (cont == NULL) cont = &drop_status_cont; LOG (GNUNET_ERROR_TYPE_DEBUG, "Asked to update entry %llu raising priority by %u and expiration to %llu\n", uid, (unsigned int) priority, (unsigned long long) expiration.abs_value); qc.sc.cont = cont; qc.sc.cont_cls = cont_cls; qe = make_queue_entry (h, sizeof (struct UpdateMessage), queue_priority, max_queue_size, timeout, &process_status_message, &qc); if (qe == NULL) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Could not create queue entry for UPDATE\n"); return NULL; } GNUNET_STATISTICS_update (h->stats, gettext_noop ("# UPDATE requests executed"), 1, GNUNET_NO); um = (struct UpdateMessage *) &qe[1]; um->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_UPDATE); um->header.size = htons (sizeof (struct UpdateMessage)); um->priority = htonl (priority); um->expiration = GNUNET_TIME_absolute_hton (expiration); um->uid = GNUNET_htonll (uid); process_queue (h); return qe; }
GNUNET_NETWORK_STRUCT_END /** * Copy the given address information into * the given buffer using the format of HELLOs. * * @param address the address * @param expiration expiration for the address * @param target where to copy the address * @param max maximum number of bytes to copy to target * @return number of bytes copied, 0 if * the target buffer was not big enough. */ size_t GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration, char *target, size_t max) { uint16_t alen; size_t slen; struct GNUNET_TIME_AbsoluteNBO exp; slen = strlen (address->transport_name) + 1; if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + address->address_length > max) return 0; exp = GNUNET_TIME_absolute_hton (expiration); alen = htons ((uint16_t) address->address_length); memcpy (target, address->transport_name, slen); memcpy (&target[slen], &alen, sizeof (uint16_t)); slen += sizeof (uint16_t); memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO)); slen += sizeof (struct GNUNET_TIME_AbsoluteNBO); memcpy (&target[slen], address->address, address->address_length); slen += address->address_length; return slen; }
/** * Copy the given address information into * the given buffer using the format of HELLOs. * * @param address the address * @param expiration expiration for the address * @param target where to copy the address * @param max maximum number of bytes to copy to target * @return number of bytes copied, 0 if * the target buffer was not big enough. */ size_t GNUNET_HELLO_add_address (const struct GNUNET_HELLO_Address *address, struct GNUNET_TIME_Absolute expiration, char *target, size_t max) { uint16_t alen; size_t slen; struct GNUNET_TIME_AbsoluteNBO exp; slen = strlen (address->transport_name) + 1; if (slen + sizeof (uint16_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + address->address_length > max) return 0; exp = GNUNET_TIME_absolute_hton (expiration); alen = htons ((uint16_t) address->address_length); memcpy (target, address->transport_name, slen); memcpy (&target[slen], &alen, sizeof (uint16_t)); slen += sizeof (uint16_t); memcpy (&target[slen], &exp, sizeof (struct GNUNET_TIME_AbsoluteNBO)); slen += sizeof (struct GNUNET_TIME_AbsoluteNBO); memcpy (&target[slen], address->address, address->address_length); slen += address->address_length; return slen; }
/** * Handle a reply we've received from another peer. If the reply * matches any of our pending queries, forward it to the respective * client(s). * * @param expiration when will the reply expire * @param key the query this reply is for * @param get_path_length number of peers in @a get_path * @param get_path path the reply took on get * @param put_path_length number of peers in @a put_path * @param put_path path the reply took on put * @param type type of the reply * @param data_size number of bytes in @a data * @param data application payload data */ void GDS_CLIENTS_handle_reply (struct GNUNET_TIME_Absolute expiration, const struct GNUNET_HashCode *key, unsigned int get_path_length, const struct GNUNET_PeerIdentity *get_path, unsigned int put_path_length, const struct GNUNET_PeerIdentity *put_path, enum GNUNET_BLOCK_Type type, size_t data_size, const void *data) { struct ForwardReplyContext frc; struct PendingMessage *pm; struct GNUNET_DHT_ClientResultMessage *reply; struct GNUNET_PeerIdentity *paths; size_t msize; LOG (GNUNET_ERROR_TYPE_DEBUG, "reply for key %s\n", GNUNET_h2s (key)); if (NULL == GNUNET_CONTAINER_multihashmap_get (forward_map, key)) { GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# REPLIES ignored for CLIENTS (no match)"), 1, GNUNET_NO); return; /* no matching request, fast exit! */ } msize = sizeof (struct GNUNET_DHT_ClientResultMessage) + data_size + (get_path_length + put_path_length) * sizeof (struct GNUNET_PeerIdentity); if (msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Could not pass reply to client, message too big!\n")); return; } pm = GNUNET_malloc (msize + sizeof (struct PendingMessage)); reply = (struct GNUNET_DHT_ClientResultMessage *) &pm[1]; pm->msg = &reply->header; reply->header.size = htons ((uint16_t) msize); reply->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_RESULT); reply->type = htonl (type); reply->get_path_length = htonl (get_path_length); reply->put_path_length = htonl (put_path_length); reply->unique_id = 0; /* filled in later */ reply->expiration = GNUNET_TIME_absolute_hton (expiration); reply->key = *key; paths = (struct GNUNET_PeerIdentity *) &reply[1]; memcpy (paths, put_path, sizeof (struct GNUNET_PeerIdentity) * put_path_length); memcpy (&paths[put_path_length], get_path, sizeof (struct GNUNET_PeerIdentity) * get_path_length); memcpy (&paths[get_path_length + put_path_length], data, data_size); frc.do_copy = GNUNET_NO; frc.pm = pm; frc.data = data; frc.data_size = data_size; frc.type = type; GNUNET_CONTAINER_multihashmap_get_multiple (forward_map, key, &forward_reply, &frc); if (GNUNET_NO == frc.do_copy) { /* did not match any of the requests, free! */ GNUNET_STATISTICS_update (GDS_stats, gettext_noop ("# REPLIES ignored for CLIENTS (no match)"), 1, GNUNET_NO); GNUNET_free (pm); } }
/** * Check if some client is monitoring PUT messages and notify * them in that case. * * @param options Options, for instance RecordRoute, DemultiplexEverywhere. * @param type The type of data in the request. * @param hop_count Hop count so far. * @param path_length number of entries in path (or 0 if not recorded). * @param path peers on the PUT path (or NULL if not recorded). * @param desired_replication_level Desired replication level. * @param exp Expiration time of the data. * @param key Key under which data is to be stored. * @param data Pointer to the data carried. * @param size Number of bytes in data. */ void GDS_CLIENTS_process_put (uint32_t options, enum GNUNET_BLOCK_Type type, uint32_t hop_count, uint32_t desired_replication_level, unsigned int path_length, const struct GNUNET_PeerIdentity *path, struct GNUNET_TIME_Absolute exp, const struct GNUNET_HashCode * key, const void *data, size_t size) { struct ClientMonitorRecord *m; struct ClientList **cl; unsigned int cl_size; cl = NULL; cl_size = 0; for (m = monitor_head; NULL != m; m = m->next) { if ((GNUNET_BLOCK_TYPE_ANY == m->type || m->type == type) && (NULL == m->key || memcmp (key, m->key, sizeof(struct GNUNET_HashCode)) == 0)) { struct PendingMessage *pm; struct GNUNET_DHT_MonitorPutMessage *mmsg; struct GNUNET_PeerIdentity *msg_path; size_t msize; unsigned int i; /* Don't send duplicates */ for (i = 0; i < cl_size; i++) if (cl[i] == m->client) break; if (i < cl_size) continue; GNUNET_array_append (cl, cl_size, m->client); msize = size; msize += path_length * sizeof (struct GNUNET_PeerIdentity); msize += sizeof (struct GNUNET_DHT_MonitorPutMessage); msize += sizeof (struct PendingMessage); pm = GNUNET_malloc (msize); mmsg = (struct GNUNET_DHT_MonitorPutMessage *) &pm[1]; pm->msg = (struct GNUNET_MessageHeader *) mmsg; mmsg->header.size = htons (msize - sizeof (struct PendingMessage)); mmsg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_PUT); mmsg->options = htonl(options); mmsg->type = htonl(type); mmsg->hop_count = htonl(hop_count); mmsg->desired_replication_level = htonl(desired_replication_level); mmsg->put_path_length = htonl(path_length); msg_path = (struct GNUNET_PeerIdentity *) &mmsg[1]; if (path_length > 0) { memcpy (msg_path, path, path_length * sizeof (struct GNUNET_PeerIdentity)); } mmsg->expiration_time = GNUNET_TIME_absolute_hton(exp); memcpy (&mmsg->key, key, sizeof (struct GNUNET_HashCode)); if (size > 0) memcpy (&msg_path[path_length], data, size); add_pending_message (m->client, pm); } } GNUNET_free_non_null (cl); }
/** * Regex callback iterator to store own service description in the DHT. * * @param cls closure. * @param key hash for current state. * @param proof proof for current state. * @param accepting #GNUNET_YES if this is an accepting state, #GNUNET_NO if not. * @param num_edges number of edges leaving current state. * @param edges edges leaving current state. */ static void regex_iterator (void *cls, const struct GNUNET_HashCode *key, const char *proof, int accepting, unsigned int num_edges, const struct REGEX_BLOCK_Edge *edges) { struct REGEX_INTERNAL_Announcement *h = cls; struct RegexBlock *block; size_t size; unsigned int i; LOG (GNUNET_ERROR_TYPE_INFO, "DHT PUT for state %s with proof `%s' and %u edges:\n", GNUNET_h2s (key), proof, num_edges); for (i = 0; i < num_edges; i++) { LOG (GNUNET_ERROR_TYPE_INFO, "Edge %u `%s' towards %s\n", i, edges[i].label, GNUNET_h2s (&edges[i].destination)); } if (GNUNET_YES == accepting) { struct RegexAcceptBlock ab; LOG (GNUNET_ERROR_TYPE_INFO, "State %s is accepting, putting own id\n", GNUNET_h2s (key)); size = sizeof (struct RegexAcceptBlock); ab.purpose.size = ntohl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO) + sizeof (struct GNUNET_HashCode)); ab.purpose.purpose = ntohl (GNUNET_SIGNATURE_PURPOSE_REGEX_ACCEPT); ab.expiration_time = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_DHT_MAX_EXPIRATION)); ab.key = *key; GNUNET_CRYPTO_eddsa_key_get_public (h->priv, &ab.peer.public_key); GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (h->priv, &ab.purpose, &ab.signature)); GNUNET_STATISTICS_update (h->stats, "# regex accepting blocks stored", 1, GNUNET_NO); GNUNET_STATISTICS_update (h->stats, "# regex accepting block bytes stored", sizeof (struct RegexAcceptBlock), GNUNET_NO); (void) GNUNET_DHT_put (h->dht, key, DHT_REPLICATION, DHT_OPT | GNUNET_DHT_RO_RECORD_ROUTE, GNUNET_BLOCK_TYPE_REGEX_ACCEPT, size, &ab, GNUNET_TIME_relative_to_absolute (DHT_TTL), NULL, NULL); } block = REGEX_BLOCK_create (proof, num_edges, edges, accepting, &size); (void) GNUNET_DHT_put (h->dht, key, DHT_REPLICATION, DHT_OPT, GNUNET_BLOCK_TYPE_REGEX, size, block, GNUNET_TIME_relative_to_absolute (DHT_TTL), NULL, NULL); GNUNET_STATISTICS_update (h->stats, "# regex blocks stored", 1, GNUNET_NO); GNUNET_STATISTICS_update (h->stats, "# regex block bytes stored", size, GNUNET_NO); GNUNET_free (block); }
/** * 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; }
int main (int argc, char *argv[]) { struct GNUNET_TIME_Absolute now; struct GNUNET_TIME_AbsoluteNBO nown; struct GNUNET_TIME_Absolute future; struct GNUNET_TIME_Absolute past; struct GNUNET_TIME_Absolute last; struct GNUNET_TIME_Absolute forever; struct GNUNET_TIME_Absolute zero; struct GNUNET_TIME_Relative rel; struct GNUNET_TIME_Relative relForever; struct GNUNET_TIME_Relative relUnit; struct GNUNET_TIME_RelativeNBO reln; unsigned int i; GNUNET_log_setup ("test-time", "WARNING", NULL); forever = GNUNET_TIME_UNIT_FOREVER_ABS; relForever = GNUNET_TIME_UNIT_FOREVER_REL; relUnit = GNUNET_TIME_UNIT_MILLISECONDS; zero.abs_value_us = 0; last = now = GNUNET_TIME_absolute_get (); while (now.abs_value_us == last.abs_value_us) now = GNUNET_TIME_absolute_get (); GNUNET_assert (now.abs_value_us > last.abs_value_us); /* test overflow checking in multiply */ rel = GNUNET_TIME_UNIT_MILLISECONDS; GNUNET_log_skip (1, GNUNET_NO); for (i = 0; i < 55; i++) rel = GNUNET_TIME_relative_multiply (rel, 2); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us); /*check zero */ rel.rel_value_us = (UINT64_MAX) - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == GNUNET_TIME_relative_multiply (rel, 0).rel_value_us); /* test infinity-check for relative to absolute */ GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_assert (last.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us); GNUNET_log_skip (0, GNUNET_YES); /* check relative to absolute */ rel.rel_value_us = 1000000; GNUNET_assert (GNUNET_TIME_absolute_get ().abs_value_us < GNUNET_TIME_relative_to_absolute (rel).abs_value_us); /*check forever */ rel.rel_value_us = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us == GNUNET_TIME_relative_to_absolute (rel).abs_value_us); /* check overflow for r2a */ rel.rel_value_us = (UINT64_MAX) - 1024; GNUNET_log_skip (1, GNUNET_NO); last = GNUNET_TIME_relative_to_absolute (rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (last.abs_value_us == GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us); /* check overflow for relative add */ GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (rel, rel); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relForever, relForever); GNUNET_log_skip (0, GNUNET_NO); GNUNET_assert (rel.rel_value_us == relForever.rel_value_us); GNUNET_log_skip (1, GNUNET_NO); rel = GNUNET_TIME_relative_add (relUnit, relUnit); GNUNET_assert (rel.rel_value_us == 2 * relUnit.rel_value_us); /* check relation check in get_duration */ future.abs_value_us = now.abs_value_us + 1000000; GNUNET_assert (GNUNET_TIME_absolute_get_difference (now, future).rel_value_us == 1000000); GNUNET_assert (GNUNET_TIME_absolute_get_difference (future, now).rel_value_us == 0); GNUNET_assert (GNUNET_TIME_absolute_get_difference (zero, forever).rel_value_us == forever.abs_value_us); past.abs_value_us = now.abs_value_us - 1000000; rel = GNUNET_TIME_absolute_get_duration (future); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_duration (past); GNUNET_assert (rel.rel_value_us >= 1000000); /* check get remaining */ rel = GNUNET_TIME_absolute_get_remaining (now); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_remaining (past); GNUNET_assert (rel.rel_value_us == 0); rel = GNUNET_TIME_absolute_get_remaining (future); GNUNET_assert (rel.rel_value_us > 0); GNUNET_assert (rel.rel_value_us <= 1000000); forever = GNUNET_TIME_UNIT_FOREVER_ABS; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == GNUNET_TIME_absolute_get_remaining (forever).rel_value_us); /* check endianess */ reln = GNUNET_TIME_relative_hton (rel); GNUNET_assert (rel.rel_value_us == GNUNET_TIME_relative_ntoh (reln).rel_value_us); nown = GNUNET_TIME_absolute_hton (now); GNUNET_assert (now.abs_value_us == GNUNET_TIME_absolute_ntoh (nown).abs_value_us); /* check absolute addition */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_SECONDS); GNUNET_assert (future.abs_value_us == now.abs_value_us + 1000 * 1000LL); future = GNUNET_TIME_absolute_add (forever, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value_us == forever.abs_value_us); rel.rel_value_us = (UINT64_MAX) - 1024; now.abs_value_us = rel.rel_value_us; future = GNUNET_TIME_absolute_add (now, rel); GNUNET_assert (future.abs_value_us == forever.abs_value_us); /* check zero */ future = GNUNET_TIME_absolute_add (now, GNUNET_TIME_UNIT_ZERO); GNUNET_assert (future.abs_value_us == now.abs_value_us); GNUNET_assert (forever.abs_value_us == GNUNET_TIME_absolute_subtract (forever, GNUNET_TIME_UNIT_MINUTES).abs_value_us); /*check absolute subtract */ now.abs_value_us = 50000; rel.rel_value_us = 100000; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value_us); rel.rel_value_us = 10000; GNUNET_assert (40000 == (GNUNET_TIME_absolute_subtract (now, rel)).abs_value_us); /*check relative divide */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_relative_divide (rel, 0)).rel_value_us); rel = GNUNET_TIME_UNIT_FOREVER_REL; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_relative_divide (rel, 2)).rel_value_us); rel = GNUNET_TIME_relative_divide (relUnit, 2); GNUNET_assert (rel.rel_value_us == relUnit.rel_value_us / 2); /* check Return absolute time of 0ms */ zero = GNUNET_TIME_UNIT_ZERO_ABS; /* check GNUNET_TIME_calculate_eta */ last.abs_value_us = GNUNET_TIME_absolute_get ().abs_value_us - 1024; forever = GNUNET_TIME_UNIT_FOREVER_ABS; forever.abs_value_us = forever.abs_value_us - 1024; GNUNET_assert (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us == GNUNET_TIME_calculate_eta (forever, 50000, 100000).rel_value_us); /* check zero */ GNUNET_log_skip (1, GNUNET_NO); GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == (GNUNET_TIME_calculate_eta (last, 60000, 50000)).rel_value_us); GNUNET_log_skip (0, GNUNET_YES); /*check forever */ GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == (GNUNET_TIME_calculate_eta (last, 0, 50000)).rel_value_us); /*check relative subtract */ now = GNUNET_TIME_absolute_get (); rel.rel_value_us = now.abs_value_us; relForever.rel_value_us = rel.rel_value_us + 1024; GNUNET_assert (1024 == GNUNET_TIME_relative_subtract (relForever, rel).rel_value_us); /*check zero */ GNUNET_assert (GNUNET_TIME_UNIT_ZERO.rel_value_us == GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us); /*check forever */ rel.rel_value_us = UINT64_MAX; GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == GNUNET_TIME_relative_subtract (rel, relForever).rel_value_us); /*check GNUNET_TIME_relative_min */ now = GNUNET_TIME_absolute_get (); rel.rel_value_us = now.abs_value_us; relForever.rel_value_us = rel.rel_value_us - 1024; GNUNET_assert (relForever.rel_value_us == GNUNET_TIME_relative_min (rel, relForever).rel_value_us); /*check GNUNET_TIME_relative_max */ GNUNET_assert (rel.rel_value_us == GNUNET_TIME_relative_max (rel, relForever).rel_value_us); /*check GNUNET_TIME_absolute_min */ now = GNUNET_TIME_absolute_get (); last.abs_value_us = now.abs_value_us - 1024; GNUNET_assert (last.abs_value_us == GNUNET_TIME_absolute_min (now, last).abs_value_us); /*check GNUNET_TIME_absolute_max */ GNUNET_assert (now.abs_value_us == GNUNET_TIME_absolute_max (now, last).abs_value_us); return 0; }
/** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used by the authority of a zone. * * @param h handle to the namestore * @param pkey private key of the zone * @param name name that is being mapped (at most 255 characters long) * @param rd record data to store * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_create (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPrivateKey *pkey, const char *name, const struct GNUNET_NAMESTORE_RecordData *rd, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; char * name_tmp; char * pkey_tmp; char * rd_tmp; size_t rd_ser_len = 0; size_t msg_size = 0; size_t name_len = 0; size_t key_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != pkey); GNUNET_assert (NULL != name); GNUNET_assert (NULL != rd); name_len = strlen(name) + 1; if (name_len > 256) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ struct GNUNET_CRYPTO_RsaPrivateKeyBinaryEncoded * pkey_enc = GNUNET_CRYPTO_rsa_encode_key (pkey); GNUNET_assert (pkey_enc != NULL); key_len = ntohs (pkey_enc->len); rd_ser_len = GNUNET_NAMESTORE_records_get_size(1, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(1, rd, rd_ser_len, rd_ser); struct RecordCreateMessage * msg; msg_size = sizeof (struct RecordCreateMessage) + key_len + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordCreateMessage *) &pe[1]; pkey_tmp = (char *) &msg[1]; name_tmp = &pkey_tmp[key_len]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_CREATE); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->name_len = htons (name_len); msg->rd_count = htons (1); msg->rd_len = htons (rd_ser_len); msg->pkey_len = htons (key_len); msg->expire = GNUNET_TIME_absolute_hton(GNUNET_TIME_UNIT_FOREVER_ABS); memcpy (pkey_tmp, pkey_enc, key_len); memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_free (pkey_enc); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_CREATE", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; }
GNUNET_SERVER_client_drop (client); return GNUNET_OK; } GNUNET_assert (sizeof (struct DataMessage) + size < GNUNET_SERVER_MAX_MESSAGE_SIZE); dm = GNUNET_malloc (sizeof (struct DataMessage) + size); dm->header.size = htons (sizeof (struct DataMessage) + size); dm->header.type = htons (GNUNET_MESSAGE_TYPE_DATASTORE_DATA); dm->rid = htonl (0); dm->size = htonl (size); dm->type = htonl (type); dm->priority = htonl (priority); dm->anonymity = htonl (anonymity); dm->replication = htonl (0); dm->reserved = htonl (0); dm->expiration = GNUNET_TIME_absolute_hton (expiration); dm->uid = GNUNET_htonll (uid); dm->key = *key; memcpy (&dm[1], data, size); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' message for `%s' of type %u with expiration %s (in: %s)\n", "DATA", GNUNET_h2s (key), type, GNUNET_STRINGS_absolute_time_to_string (expiration), GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (expiration), GNUNET_YES)); GNUNET_STATISTICS_update (stats, gettext_noop ("# results found"), 1, GNUNET_NO); transmit (client, &dm->header); GNUNET_SERVER_client_drop (client); return GNUNET_OK; }
/** * Store an item in the namestore. If the item is already present, * the expiration time is updated to the max of the existing time and * the new time. This API is used when we cache signatures from other * authorities. * * @param h handle to the namestore * @param zone_key public key of the zone * @param name name that is being mapped (at most 255 characters long) * @param freshness when does the corresponding block in the DHT expire (until * when should we never do a DHT lookup for the same name again)? * @param rd_count number of entries in 'rd' array * @param rd array of records with data to store * @param signature signature for all the records in the zone under the given name * @param cont continuation to call when done * @param cont_cls closure for cont * @return handle to abort the request */ struct GNUNET_NAMESTORE_QueueEntry * GNUNET_NAMESTORE_record_put (struct GNUNET_NAMESTORE_Handle *h, const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *zone_key, const char *name, struct GNUNET_TIME_Absolute freshness, unsigned int rd_count, const struct GNUNET_NAMESTORE_RecordData *rd, const struct GNUNET_CRYPTO_RsaSignature *signature, GNUNET_NAMESTORE_ContinuationWithStatus cont, void *cont_cls) { struct GNUNET_NAMESTORE_QueueEntry *qe; struct PendingMessage *pe; /* pointer to elements */ char * rd_tmp; char * name_tmp; size_t msg_size = 0; size_t name_len = 0; size_t rd_ser_len = 0; uint32_t rid = 0; GNUNET_assert (NULL != h); GNUNET_assert (NULL != zone_key); GNUNET_assert (NULL != name); GNUNET_assert (NULL != rd); GNUNET_assert (NULL != signature); name_len = strlen(name) + 1; if (name_len > 256) { GNUNET_break (0); return NULL; } rid = get_op_id(h); qe = GNUNET_malloc(sizeof (struct GNUNET_NAMESTORE_QueueEntry)); qe->nsh = h; qe->cont = cont; qe->cont_cls = cont_cls; qe->op_id = rid; GNUNET_CONTAINER_DLL_insert_tail(h->op_head, h->op_tail, qe); /* set msg_size*/ rd_ser_len = GNUNET_NAMESTORE_records_get_size(rd_count, rd); char rd_ser[rd_ser_len]; GNUNET_NAMESTORE_records_serialize(rd_count, rd, rd_ser_len, rd_ser); struct RecordPutMessage * msg; msg_size = sizeof (struct RecordPutMessage) + name_len + rd_ser_len; /* create msg here */ pe = GNUNET_malloc(sizeof (struct PendingMessage) + msg_size); pe->size = msg_size; pe->is_init = GNUNET_NO; msg = (struct RecordPutMessage *) &pe[1]; name_tmp = (char *) &msg[1]; rd_tmp = &name_tmp[name_len]; msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_PUT); msg->gns_header.header.size = htons (msg_size); msg->gns_header.r_id = htonl (rid); msg->signature = *signature; msg->name_len = htons (name_len); msg->expire = GNUNET_TIME_absolute_hton (freshness); msg->rd_len = htons (rd_ser_len); msg->rd_count = htons (rd_count); msg->public_key = *zone_key; memcpy (name_tmp, name, name_len); memcpy (rd_tmp, rd_ser, rd_ser_len); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message for name `%s' with size %u\n", "NAMESTORE_RECORD_PUT", name, msg_size); GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); do_transmit(h); return qe; }
/** * We're ready to transmit a request to the VPN service. Do it. * * @param cls the 'struct GNUNET_VPN_Handle*' * @param size number of bytes available in buf * @param buf where to copy the request * @return number of bytes copied to 'buf' */ static size_t transmit_request (void *cls, size_t size, void *buf) { struct GNUNET_VPN_Handle *vh = cls; struct GNUNET_VPN_RedirectionRequest *rr; struct RedirectToIpRequestMessage rip; struct RedirectToServiceRequestMessage rs; char *cbuf; size_t alen; size_t ret; vh->th = NULL; /* find a pending request */ rr = vh->rr_head; while ( (NULL != rr) && (0 != rr->request_id) ) rr = rr->next; if (NULL == rr) return 0; if (0 == size) { reconnect (vh); return 0; } /* if first request, start receive loop */ if (0 == vh->request_id_gen) GNUNET_CLIENT_receive (vh->client, &receive_response, vh, GNUNET_TIME_UNIT_FOREVER_REL); if (NULL == rr->addr) { ret = sizeof (struct RedirectToServiceRequestMessage); GNUNET_assert (ret <= size); rs.header.size = htons ((uint16_t) ret); rs.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_SERVICE); rs.nac = htonl (rr->nac); rs.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); rs.protocol = htonl (rr->protocol); rs.result_af = htonl (rr->result_af); rs.target = rr->peer; rs.service_descriptor = rr->serv; rs.request_id = rr->request_id = ++vh->request_id_gen; memcpy (buf, &rs, sizeof (struct RedirectToServiceRequestMessage)); } else { switch (rr->addr_af) { case AF_INET: alen = sizeof (struct in_addr); break; case AF_INET6: alen = sizeof (struct in6_addr); break; default: GNUNET_assert (0); return 0; } ret = alen + sizeof (struct RedirectToIpRequestMessage); GNUNET_assert (ret <= size); rip.header.size = htons ((uint16_t) ret); rip.header.type = htons (GNUNET_MESSAGE_TYPE_VPN_CLIENT_REDIRECT_TO_IP); rip.nac = htonl (rr->nac); rip.expiration_time = GNUNET_TIME_absolute_hton (rr->expiration_time); rip.result_af = htonl (rr->result_af); rip.addr_af = htonl (rr->addr_af); rip.request_id = rr->request_id = ++vh->request_id_gen; cbuf = buf; memcpy (cbuf, &rip, sizeof (struct RedirectToIpRequestMessage)); memcpy (&cbuf[sizeof (struct RedirectToIpRequestMessage)], rr->addr, alen); } /* test if there are more pending requests */ while ( (NULL != rr) && (0 != rr->request_id) ) rr = rr->next; if (NULL != rr) vh->th = GNUNET_CLIENT_notify_transmit_ready (vh->client, sizeof (struct RedirectToServiceRequestMessage), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_NO, &transmit_request, vh); return ret; }