/** * Iterate over all nodes in the tree. * * @param tree Tree to use.. * @param cb Callback to call over each child. * @param cb_cls Closure for @c cb. * * TODO: recursive implementation? (s/heap/stack/g) */ void tree_iterate_all (struct MeshTunnelTree *tree, MeshWholeTreeCallback cb, void *cb_cls) { struct MeshTunnelTreeNode *parent; struct MeshTunnelTreeNode *n; struct MeshTreePendingNode *head; struct MeshTreePendingNode *tail; struct MeshTreePendingNode *pending; cb (cb_cls, tree->root->peer, 0); pending = GNUNET_malloc (sizeof (struct MeshTreePendingNode)); pending->node = tree->root; head = tail = NULL; GNUNET_CONTAINER_DLL_insert (head, tail, pending); while (NULL != head) { pending = head; parent = pending->node; GNUNET_CONTAINER_DLL_remove (head, tail, pending); GNUNET_free (pending); for (n = parent->children_head; NULL != n; n = n->next) { cb (cb_cls, n->peer, parent->peer); pending = GNUNET_malloc (sizeof (struct MeshTreePendingNode)); pending->node = n; /* Insert_tail: breadth first, Insert: depth first */ GNUNET_CONTAINER_DLL_insert (head, tail, pending); } } }
/** * Notifies a tree that a connection it might be using is broken. * Marks all peers down the paths as disconnected and notifies the client. * * @param t Tree to use. * @param p1 Short id of one of the peers (order unimportant) * @param p2 Short id of one of the peers (order unimportant) * @param cb Function to call for every peer that is marked as disconnected. * @param cbcls Closure for cb. * * @return Short ID of the first disconnected peer in the tree. */ GNUNET_PEER_Id tree_notify_connection_broken (struct MeshTunnelTree *t, GNUNET_PEER_Id p1, GNUNET_PEER_Id p2, MeshTreeCallback cb, void *cbcls) { struct MeshTunnelTreeNode *n; struct MeshTunnelTreeNode *c; n = tree_find_peer (t, p1); if (NULL == n) return 0; if (NULL != n->parent && n->parent->peer == p2) { tree_mark_peers_disconnected (t, n, cb, cbcls); GNUNET_CONTAINER_DLL_remove (n->parent->children_head, n->parent->children_tail, n); GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, n); return p1; } for (c = n->children_head; NULL != c; c = c->next) { if (c->peer == p2) { tree_mark_peers_disconnected (t, c, cb, cbcls); GNUNET_CONTAINER_DLL_remove (n->children_head, n->children_tail, c); GNUNET_CONTAINER_DLL_insert (t->disconnected_head, t->disconnected_tail, c); return p2; } } return 0; }
static void nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen) { struct Plugin *plugin = cls; struct IPv4HttpAddressWrapper *w_t4 = NULL; struct IPv6HttpAddressWrapper *w_t6 = NULL; int af; af = addr->sa_family; switch (af) { case AF_INET: w_t4 = find_address (plugin, addr, addrlen); if (w_t4 == NULL) { struct sockaddr_in *a4 = (struct sockaddr_in *) addr; w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); w_t4->addr.u4_port = a4->sin_port; GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, w_t4); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to add IPv4 address `%s'\n", http_plugin_address_to_string (NULL, &w_t4->addr, sizeof (struct IPv4HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, sizeof (struct IPv4HttpAddress)); } break; case AF_INET6: w_t6 = find_address (plugin, addr, addrlen); if (w_t6 == NULL) { w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); w_t6->addr6.u6_port = a6->sin6_port; GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, w_t6); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Notifying transport to add IPv6 address `%s'\n", http_plugin_address_to_string (NULL, &w_t6->addr6, sizeof (struct IPv6HttpAddress))); plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, sizeof (struct IPv6HttpAddress)); } break; default: return; } }
/** * Start monitoring the local DHT service. * * @param handle Handle to the DHT service. * @param type Type of blocks that are of interest. * @param key Key of data of interest, NULL for all. * @param get_cb Callback to process monitored get messages. * @param get_resp_cb Callback to process monitored get response messages. * @param put_cb Callback to process monitored put messages. * @param cb_cls Closure for cb. * * @return Handle to stop monitoring. */ struct GNUNET_DHT_MonitorHandle * GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const GNUNET_HashCode *key, GNUNET_DHT_MonitorGetCB get_cb, GNUNET_DHT_MonitorGetRespCB get_resp_cb, GNUNET_DHT_MonitorPutCB put_cb, void *cb_cls) { struct GNUNET_DHT_MonitorHandle *h; struct GNUNET_DHT_MonitorStartStopMessage *m; struct PendingMessage *pending; h = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorHandle)); GNUNET_CONTAINER_DLL_insert(handle->monitor_head, handle->monitor_tail, h); h->get_cb = get_cb; h->get_resp_cb = get_resp_cb; h->put_cb = put_cb; h->cb_cls = cb_cls; h->type = type; h->dht_handle = handle; if (NULL != key) { h->key = GNUNET_malloc (sizeof(GNUNET_HashCode)); memcpy (h->key, key, sizeof(GNUNET_HashCode)); } pending = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorStartStopMessage) + sizeof (struct PendingMessage)); m = (struct GNUNET_DHT_MonitorStartStopMessage *) &pending[1]; pending->msg = &m->header; pending->handle = handle; pending->free_on_send = GNUNET_YES; m->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_START); m->header.size = htons (sizeof (struct GNUNET_DHT_MonitorStartStopMessage)); m->type = htonl(type); m->get = htons(NULL != get_cb); m->get_resp = htons(NULL != get_resp_cb); m->put = htons(NULL != put_cb); if (NULL != key) { m->filter_key = htons(1); memcpy (&m->key, key, sizeof(GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; process_pending_messages (handle); return h; }
/** * Try again to connect to the identity service. * * @param cls handle to the identity service. * @param tc scheduler context */ static void reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_IDENTITY_Handle *h = cls; struct GNUNET_IDENTITY_Operation *op; struct GNUNET_MessageHeader msg; h->reconnect_task = NULL; LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to identity service.\n"); GNUNET_assert (NULL == h->client); h->client = GNUNET_CLIENT_connect ("identity", h->cfg); GNUNET_assert (NULL != h->client); if ( (NULL == h->op_head) || (GNUNET_MESSAGE_TYPE_IDENTITY_START != ntohs (h->op_head->msg->type)) ) { op = GNUNET_malloc (sizeof (struct GNUNET_IDENTITY_Operation) + sizeof (struct GNUNET_MessageHeader)); op->h = h; op->msg = (const struct GNUNET_MessageHeader *) &op[1]; msg.size = htons (sizeof (msg)); msg.type = htons (GNUNET_MESSAGE_TYPE_IDENTITY_START); memcpy (&op[1], &msg, sizeof (msg)); GNUNET_CONTAINER_DLL_insert (h->op_head, h->op_tail, op); } transmit_next (h); GNUNET_assert (NULL != h->th); }
static int iface_proc (void *cls, const char *name, int isDefault, const struct sockaddr *addr, const struct sockaddr *broadcast_addr, const struct sockaddr *netmask, socklen_t addrlen) { struct Plugin *plugin = cls; if (addr != NULL) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ", GNUNET_a2s (addr, addrlen), name, addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "broadcast address %s for interface %s %p\n ", GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ", GNUNET_a2s (netmask, addrlen), name, netmask); /* Collecting broadcast addresses */ if (broadcast_addr != NULL) { struct BroadcastAddress *ba = GNUNET_malloc (sizeof (struct BroadcastAddress)); ba->addr = GNUNET_malloc (addrlen); memcpy (ba->addr, broadcast_addr, addrlen); ba->addrlen = addrlen; GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head, plugin->ipv4_broadcast_tail, ba); } } return GNUNET_OK; }
/** * Store an item in the datastore. * * @param cls closure * @param key key for the item * @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 replication-level for the content * @param expiration expiration time for the content * @param msg set to error message * @return GNUNET_OK on success */ static int heap_plugin_put (void *cls, const struct GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, uint32_t replication, struct GNUNET_TIME_Absolute expiration, char **msg) { struct Plugin *plugin = cls; struct Value *value; value = GNUNET_malloc (sizeof (struct Value) + size); value->key = *key; value->data = &value[1]; value->expire_heap = GNUNET_CONTAINER_heap_insert (plugin->by_expiration, value, expiration.abs_value); value->replication_heap = GNUNET_CONTAINER_heap_insert (plugin->by_replication, value, replication); value->expiration = expiration; if (0 == anonymity) { struct ZeroAnonByType *zabt; for (zabt = plugin->zero_head; NULL != zabt; zabt = zabt->next) if (zabt->type == type) break; if (NULL == zabt) { zabt = GNUNET_malloc (sizeof (struct ZeroAnonByType)); zabt->type = type; GNUNET_CONTAINER_DLL_insert (plugin->zero_head, plugin->zero_tail, zabt); } if (zabt->array_size == zabt->array_pos) { GNUNET_array_grow (zabt->array, zabt->array_size, zabt->array_size * 2 + 4); } value->zero_anon_offset = zabt->array_pos; zabt->array[zabt->array_pos++] = value; } value->size = size; value->priority = priority; value->anonymity = anonymity; value->replication = replication; value->type = type; memcpy (&value[1], data, size); GNUNET_CONTAINER_multihashmap_put (plugin->keyvalue, &value->key, value, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); plugin->size += size; return GNUNET_OK; }
/** * Add or remove an address from this peer's HELLO message. * * @param addremove GNUNET_YES to add, GNUNET_NO to remove * @param address address to add or remove */ void GST_hello_modify_addresses (int addremove, const struct GNUNET_HELLO_Address *address) { struct OwnAddressList *al; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, (addremove == GNUNET_YES) ? "Adding `%s' to the set of our addresses\n" : "Removing `%s' from the set of our addresses\n", GST_plugins_a2s (address)); GNUNET_assert (address != NULL); if (GNUNET_NO == addremove) { for (al = oal_head; al != NULL; al = al->next) if (0 == GNUNET_HELLO_address_cmp (address, al->address)) { GNUNET_CONTAINER_DLL_remove (oal_head, oal_tail, al); GNUNET_HELLO_address_free (al->address); GNUNET_free (al); refresh_hello (); return; } /* address to be removed not found!? */ GNUNET_break (0); return; } al = GNUNET_malloc (sizeof (struct OwnAddressList)); GNUNET_CONTAINER_DLL_insert (oal_head, oal_tail, al); al->address = GNUNET_HELLO_address_copy (address); refresh_hello (); }
/** * Handler for monitor start messages * * @param cls closure for the service * @param client the client we received this message from * @param message the actual message received * */ static void handle_dht_local_monitor (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { struct ClientMonitorRecord *r; const struct GNUNET_DHT_MonitorStartStopMessage *msg; msg = (struct GNUNET_DHT_MonitorStartStopMessage *) message; r = GNUNET_new (struct ClientMonitorRecord); r->client = find_active_client(client); r->type = ntohl(msg->type); r->get = ntohs(msg->get); r->get_resp = ntohs(msg->get_resp); r->put = ntohs(msg->put); if (0 == ntohs(msg->filter_key)) r->key = NULL; else { r->key = GNUNET_new (struct GNUNET_HashCode); memcpy (r->key, &msg->key, sizeof (struct GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (monitor_head, monitor_tail, r); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
/** * We've validated the hash of the file we're about to index. Signal * success to the client and update our internal data structures. * * @param ii the index info entry for the request */ static void signal_index_ok (struct IndexInfo *ii) { struct IndexInfo *ir; if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (ifm, &ii->file_id, ii, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { ir = GNUNET_CONTAINER_multihashmap_get (ifm, &ii->file_id); GNUNET_assert (NULL != ir); GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Index request received for file `%s' is already indexed as `%s'. Permitting anyway.\n"), ii->filename, ir->filename); GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); GNUNET_free (ii); return; } GNUNET_CONTAINER_DLL_insert (indexed_files_head, indexed_files_tail, ii); write_index_list (); GNUNET_SERVER_transmit_context_append_data (ii->tc, NULL, 0, GNUNET_MESSAGE_TYPE_FS_INDEX_START_OK); GNUNET_SERVER_transmit_context_run (ii->tc, GNUNET_TIME_UNIT_MINUTES); ii->tc = NULL; }
/** * Transmit the given message to the client. * * @param client target of the message * @param msg message to transmit, will be freed! */ static void transmit (struct GNUNET_SERVER_Client *client, struct GNUNET_MessageHeader *msg) { struct TransmitCallbackContext *tcc; if (GNUNET_YES == cleaning_done) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Shutdown in progress, aborting transmission.\n")); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); return; } tcc = GNUNET_new (struct TransmitCallbackContext); tcc->msg = msg; tcc->client = client; if (NULL == (tcc->th = GNUNET_SERVER_notify_transmit_ready (client, ntohs (msg->size), GNUNET_TIME_UNIT_FOREVER_REL, &transmit_callback, tcc))) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); GNUNET_free (msg); GNUNET_free (tcc); return; } GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (tcc_head, tcc_tail, tcc); }
/** * Process the given file from the "EGODIR". Parses the file * and creates the respective 'struct Ego' in memory. * * @param cls NULL * @param filename name of the file to parse * @return #GNUNET_OK to continue to iterate, * #GNUNET_NO to stop iteration with no error, * #GNUNET_SYSERR to abort iteration with error! */ static int process_ego_file (void *cls, const char *filename) { struct Ego *ego; const char *fn; fn = strrchr (filename, (int) DIR_SEPARATOR); if (NULL == fn) { GNUNET_break (0); return GNUNET_OK; } ego = GNUNET_new (struct Ego); ego->pk = GNUNET_CRYPTO_ecdsa_key_create_from_file (filename); if (NULL == ego->pk) { GNUNET_free (ego); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to parse ego information in `%s'\n"), filename); return GNUNET_OK; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded ego `%s'\n", fn + 1); ego->identifier = GNUNET_strdup (fn + 1); GNUNET_CONTAINER_DLL_insert (ego_head, ego_tail, ego); return GNUNET_OK; }
/** * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message * * Remarks: start_peer's notify_connect callback can be called before. * * @param tth transport testing handle * @param p1 peer 1 * @param p2 peer 2 * @param cb the callback to call when both peers notified that they are connected * @param cls callback cls * @return a connect request handle */ GNUNET_TRANSPORT_TESTING_ConnectRequest GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth, struct PeerContext *p1, struct PeerContext *p2, GNUNET_TRANSPORT_TESTING_connect_cb cb, void *cls) { GNUNET_assert (tth != NULL); struct ConnectingContext *cc = GNUNET_new (struct ConnectingContext); GNUNET_assert (p1 != NULL); GNUNET_assert (p2 != NULL); cc->p1 = p1; cc->p2 = p2; cc->cb = cb; if (cls != NULL) cc->cb_cls = cls; else cc->cb_cls = cc; cc->th_p1 = p1->th; cc->th_p2 = p2->th; GNUNET_assert (cc->th_p1 != NULL); GNUNET_assert (cc->th_p2 != NULL); GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc); cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing", "New connect request %p\n", cc); return cc; }
/** * Queue a request from a client for transmission to a particular peer. * * @param car request to queue; this handle is then shared between * the caller (CLIENTS subsystem) and SESSIONS and must not * be released by either until either #GSC_SESSIONS_dequeue(), * #GSC_SESSIONS_transmit() or #GSC_CLIENTS_failed() * have been invoked on it */ void GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car) { struct Session *session; session = find_session (&car->target); if (NULL == session) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Dropped client request for transmission (am disconnected)\n"); GNUNET_break (0); /* should have been rejected earlier */ GSC_CLIENTS_reject_request (car, GNUNET_NO); return; } if (car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) { GNUNET_break (0); GSC_CLIENTS_reject_request (car, GNUNET_YES); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received client transmission request. queueing\n"); GNUNET_CONTAINER_DLL_insert (session->active_client_request_head, session->active_client_request_tail, car); try_transmission (session); }
/** * Add another child node to the tree. * * @param parent parent of the child, NULL for top level * @param filename name of the file or directory * @param is_directory GNUNET_YES for directories * @return new entry that was just created */ static struct GNUNET_FS_ShareTreeItem * expand_tree (struct GNUNET_FS_ShareTreeItem *parent, const char *filename, int is_directory) { struct GNUNET_FS_ShareTreeItem *chld; size_t slen; chld = GNUNET_malloc (sizeof (struct GNUNET_FS_ShareTreeItem)); chld->parent = parent; chld->filename = GNUNET_strdup (filename); GNUNET_asprintf (&chld->short_filename, "%s%s", GNUNET_STRINGS_get_short_name (filename), is_directory == GNUNET_YES ? "/" : ""); /* make sure we do not end with '//' */ slen = strlen (chld->short_filename); if ( (slen >= 2) && (chld->short_filename[slen-1] == '/') && (chld->short_filename[slen-2] == '/') ) chld->short_filename[slen-1] = '\0'; chld->is_directory = is_directory; if (NULL != parent) GNUNET_CONTAINER_DLL_insert (parent->children_head, parent->children_tail, chld); return chld; }
static void resolve_validation_address (const struct GNUNET_PeerIdentity *id, const struct GNUNET_HELLO_Address *address, int numeric, struct GNUNET_TIME_Absolute last_validation, struct GNUNET_TIME_Absolute valid_until, struct GNUNET_TIME_Absolute next_validation, enum GNUNET_TRANSPORT_ValidationState state) { struct ValidationResolutionContext *vc; vc = GNUNET_new (struct ValidationResolutionContext); GNUNET_assert(NULL != vc); GNUNET_CONTAINER_DLL_insert(vc_head, vc_tail, vc); address_resolutions++; vc->id = (*id); vc->transport = GNUNET_strdup(address->transport_name); vc->addrcp = GNUNET_HELLO_address_copy (address); vc->printed = GNUNET_NO; vc->state = state; vc->last_validation = last_validation; vc->valid_until = valid_until; vc->next_validation = next_validation; /* Resolve address to string */ vc->asc = GNUNET_TRANSPORT_address_to_string (cfg, address, numeric, RESOLUTION_TIMEOUT, &process_validation_string, vc); }
/** * Force plugin to terminate session due to communication * issue. * * @param plugin_name name of the plugin * @param session session to termiante */ static void kill_session (const char *plugin_name, struct GNUNET_ATS_Session *session) { struct GNUNET_TRANSPORT_PluginFunctions *plugin; struct GNUNET_ATS_SessionKiller *sk; for (sk = sk_head; NULL != sk; sk = sk->next) if (sk->session == session) return; plugin = GST_plugins_find (plugin_name); if (NULL == plugin) { GNUNET_break(0); return; } /* need to issue disconnect asynchronously */ sk = GNUNET_new (struct GNUNET_ATS_SessionKiller); sk->session = session; sk->plugin = plugin; sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, sk); GNUNET_CONTAINER_DLL_insert (sk_head, sk_tail, sk); }
/** * Stop monitoring. * * @param handle The handle to the monitor request returned by monitor_start. * * On return get_handle will no longer be valid, caller must not use again!!! */ void GNUNET_DHT_monitor_stop (struct GNUNET_DHT_MonitorHandle *handle) { struct GNUNET_DHT_MonitorStartStopMessage *m; struct PendingMessage *pending; GNUNET_CONTAINER_DLL_remove (handle->dht_handle->monitor_head, handle->dht_handle->monitor_tail, handle); pending = GNUNET_malloc (sizeof (struct GNUNET_DHT_MonitorStartStopMessage) + sizeof (struct PendingMessage)); m = (struct GNUNET_DHT_MonitorStartStopMessage *) &pending[1]; pending->msg = &m->header; pending->handle = handle->dht_handle; pending->free_on_send = GNUNET_YES; m->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_MONITOR_STOP); m->header.size = htons (sizeof (struct GNUNET_DHT_MonitorStartStopMessage)); m->type = htonl(handle->type); m->get = htons(NULL != handle->get_cb); m->get_resp = htons(NULL != handle->get_resp_cb); m->put = htons(NULL != handle->put_cb); if (NULL != handle->key) { m->filter_key = htons(1); memcpy (&m->key, handle->key, sizeof(GNUNET_HashCode)); } GNUNET_CONTAINER_DLL_insert (handle->dht_handle->pending_head, handle->dht_handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; process_pending_messages (handle->dht_handle); GNUNET_free_non_null (handle->key); GNUNET_free (handle); }
/** * Look for a block by directly contacting a particular peer. * * @param target peer that should have the block * @param query hash to query for the block * @param type desired type for the block * @param proc function to call with result * @param proc_cls closure for 'proc' * @return handle to cancel the operation */ struct GSF_StreamRequest * GSF_stream_query (const struct GNUNET_PeerIdentity *target, const struct GNUNET_HashCode *query, enum GNUNET_BLOCK_Type type, GSF_StreamReplyProcessor proc, void *proc_cls) { struct StreamHandle *sh; struct GSF_StreamRequest *sr; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Preparing to send query for %s via stream to %s\n", GNUNET_h2s (query), GNUNET_i2s (target)); sh = get_stream (target); sr = GNUNET_malloc (sizeof (struct GSF_StreamRequest)); sr->sh = sh; sr->proc = proc; sr->proc_cls = proc_cls; sr->type = type; sr->query = *query; GNUNET_CONTAINER_DLL_insert (sh->pending_head, sh->pending_tail, sr); if (GNUNET_YES == sh->is_ready) transmit_pending (sh); return sr; }
/** * Start monitoring the local DHT service. * * @param handle Handle to the DHT service. * @param type Type of blocks that are of interest. * @param key Key of data of interest, NULL for all. * @param get_cb Callback to process monitored get messages. * @param get_resp_cb Callback to process monitored get response messages. * @param put_cb Callback to process monitored put messages. * @param cb_cls Closure for callbacks. * @return Handle to stop monitoring. */ struct GNUNET_DHT_MonitorHandle * GNUNET_DHT_monitor_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode *key, GNUNET_DHT_MonitorGetCB get_cb, GNUNET_DHT_MonitorGetRespCB get_resp_cb, GNUNET_DHT_MonitorPutCB put_cb, void *cb_cls) { struct GNUNET_DHT_MonitorHandle *h; struct GNUNET_DHT_MonitorStartStopMessage *m; struct PendingMessage *pending; h = GNUNET_new (struct GNUNET_DHT_MonitorHandle); GNUNET_CONTAINER_DLL_insert(handle->monitor_head, handle->monitor_tail, h); h->get_cb = get_cb; h->get_resp_cb = get_resp_cb; h->put_cb = put_cb; h->cb_cls = cb_cls; h->type = type; h->dht_handle = handle; if (NULL != key) { h->key = GNUNET_new (struct GNUNET_HashCode); *h->key = *key; }
/** * Activity on our listen socket. Accept the * incoming connection. * * @param cls the `struct GNUNET_NAT_Test` * @param tc scheduler context */ static void do_accept (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_NAT_Test *tst = cls; struct GNUNET_NETWORK_Handle *s; struct NatActivity *wl; tst->ltask = NULL; if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) return; tst->ltask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, tst->lsock, &do_accept, tst); s = GNUNET_NETWORK_socket_accept (tst->lsock, NULL, NULL); if (NULL == s) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, "accept"); return; /* odd error */ } LOG (GNUNET_ERROR_TYPE_DEBUG, "Got an inbound connection, waiting for data\n"); wl = GNUNET_new (struct NatActivity); wl->sock = s; wl->h = tst; wl->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, wl->sock, &do_read, wl); GNUNET_CONTAINER_DLL_insert (tst->na_head, tst->na_tail, wl); }
/** * Disconnect from service and then reconnect. * * @param handle our handle */ static void force_reconnect (struct GNUNET_GNS_Handle *handle) { struct GNUNET_GNS_ShortenRequest *st; struct GNUNET_GNS_LookupRequest *lh; struct GNUNET_GNS_GetAuthRequest *ga; struct PendingMessage *p; GNUNET_CLIENT_disconnect (handle->client); handle->client = NULL; handle->in_receive = GNUNET_NO; for (st = handle->shorten_head; NULL != st; st = st->next) { p = (struct PendingMessage *) &st[1]; if (GNUNET_NO == p->transmitted) continue; p->transmitted = GNUNET_NO; GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, p); } for (lh = handle->lookup_head; NULL != lh; lh = lh->next) { p = (struct PendingMessage *) &lh[1]; if (GNUNET_NO == p->transmitted) continue; p->transmitted = GNUNET_NO; GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, p); } for (ga = handle->get_auth_head; NULL != ga; ga = ga->next) { p = (struct PendingMessage *) &ga[1]; if (GNUNET_NO == p->transmitted) continue; p->transmitted = GNUNET_NO; GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, p); } handle->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff); handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff, &reconnect_task, handle); }
/** * Client asked to resolve an address. Process the request. * * @param cls unused * @param client the client * @param message the resolution request */ static void clients_handle_address_to_string (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AddressLookupMessage *alum; struct GNUNET_TRANSPORT_PluginFunctions *papi; const char *plugin_name; const char *address; uint32_t address_len; uint16_t size; struct GNUNET_SERVER_TransmitContext *tc; struct AddressToStringContext *actx; struct GNUNET_TIME_Relative rtimeout; int32_t numeric; size = ntohs (message->size); if (size < sizeof (struct AddressLookupMessage)) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } alum = (const struct AddressLookupMessage *) message; address_len = ntohs (alum->addrlen); if (size <= sizeof (struct AddressLookupMessage) + address_len) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } address = (const char *) &alum[1]; plugin_name = (const char *) &address[address_len]; if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1]) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout); numeric = ntohs (alum->numeric_only); tc = GNUNET_SERVER_transmit_context_create (client); papi = GST_plugins_printer_find (plugin_name); if (NULL == papi) { GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); GNUNET_SERVER_transmit_context_run (tc, rtimeout); return; } actx = GNUNET_new (struct AddressToStringContext); actx->tc = tc; GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx); GNUNET_SERVER_disable_receive_done_warning (client); papi->address_pretty_printer (papi->cls, plugin_name, address, address_len, numeric, rtimeout, &transmit_address_to_client, actx); }
/** * 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; }
/** * 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; }
/** * Our current client connection went down. Clean it up * and try to reconnect! * * @param h our handle to the core service */ static void reconnect (struct GNUNET_CORE_Handle *h) { struct ControlMessage *cm; struct InitMessage *init; uint32_t opt; uint16_t msize; uint16_t *ts; unsigned int hpos; GNUNET_assert (NULL == h->client); GNUNET_assert (GNUNET_YES == h->currently_down); GNUNET_assert (NULL != h->cfg); h->client = GNUNET_CLIENT_connect ("core", h->cfg); if (NULL == h->client) { reconnect_later (h); return; } msize = h->hcnt * sizeof (uint16_t) + sizeof (struct InitMessage); cm = GNUNET_malloc (sizeof (struct ControlMessage) + msize); cm->cont = &init_done_task; cm->cont_cls = h; init = (struct InitMessage *) &cm[1]; init->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT); init->header.size = htons (msize); opt = 0; if (h->inbound_notify != NULL) { if (h->inbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_INBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_INBOUND; } if (h->outbound_notify != NULL) { if (h->outbound_hdr_only) opt |= GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND; else opt |= GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND; } LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service, monitoring messages of type %u\n", opt); init->options = htonl (opt); ts = (uint16_t *) & init[1]; for (hpos = 0; hpos < h->hcnt; hpos++) ts[hpos] = htons (h->handlers[hpos].type); GNUNET_CONTAINER_DLL_insert (h->control_pending_head, h->control_pending_tail, cm); trigger_next_request (h, GNUNET_YES); }
/** * Prepare a statement. Prepared statements are automatically discarded * when the MySQL context is destroyed. * * @param mc mysql context * @param query query text * @return prepared statement, NULL on error */ struct GNUNET_MYSQL_StatementHandle * GNUNET_MYSQL_statement_prepare (struct GNUNET_MYSQL_Context *mc, const char *query) { struct GNUNET_MYSQL_StatementHandle *sh; sh = GNUNET_new (struct GNUNET_MYSQL_StatementHandle); sh->mc = mc; sh->query = GNUNET_strdup (query); GNUNET_CONTAINER_DLL_insert (mc->shead, mc->stail, sh); return sh; }
/** * Perform an asynchronous GET operation on the DHT identified. See * also #GNUNET_BLOCK_evaluate. * * @param handle handle to the DHT service * @param type expected type of the response object * @param key the key to look up * @param desired_replication_level estimate of how many nearest peers this request should reach * @param options routing options for this message * @param xquery extended query data (can be NULL, depending on type) * @param xquery_size number of bytes in @a xquery * @param iter function to call on each result * @param iter_cls closure for iter * @return handle to stop the async get */ struct GNUNET_DHT_GetHandle * GNUNET_DHT_get_start (struct GNUNET_DHT_Handle *handle, enum GNUNET_BLOCK_Type type, const struct GNUNET_HashCode * key, uint32_t desired_replication_level, enum GNUNET_DHT_RouteOption options, const void *xquery, size_t xquery_size, GNUNET_DHT_GetIterator iter, void *iter_cls) { struct GNUNET_DHT_ClientGetMessage *get_msg; struct GNUNET_DHT_GetHandle *get_handle; size_t msize; struct PendingMessage *pending; msize = sizeof (struct GNUNET_DHT_ClientGetMessage) + xquery_size; if ((msize >= GNUNET_SERVER_MAX_MESSAGE_SIZE) || (xquery_size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)) { GNUNET_break (0); return NULL; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending query for %s to DHT %p\n", GNUNET_h2s (key), handle); pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize); get_msg = (struct GNUNET_DHT_ClientGetMessage *) &pending[1]; pending->msg = &get_msg->header; pending->handle = handle; pending->free_on_send = GNUNET_NO; get_msg->header.size = htons (msize); get_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET); get_msg->options = htonl ((uint32_t) options); get_msg->desired_replication_level = htonl (desired_replication_level); get_msg->type = htonl (type); get_msg->key = *key; get_msg->unique_id = ++handle->uid_gen; memcpy (&get_msg[1], xquery, xquery_size); GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; get_handle = GNUNET_new (struct GNUNET_DHT_GetHandle); get_handle->key = *key; get_handle->dht_handle = handle; get_handle->iter = iter; get_handle->iter_cls = iter_cls; get_handle->message = pending; get_handle->unique_id = get_msg->unique_id; GNUNET_CONTAINER_multihashmap_put (handle->active_requests, &get_handle->key, get_handle, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); process_pending_messages (handle); return get_handle; }
/** * Handle ANNOUNCE message. * * @param cls closure * @param client identification of the client * @param message the actual message */ static void handle_announce (void *cls, struct GNUNET_SERVER_Client *client, const struct GNUNET_MessageHeader *message) { const struct AnnounceMessage *am; const char *regex; struct ClientEntry *ce; uint16_t size; size = ntohs (message->size); am = (const struct AnnounceMessage *) message; regex = (const char *) &am[1]; if ( (size <= sizeof (struct AnnounceMessage)) || ('\0' != regex[size - sizeof (struct AnnounceMessage) - 1]) ) { GNUNET_break (0); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } ce = GNUNET_new (struct ClientEntry); ce->client = client; ce->frequency = GNUNET_TIME_relative_ntoh (am->refresh_delay); ce->refresh_task = GNUNET_SCHEDULER_add_delayed (ce->frequency, &reannounce, ce); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting to announce regex `%s' every %s\n", regex, GNUNET_STRINGS_relative_time_to_string (ce->frequency, GNUNET_NO)); ce->ah = REGEX_INTERNAL_announce (dht, my_private_key, regex, ntohs (am->compression), stats); if (NULL == ce->ah) { GNUNET_break (0); GNUNET_SCHEDULER_cancel (ce->refresh_task); GNUNET_free (ce); GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); return; } GNUNET_CONTAINER_DLL_insert (client_head, client_tail, ce); GNUNET_SERVER_receive_done (client, GNUNET_OK); }
/** * Stop async DHT-get. * * @param get_handle handle to the GET operation to stop */ void GNUNET_DHT_get_stop (struct GNUNET_DHT_GetHandle *get_handle) { struct GNUNET_DHT_Handle *handle; const struct GNUNET_DHT_ClientGetMessage *get_msg; struct GNUNET_DHT_ClientGetStopMessage *stop_msg; struct PendingMessage *pending; handle = get_handle->message->handle; get_msg = (const struct GNUNET_DHT_ClientGetMessage *) get_handle->message->msg; LOG (GNUNET_ERROR_TYPE_DEBUG, "Sending STOP for %s to DHT via %p\n", GNUNET_h2s (&get_msg->key), handle); /* generate STOP */ pending = GNUNET_malloc (sizeof (struct PendingMessage) + sizeof (struct GNUNET_DHT_ClientGetStopMessage)); stop_msg = (struct GNUNET_DHT_ClientGetStopMessage *) &pending[1]; pending->msg = &stop_msg->header; pending->handle = handle; pending->free_on_send = GNUNET_YES; stop_msg->header.size = htons (sizeof (struct GNUNET_DHT_ClientGetStopMessage)); stop_msg->header.type = htons (GNUNET_MESSAGE_TYPE_DHT_CLIENT_GET_STOP); stop_msg->reserved = htonl (0); stop_msg->unique_id = get_msg->unique_id; stop_msg->key = get_msg->key; GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail, pending); pending->in_pending_queue = GNUNET_YES; /* remove 'GET' from active status */ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (handle->active_requests, &get_handle->key, get_handle)); if (GNUNET_YES == get_handle->message->in_pending_queue) { GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail, get_handle->message); get_handle->message->in_pending_queue = GNUNET_NO; } GNUNET_free (get_handle->message); GNUNET_array_grow (get_handle->seen_results, get_handle->seen_results_end, 0); GNUNET_free (get_handle); process_pending_messages (handle); }