/** * Get a random item for replication. Returns a single, not expired, * random item from those with the highest replication counters. The * item's replication counter is decremented by one IF it was positive * before. Call 'proc' with all values ZERO or NULL if the datastore * is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void mysql_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct ReplCtx rc; unsigned long long rvalue; unsigned long repl; MYSQL_BIND results; rc.plugin = plugin; rc.proc = proc; rc.proc_cls = proc_cls; memset (&results, 0, sizeof (results)); results.buffer_type = MYSQL_TYPE_LONG; results.buffer = &repl; results.is_unsigned = GNUNET_YES; if (1 != GNUNET_MYSQL_statement_run_prepared_select (plugin->mc, plugin->max_repl, 1, &results, NULL, NULL, -1)) { proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } rvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); execute_select (plugin, plugin->select_replication, &repl_proc, &rc, MYSQL_TYPE_LONG, &repl, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, MYSQL_TYPE_LONG, &repl, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, -1); }
/** * Get a zero-anonymity datum from the datastore. * * @param cls our "struct Plugin*" * @param offset offset of the result * @param type entries of which type should be considered? * Use 0 for any type. * @param proc function to call on a matching value or NULL * @param proc_cls closure for iter */ static void mysql_plugin_get_zero_anonymity (void *cls, uint64_t offset, enum GNUNET_BLOCK_Type type, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; unsigned long long rvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); execute_select (plugin, plugin->zero_iter, proc, proc_cls, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONGLONG, &rvalue, GNUNET_YES, -1); }
/** * 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 mysql_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; unsigned int irepl = replication; unsigned int ipriority = priority; unsigned int ianonymity = anonymity; unsigned long long lexpiration = expiration.abs_value_us; unsigned long long lrvalue = (unsigned long long) GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); unsigned long hashSize; unsigned long hashSize2; unsigned long lsize; struct GNUNET_HashCode vhash; if (size > MAX_DATUM_SIZE) { GNUNET_break (0); return GNUNET_SYSERR; } hashSize = sizeof (struct GNUNET_HashCode); hashSize2 = sizeof (struct GNUNET_HashCode); lsize = size; GNUNET_CRYPTO_hash (data, size, &vhash); if (GNUNET_OK != GNUNET_MYSQL_statement_run_prepared (plugin->mc, plugin->insert_entry, NULL, MYSQL_TYPE_LONG, &irepl, GNUNET_YES, MYSQL_TYPE_LONG, &type, GNUNET_YES, MYSQL_TYPE_LONG, &ipriority, GNUNET_YES, MYSQL_TYPE_LONG, &ianonymity, GNUNET_YES, MYSQL_TYPE_LONGLONG, &lexpiration, GNUNET_YES, MYSQL_TYPE_LONGLONG, &lrvalue, GNUNET_YES, MYSQL_TYPE_BLOB, key, hashSize, &hashSize, MYSQL_TYPE_BLOB, &vhash, hashSize2, &hashSize2, MYSQL_TYPE_BLOB, data, lsize, &lsize, -1)) return GNUNET_SYSERR; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Inserted value `%s' with size %u into gn090 table\n", GNUNET_h2s (key), (unsigned int) size); if (size > 0) plugin->env->duc (plugin->env->cls, size); return GNUNET_OK; }
/** * Initialize the connection with the DHT service. * * @param cfg configuration to use * @param ht_len size of the internal hash table to use for * processing multiple GET/FIND requests in parallel * @return handle to the DHT service, or NULL on error */ struct GNUNET_DHT_Handle * GNUNET_DHT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, unsigned int ht_len) { struct GNUNET_DHT_Handle *handle; handle = GNUNET_new (struct GNUNET_DHT_Handle); handle->cfg = cfg; handle->uid_gen = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); handle->active_requests = GNUNET_CONTAINER_multihashmap_create (ht_len, GNUNET_YES); if (GNUNET_NO == try_connect (handle)) { GNUNET_DHT_disconnect (handle); return NULL; } return handle; }
/** * Get the transmission delay that should be applied for a * particular round. * * @param round_offset -1 for the previous round (random delay between 0 and 50ms) * 0 for the current round (based on our proximity to time key) * @return delay that should be applied */ static struct GNUNET_TIME_Relative get_transmit_delay (int round_offset) { struct GNUNET_TIME_Relative ret; struct GNUNET_TIME_Absolute tgt; double dist_delay; uint32_t matching_bits; switch (round_offset) { case -1: /* previous round is randomized between 0 and 50 ms */ #if USE_RANDOM_DELAYS ret.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, 50); #else ret = GNUNET_TIME_UNIT_ZERO; #endif GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting previous round behind schedule in %s\n", GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES)); return ret; case 0: /* current round is based on best-known matching_bits */ matching_bits = ntohl (size_estimate_messages[estimate_index].matching_bits); dist_delay = get_matching_bits_delay (matching_bits); dist_delay += get_delay_randomization (matching_bits).rel_value_us; ret.rel_value_us = (uint64_t) dist_delay; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "For round %s, delay for %u matching bits is %s\n", GNUNET_STRINGS_absolute_time_to_string (current_timestamp), (unsigned int) matching_bits, GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES)); /* now consider round start time and add delay to it */ tgt = GNUNET_TIME_absolute_add (current_timestamp, ret); return GNUNET_TIME_absolute_get_remaining (tgt); } GNUNET_break (0); return GNUNET_TIME_UNIT_FOREVER_REL; }
/** * Get a random item for replication. Returns a single random item * from those with the highest replication counters. The item's * replication counter is decremented by one IF it was positive before. * Call 'proc' with all values ZERO or NULL if the datastore is empty. * * @param cls closure * @param proc function to call the value (once only). * @param proc_cls closure for proc */ static void sqlite_plugin_get_replication (void *cls, PluginDatumProcessor proc, void *proc_cls) { struct Plugin *plugin = cls; struct ReplCtx rc; uint64_t rvalue; uint32_t repl; sqlite3_stmt *stmt; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Getting random block based on replication order.\n"); rc.have_uid = GNUNET_NO; rc.proc = proc; rc.proc_cls = proc_cls; stmt = plugin->maxRepl; if (SQLITE_ROW != sqlite3_step (stmt)) { if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); /* DB empty */ proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } repl = sqlite3_column_int (stmt, 0); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); stmt = plugin->selRepl; rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, rvalue)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } if (SQLITE_OK != sqlite3_bind_int (stmt, 2, repl)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); proc (proc_cls, NULL, 0, NULL, 0, 0, 0, GNUNET_TIME_UNIT_ZERO_ABS, 0); return; } execute_get (plugin, stmt, &repl_proc, &rc); if (GNUNET_YES == rc.have_uid) { if (SQLITE_OK != sqlite3_bind_int64 (plugin->updRepl, 1, rc.uid)) { LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return; } if (SQLITE_DONE != sqlite3_step (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (plugin->updRepl)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); } }
/** * 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 an error message * @return GNUNET_OK on success */ static int sqlite_plugin_put (void *cls, const 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; int n; int ret; sqlite3_stmt *stmt; GNUNET_HashCode vhash; uint64_t rvalue; if (size > MAX_ITEM_SIZE) return GNUNET_SYSERR; GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Storing in database block with type %u/key `%s'/priority %u/expiration in %llu ms (%lld).\n", type, GNUNET_h2s (key), priority, (unsigned long long) GNUNET_TIME_absolute_get_remaining (expiration).rel_value, (long long) expiration.abs_value); GNUNET_CRYPTO_hash (data, size, &vhash); stmt = plugin->insertContent; rvalue = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX); if ((SQLITE_OK != sqlite3_bind_int (stmt, 1, replication)) || (SQLITE_OK != sqlite3_bind_int (stmt, 2, type)) || (SQLITE_OK != sqlite3_bind_int (stmt, 3, priority)) || (SQLITE_OK != sqlite3_bind_int (stmt, 4, anonymity)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 5, expiration.abs_value)) || (SQLITE_OK != sqlite3_bind_int64 (stmt, 6, rvalue)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 7, key, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 8, &vhash, sizeof (GNUNET_HashCode), SQLITE_TRANSIENT)) || (SQLITE_OK != sqlite3_bind_blob (stmt, 9, data, size, SQLITE_TRANSIENT))) { LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_bind_XXXX"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return GNUNET_SYSERR; } n = sqlite3_step (stmt); switch (n) { case SQLITE_DONE: plugin->env->duc (plugin->env->cls, size + GNUNET_DATASTORE_ENTRY_OVERHEAD); GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "sqlite", "Stored new entry (%u bytes)\n", size + GNUNET_DATASTORE_ENTRY_OVERHEAD); ret = GNUNET_OK; break; case SQLITE_BUSY: GNUNET_break (0); LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); ret = GNUNET_SYSERR; break; default: LOG_SQLITE (plugin, msg, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_step"); if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); database_shutdown (plugin); database_setup (plugin->env->cfg, plugin); return GNUNET_SYSERR; } if (SQLITE_OK != sqlite3_reset (stmt)) LOG_SQLITE (plugin, NULL, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "sqlite3_reset"); return ret; }