/** * Task triggered whenever we receive a SIGCHLD (child * process died). * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_DISK_FileHandle *pr; char c[16]; pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); child_death_task_id = NULL; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) { child_death_task_id = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &child_death_task, NULL); return; } /* consume the signal */ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); LOG_DEBUG ("Child died\n"); GNUNET_SCHEDULER_cancel (terminate_task_id); terminate_task_id = NULL; GNUNET_assert (GNUNET_OK == GNUNET_OS_process_status (child, &child_status, &child_exit_code)); GNUNET_OS_process_destroy (child); child = NULL; shutdown_task_id = GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); }
static void read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { int bytes; bytes = GNUNET_DISK_file_read (rc.stdout_read_handle, &rc.buf[rc.buf_offset], \ sizeof (rc.buf) - rc.buf_offset); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "bytes is %d\n", bytes); if (bytes < 1) { GNUNET_break (0); ok = 1; GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } ok = strncmp (rc.buf, test_phrase, strlen (test_phrase)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "read %s\n", &rc.buf[rc.buf_offset]); rc.buf_offset += bytes; if (0 == ok) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, rc.stdout_read_handle, &read_call, NULL); }
/** * @brief Restore the peers on disk to #valid_peers. */ static void restore_valid_peers () { off_t file_size; uint32_t num_peers; struct GNUNET_DISK_FileHandle *fh; char *buf; ssize_t size_read; char *iter_buf; char *str_repr; const struct GNUNET_PeerIdentity *peer; if (0 == strncmp ("DISABLE", filename_valid_peers, 7)) { return; } if (GNUNET_OK != GNUNET_DISK_file_test (filename_valid_peers)) { return; } fh = GNUNET_DISK_file_open (filename_valid_peers, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); GNUNET_assert (NULL != fh); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_handle_size (fh, &file_size)); num_peers = file_size / 53; buf = GNUNET_malloc (file_size); size_read = GNUNET_DISK_file_read (fh, buf, file_size); GNUNET_assert (size_read == file_size); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restoring %" PRIu32 " peers from file `%s'\n", num_peers, filename_valid_peers); for (iter_buf = buf; iter_buf < buf + file_size - 1; iter_buf += 53) { str_repr = GNUNET_strndup (iter_buf, 53); peer = s2i_full (str_repr); GNUNET_free (str_repr); add_valid_peer (peer); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restored valid peer %s from disk\n", GNUNET_i2s_full (peer)); } iter_buf = NULL; GNUNET_free (buf); LOG (GNUNET_ERROR_TYPE_DEBUG, "num_peers: %" PRIu32 ", _size (valid_peers): %u\n", num_peers, GNUNET_CONTAINER_multipeermap_size (valid_peers)); if (num_peers != GNUNET_CONTAINER_multipeermap_size (valid_peers)) { LOG (GNUNET_ERROR_TYPE_WARNING, "Number of restored peers does not match file size. Have probably duplicates.\n"); } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); LOG (GNUNET_ERROR_TYPE_DEBUG, "Restored %u valid peers from disk\n", GNUNET_CONTAINER_multipeermap_size (valid_peers)); }
/** * File hashing task. * * @param cls closure * @param tc context */ static void file_hash_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_CRYPTO_FileHashContext *fhc = cls; struct GNUNET_HashCode *res; size_t delta; fhc->task = GNUNET_SCHEDULER_NO_TASK; GNUNET_assert (fhc->offset <= fhc->fsize); delta = fhc->bsize; if (fhc->fsize - fhc->offset < delta) delta = fhc->fsize - fhc->offset; if (delta != GNUNET_DISK_file_read (fhc->fh, fhc->buffer, delta)) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", fhc->filename); file_hash_finish (fhc, NULL); return; } gcry_md_write (fhc->md, fhc->buffer, delta); fhc->offset += delta; if (fhc->offset == fhc->fsize) { res = (struct GNUNET_HashCode *) gcry_md_read (fhc->md, GCRY_MD_SHA512); file_hash_finish (fhc, res); return; } fhc->task = GNUNET_SCHEDULER_add_with_priority (fhc->priority, &file_hash_task, fhc); }
/** * Get the namespace ID belonging to the given namespace name. * * @param cfg configuration to use * @param ns_uname unique (!) human-readable name for the namespace * @param nsid set to namespace ID based on 'ns_uname' * @return GNUNET_OK on success, GNUNET_SYSERR on failure */ int GNUNET_PSEUDONYM_name_to_id (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *ns_uname, struct GNUNET_HashCode * nsid) { size_t slen; uint64_t len; unsigned int idx; char *name; struct GNUNET_HashCode nh; char *fn; struct GNUNET_DISK_FileHandle *fh; idx = -1; slen = strlen (ns_uname); while ((slen > 0) && (1 != SSCANF (&ns_uname[slen - 1], "-%u", &idx))) slen--; if (slen == 0) return GNUNET_SYSERR; name = GNUNET_strdup (ns_uname); name[slen - 1] = '\0'; GNUNET_CRYPTO_hash (name, strlen (name), &nh); GNUNET_free (name); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); if ((GNUNET_OK != GNUNET_DISK_file_test (fn) || (GNUNET_OK != GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES))) || ((idx + 1) * sizeof (struct GNUNET_HashCode) > len)) { GNUNET_free (fn); return GNUNET_SYSERR; } fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); GNUNET_free (fn); if (GNUNET_SYSERR == GNUNET_DISK_file_seek (fh, idx * sizeof (struct GNUNET_HashCode), GNUNET_DISK_SEEK_SET)) { GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } if (sizeof (struct GNUNET_HashCode) != GNUNET_DISK_file_read (fh, nsid, sizeof (struct GNUNET_HashCode))) { GNUNET_DISK_file_close (fh); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); return GNUNET_OK; }
/** * Return unique variant of the namespace name. * Use it after GNUNET_PSEUDONYM_get_info() to make sure * that name is unique. * * @param cfg configuration * @param nsid cryptographic ID of the namespace * @param name name to uniquify * @param suffix if not NULL, filled with the suffix value * @return NULL on failure (should never happen), name on success. * Free the name with GNUNET_free(). */ char * GNUNET_PSEUDONYM_name_uniquify (const struct GNUNET_CONFIGURATION_Handle *cfg, const struct GNUNET_HashCode * nsid, const char *name, unsigned int *suffix) { struct GNUNET_HashCode nh; uint64_t len; char *fn; struct GNUNET_DISK_FileHandle *fh; unsigned int i; unsigned int idx; char *ret; struct stat sbuf; GNUNET_CRYPTO_hash (name, strlen (name), &nh); fn = get_data_filename (cfg, PS_NAMES_DIR, &nh); GNUNET_assert (fn != NULL); len = 0; if (0 == STAT (fn, &sbuf)) GNUNET_break (GNUNET_OK == GNUNET_DISK_file_size (fn, &len, GNUNET_YES, GNUNET_YES)); fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); i = 0; idx = -1; while ((len >= sizeof (struct GNUNET_HashCode)) && (sizeof (struct GNUNET_HashCode) == GNUNET_DISK_file_read (fh, &nh, sizeof (struct GNUNET_HashCode)))) { if (0 == memcmp (&nh, nsid, sizeof (struct GNUNET_HashCode))) { idx = i; break; } i++; len -= sizeof (struct GNUNET_HashCode); } if (idx == -1) { idx = i; if (sizeof (struct GNUNET_HashCode) != GNUNET_DISK_file_write (fh, nsid, sizeof (struct GNUNET_HashCode))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "write", fn); } GNUNET_DISK_file_close (fh); ret = GNUNET_malloc (strlen (name) + 32); GNUNET_snprintf (ret, strlen (name) + 32, "%s-%u", name, idx); if (suffix != NULL) *suffix = idx; GNUNET_free (fn); return ret; }
/** * Clears a bit from bitArray if the respective usage * counter on the disk hits/is zero. * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test * @param fh A file to keep the 4bit address usage counters in */ static void decrementBit (char *bitArray, unsigned int bitIdx, const struct GNUNET_DISK_FileHandle *fh) { off_t fileslot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; if (GNUNET_DISK_handle_invalid (fh)) return; /* cannot decrement! */ /* Each char slot in the counter file holds two 4 bit counters */ fileslot = bitIdx / 2; targetLoc = bitIdx % 2; if (GNUNET_SYSERR == GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek"); return; } if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & 0xF0) >> 4; /* decrement, but once we have reached the max, never go back! */ if (targetLoc == 0) { if ((low > 0) && (low < 0xF)) low--; if (low == 0) { clearBit (bitArray, bitIdx); } } else { if ((high > 0) && (high < 0xF)) high--; if (high == 0) { clearBit (bitArray, bitIdx); } } value = ((high << 4) | low); if (GNUNET_SYSERR == GNUNET_DISK_file_seek (fh, fileslot, GNUNET_DISK_SEEK_SET)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "seek"); return; } GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); }
/** * Read the output of `external-ip` into `buf`. When complete, parse * the address and call our callback. * * @param cls the `struct GNUNET_NAT_ExternalHandle` */ static void read_external_ipv4 (void *cls) { struct GNUNET_NAT_ExternalHandle *eh = cls; ssize_t ret; struct in_addr addr; eh->task = NULL; ret = GNUNET_DISK_file_read (eh->r, &eh->buf[eh->off], sizeof (eh->buf) - eh->off); if (ret > 0) { /* try to read more */ eh->off += ret; eh->task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, eh->r, &read_external_ipv4, eh); return; } eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID; if ( (eh->off > 7) && (eh->buf[eh->off - 1] == '\n') ) { eh->buf[eh->off - 1] = '\0'; if (1 == inet_pton (AF_INET, eh->buf, &addr)) { if (0 == addr.s_addr) eh->ret = GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID; /* got 0.0.0.0 */ else eh->ret = GNUNET_NAT_ERROR_SUCCESS; } } eh->cb (eh->cb_cls, (GNUNET_NAT_ERROR_SUCCESS == eh->ret) ? &addr : NULL, eh->ret); GNUNET_NAT_mini_get_external_ipv4_cancel_ (eh); }
static void read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; char buf[16]; memset (&buf, 0, sizeof (buf)); int bytes; bytes = GNUNET_DISK_file_read (stdout_read_handle, &buf, sizeof (buf)); #if VERBOSE FPRINTF (stderr, "bytes is %d\n", bytes); #endif if (bytes < 1) { GNUNET_break (0); ok = 1; GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } ok = strncmp (&buf[0], test_phrase, strlen (test_phrase)); #if VERBOSE FPRINTF (stderr, "read %s\n", &buf[0]); #endif if (ok == 0) { GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, stdout_read_handle); }
/** * Sets a bit active in the bitArray and increments * bit-specific usage counter on disk (but only if * the counter was below 4 bit max (==15)). * * @param bitArray memory area to set the bit in * @param bitIdx which bit to test * @param fh A file to keep the 4 bit address usage counters in */ static void incrementBit (char *bitArray, unsigned int bitIdx, const struct GNUNET_DISK_FileHandle *fh) { OFF_T fileSlot; unsigned char value; unsigned int high; unsigned int low; unsigned int targetLoc; setBit (bitArray, bitIdx); if (GNUNET_DISK_handle_invalid (fh)) return; /* Update the counter file on disk */ fileSlot = bitIdx / 2; targetLoc = bitIdx % 2; GNUNET_assert (fileSlot == GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); if (1 != GNUNET_DISK_file_read (fh, &value, 1)) value = 0; low = value & 0xF; high = (value & (~0xF)) >> 4; if (targetLoc == 0) { if (low < 0xF) low++; } else { if (high < 0xF) high++; } value = ((high << 4) | low); GNUNET_assert (fileSlot == GNUNET_DISK_file_seek (fh, fileSlot, GNUNET_DISK_SEEK_SET)); GNUNET_assert (1 == GNUNET_DISK_file_write (fh, &value, 1)); }
/** * Function called by the tree encoder to obtain * a block of plaintext data (for the lowest level * of the tree). * * @param cls our publishing context * @param offset identifies which block to get * @param max (maximum) number of bytes to get; returning * fewer will also cause errors * @param buf where to copy the plaintext buffer * @param emsg location to store an error message (on error) * @return number of bytes copied to buf, 0 on error */ static size_t unindex_reader (void *cls, uint64_t offset, size_t max, void *buf, char **emsg) { struct GNUNET_FS_UnindexContext *uc = cls; size_t pt_size; pt_size = GNUNET_MIN (max, uc->file_size - offset); if (offset != GNUNET_DISK_file_seek (uc->fh, offset, GNUNET_DISK_SEEK_SET)) { *emsg = GNUNET_strdup (_("Failed to find given position in file")); return 0; } if (pt_size != GNUNET_DISK_file_read (uc->fh, buf, pt_size)) { *emsg = GNUNET_strdup (_("Failed to read file")); return 0; } return pt_size; }
/** * We've received an on-demand encoded block from the datastore. * Attempt to do on-demand encoding and (if successful), call the * continuation with the resulting block. On error, clean up and ask * the datastore for more results. * * @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 * @param cont function to call with the actual block (at most once, on success) * @param cont_cls closure for cont * @return GNUNET_OK on success */ int GNUNET_FS_handle_on_demand_block (const struct GNUNET_HashCode * key, uint32_t size, const void *data, enum GNUNET_BLOCK_Type type, uint32_t priority, uint32_t anonymity, struct GNUNET_TIME_Absolute expiration, uint64_t uid, GNUNET_DATASTORE_DatumProcessor cont, void *cont_cls) { const struct OnDemandBlock *odb; struct GNUNET_HashCode nkey; struct GNUNET_CRYPTO_AesSessionKey skey; struct GNUNET_CRYPTO_AesInitializationVector iv; struct GNUNET_HashCode query; ssize_t nsize; char ndata[DBLOCK_SIZE]; char edata[DBLOCK_SIZE]; const char *fn; struct GNUNET_DISK_FileHandle *fh; uint64_t off; struct IndexInfo *ii; if (size != sizeof (struct OnDemandBlock)) { GNUNET_break (0); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } odb = (const struct OnDemandBlock *) data; off = GNUNET_ntohll (odb->offset); ii = GNUNET_CONTAINER_multihashmap_get (ifm, &odb->file_id); if (NULL == ii) { GNUNET_break (0); return GNUNET_SYSERR; } fn = ii->filename; if ((NULL == fn) || (0 != ACCESS (fn, R_OK))) { GNUNET_STATISTICS_update (GSF_stats, gettext_noop ("# index blocks removed: original file inaccessible"), 1, GNUNET_YES); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } if ((NULL == (fh = GNUNET_DISK_file_open (fn, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE))) || (off != GNUNET_DISK_file_seek (fh, off, GNUNET_DISK_SEEK_SET)) || (-1 == (nsize = GNUNET_DISK_file_read (fh, ndata, sizeof (ndata))))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _ ("Could not access indexed file `%s' (%s) at offset %llu: %s\n"), GNUNET_h2s (&odb->file_id), fn, (unsigned long long) off, (fn == NULL) ? _("not indexed") : STRERROR (errno)); if (fh != NULL) GNUNET_DISK_file_close (fh); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); GNUNET_CRYPTO_hash (ndata, nsize, &nkey); GNUNET_CRYPTO_hash_to_aes_key (&nkey, &skey, &iv); GNUNET_CRYPTO_aes_encrypt (ndata, nsize, &skey, &iv, edata); GNUNET_CRYPTO_hash (edata, nsize, &query); if (0 != memcmp (&query, key, sizeof (struct GNUNET_HashCode))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Indexed file `%s' changed at offset %llu\n"), fn, (unsigned long long) off); GNUNET_DATASTORE_remove (dsh, key, size, data, -1, -1, GNUNET_TIME_UNIT_FOREVER_REL, &remove_cont, NULL); return GNUNET_SYSERR; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "On-demand encoded block for query `%s'\n", GNUNET_h2s (key)); cont (cont_cls, key, nsize, edata, GNUNET_BLOCK_TYPE_FS_DBLOCK, priority, anonymity, expiration, uid); return GNUNET_OK; }
/** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param plugin the plugin context (state for this module) * @return #GNUNET_OK on success */ static int database_setup (struct Plugin *plugin) { char *afsdir; char* block_buffer; char* buffer; char* line; char* query; char* block; size_t size; struct FlatFileEntry *entry; struct GNUNET_DISK_FileHandle *fh; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "namecache-flat", "FILENAME", &afsdir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "namecache-flat", "FILENAME"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } } /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ plugin->fn = afsdir; /* Load data from file into hashmap */ plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); fh = GNUNET_DISK_file_open (afsdir, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize file: %s.\n"), afsdir); return GNUNET_SYSERR; } if (GNUNET_SYSERR == GNUNET_DISK_file_size (afsdir, &size, GNUNET_YES, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to get filesize: %s.\n"), afsdir); return GNUNET_SYSERR; } if (0 == size) return GNUNET_OK; buffer = GNUNET_malloc (size); if (GNUNET_SYSERR == GNUNET_DISK_file_read (fh, buffer, size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to read file: %s.\n"), afsdir); return GNUNET_SYSERR; } GNUNET_DISK_file_close (fh); if (0 < size) { line = strtok (buffer, "\n"); while (line != NULL) { query = strtok (line, ","); if (NULL == query) break; block = strtok (NULL, ","); if (NULL == block) break; line = strtok (NULL, "\n"); entry = GNUNET_malloc (sizeof (struct FlatFileEntry)); GNUNET_CRYPTO_hash_from_string (query, &entry->query); GNUNET_STRINGS_base64_decode (block, strlen (block), &block_buffer); entry->block = (struct GNUNET_GNSRECORD_Block *) block_buffer; if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (plugin->hm, &entry->query, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_free (entry); GNUNET_break (0); } } } GNUNET_free (buffer); return GNUNET_OK; }
/** * Load a bloom-filter from a file. * * @param filename the name of the file (or the prefix) * @param size the size of the bloom-filter (number of * bytes of storage space to use); will be rounded up * to next power of 2 * @param k the number of GNUNET_CRYPTO_hash-functions to apply per * element (number of bits set per element in the set) * @return the bloomfilter */ struct GNUNET_CONTAINER_BloomFilter * GNUNET_CONTAINER_bloomfilter_load (const char *filename, size_t size, unsigned int k) { struct GNUNET_CONTAINER_BloomFilter *bf; char *rbuff; OFF_T pos; int i; size_t ui; OFF_T fsize; int must_read; GNUNET_assert (NULL != filename); if ((k == 0) || (size == 0)) return NULL; if (size < BUFFSIZE) size = BUFFSIZE; ui = 1; while ( (ui < size) && (ui * 2 > ui) ) ui *= 2; size = ui; /* make sure it's a power of 2 */ bf = GNUNET_malloc (sizeof (struct GNUNET_CONTAINER_BloomFilter)); /* Try to open a bloomfilter file */ if (GNUNET_YES == GNUNET_DISK_file_test (filename)) bf->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL != bf->fh) { /* file existed, try to read it! */ must_read = GNUNET_YES; if (GNUNET_OK != GNUNET_DISK_file_handle_size (bf->fh, &fsize)) { GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } if (fsize == 0) { /* found existing empty file, just overwrite */ if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } else if (fsize != size * 4LL) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Size of file on disk is incorrect for this Bloom filter (want %llu, have %llu)\n"), (unsigned long long) (size * 4LL), (unsigned long long) fsize); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } else { /* file did not exist, don't read, just create */ must_read = GNUNET_NO; bf->fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == bf->fh) { GNUNET_free (bf); return NULL; } if (GNUNET_OK != make_empty_file (bf->fh, size * 4LL)) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "write"); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } } bf->filename = GNUNET_strdup (filename); /* Alloc block */ bf->bitArray = GNUNET_malloc_large (size); if (bf->bitArray == NULL) { if (bf->fh != NULL) GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf->filename); GNUNET_free (bf); return NULL; } bf->bitArraySize = size; bf->addressesPerElement = k; if (GNUNET_YES != must_read) return bf; /* already done! */ /* Read from the file what bits we can */ rbuff = GNUNET_malloc (BUFFSIZE); pos = 0; while (pos < size * 8LL) { int res; res = GNUNET_DISK_file_read (bf->fh, rbuff, BUFFSIZE); if (res == -1) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "read", bf->filename); GNUNET_free (rbuff); GNUNET_free (bf->filename); GNUNET_DISK_file_close (bf->fh); GNUNET_free (bf); return NULL; } if (res == 0) break; /* is ok! we just did not use that many bits yet */ for (i = 0; i < res; i++) { if ((rbuff[i] & 0x0F) != 0) setBit (bf->bitArray, pos + i * 2); if ((rbuff[i] & 0xF0) != 0) setBit (bf->bitArray, pos + i * 2 + 1); } if (res < BUFFSIZE) break; pos += BUFFSIZE * 2; /* 2 bits per byte in the buffer */ } GNUNET_free (rbuff); return bf; }
int main (int argc, char *argv[]) { struct GNUNET_DISK_FileHandle *fh; struct GNUNET_HELLO_Message *orig; struct GNUNET_HELLO_Message *result; struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk; uint64_t fsize; GNUNET_log_setup ("gnunet-hello", "INFO", NULL); if (argc != 2) { FPRINTF (stderr, "%s", _("Call with name of HELLO file to modify.\n")); return 1; } if (GNUNET_OK != GNUNET_DISK_file_size (argv[1], &fsize, GNUNET_YES, GNUNET_YES)) { FPRINTF (stderr, _("Error accessing file `%s': %s\n"), argv[1], STRERROR (errno)); return 1; } if (fsize > 65536) { FPRINTF (stderr, _("File `%s' is too big to be a HELLO\n"), argv[1]); return 1; } if (fsize < sizeof (struct GNUNET_MessageHeader)) { FPRINTF (stderr, _("File `%s' is too small to be a HELLO\n"), argv[1]); return 1; } fh = GNUNET_DISK_file_open (argv[1], GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { FPRINTF (stderr, _("Error opening file `%s': %s\n"), argv[1], STRERROR (errno)); return 1; } { char buf[fsize] GNUNET_ALIGN; GNUNET_assert (fsize == GNUNET_DISK_file_read (fh, buf, fsize)); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); orig = (struct GNUNET_HELLO_Message *) buf; if ( (fsize != GNUNET_HELLO_size (orig)) || (GNUNET_OK != GNUNET_HELLO_get_key (orig, &pk)) ) { FPRINTF (stderr, _("Did not find well-formed HELLO in file `%s'\n"), argv[1]); return 1; } result = GNUNET_HELLO_create (&pk, &add_from_hello, &orig); GNUNET_assert (NULL != result); fh = GNUNET_DISK_file_open (argv[1], GNUNET_DISK_OPEN_WRITE, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fh) { FPRINTF (stderr, _("Error opening file `%s': %s\n"), argv[1], STRERROR (errno)); GNUNET_free (result); return 1; } fsize = GNUNET_HELLO_size (result); if (fsize != GNUNET_DISK_file_write (fh, result, fsize)) { FPRINTF (stderr, _("Error writing HELLO to file `%s': %s\n"), argv[1], STRERROR (errno)); (void) GNUNET_DISK_file_close (fh); return 1; } GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); } return 0; }
/** * Task triggered whenever we receive a SIGCHLD (child * process died). * * @param cls closure, NULL if we need to self-restart * @param tc context */ static void maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { struct ServiceList *pos; struct ServiceList *next; struct ServiceListeningInfo *sli; const char *statstr; int statcode; int ret; char c[16]; enum GNUNET_OS_ProcessStatusType statusType; unsigned long statusCode; const struct GNUNET_DISK_FileHandle *pr; pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ); child_death_task = GNUNET_SCHEDULER_NO_TASK; if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY)) { /* shutdown scheduled us, ignore! */ child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); return; } /* consume the signal */ GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c))); /* check for services that died (WAITPID) */ next = running_head; while (NULL != (pos = next)) { next = pos->next; if (pos->proc == NULL) { if (GNUNET_YES == in_shutdown) free_service (pos); continue; } if ((GNUNET_SYSERR == (ret = GNUNET_OS_process_status (pos->proc, &statusType, &statusCode))) || ((ret == GNUNET_NO) || (statusType == GNUNET_OS_PROCESS_STOPPED) || (statusType == GNUNET_OS_PROCESS_RUNNING))) continue; if (statusType == GNUNET_OS_PROCESS_EXITED) { statstr = _( /* process termination method */ "exit"); statcode = statusCode; } else if (statusType == GNUNET_OS_PROCESS_SIGNALED) { statstr = _( /* process termination method */ "signal"); statcode = statusCode; } else { statstr = _( /* process termination method */ "unknown"); statcode = 0; } if (0 != pos->killed_at.abs_value) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Service `%s' took %llu ms to terminate\n"), pos->name, GNUNET_TIME_absolute_get_duration (pos->killed_at).rel_value); } GNUNET_OS_process_destroy (pos->proc); pos->proc = NULL; if (NULL != pos->killing_client) { signal_result (pos->killing_client, pos->name, GNUNET_ARM_PROCESS_DOWN); GNUNET_SERVER_client_drop (pos->killing_client); pos->killing_client = NULL; /* process can still be re-started on-demand, ensure it is re-started if there is demand */ for (sli = pos->listen_head; NULL != sli; sli = sli->next) { GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); sli->accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, sli->listen_socket, &accept_connection, sli); } continue; } if (GNUNET_YES != in_shutdown) { if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) { /* process terminated normally, allow restart at any time */ pos->restart_at.abs_value = 0; } else { if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Service `%s' terminated with status %s/%d, will restart in %llu ms\n"), pos->name, statstr, statcode, pos->backoff.rel_value); /* schedule restart */ pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); pos->backoff = GNUNET_TIME_relative_min (EXPONENTIAL_BACKOFF_THRESHOLD, GNUNET_TIME_relative_multiply (pos->backoff, 2)); } if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) GNUNET_SCHEDULER_cancel (child_restart_task); child_restart_task = GNUNET_SCHEDULER_add_with_priority (GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); } else { free_service (pos); } } child_death_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) do_shutdown (); }
static void read_call (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { const struct GNUNET_DISK_FileHandle *stdout_read_handle = cls; char level[8]; long delay; long delays[8]; int rd; read_task = NULL; rd = GNUNET_DISK_file_read (stdout_read_handle, buf_ptr, sizeof (buf) - bytes); if (rd > 0) { buf_ptr += rd; bytes += rd; #if VERBOSE FPRINTF (stderr, "got %d bytes, reading more\n", rd); #endif read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, stdout_read_handle, &read_call, (void*) stdout_read_handle); return; } #if VERBOSE FPRINTF (stderr, "bytes is %d:%s\n", bytes, buf); #endif /* +------CHILD OUTPUT-- * | SOFT HARD * | E W I D E W I D * | 0E * * * * | 1W * * * * * P 2I * * * * * * H 3D * * * * * * * A * S 4E * * * E 5W * * * * * | 6I * * * * * * * | 7D * * * * * * * * * | 8 * * * * * | 9 * * * * */ char *p = buf; if (bytes == LOG_BUFFER_SIZE || !(p = read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "ERROR", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[0], level)) || !(p = read_output_line (1, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "WARNING", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[1], level)) || !(p = read_output_line (2, 3, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "INFO", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[2], level)) || !(p = read_output_line (3, 3, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '1', "DEBUG", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[3], level)) || !(p = read_output_line (0, 3, 4, 9, 'L', "ERROR", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "ERROR", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[4], level)) || !(p = read_output_line (0, 3, 5, 9, 'L', "WARNING", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "WARNING", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[5], level)) || !(p = read_output_line (-1, -1, 6, 7, 'L', "INFO", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "INFO", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[6], level)) || !(p = read_output_line (-1, -1, 7, 7, 'L', "DEBUG", -1, 1, phase, p, &bytes, &delay, level)) || !(p = read_output_line (0, 3, 4, 9, '2', "DEBUG", OUTPUT_DELAY, MAX_SKIP_DELAY, phase, p, &bytes, &delays[7], level))) { if (bytes == LOG_BUFFER_SIZE) FPRINTF (stderr, "%s", "Ran out of buffer space!\n"); GNUNET_break (0); ok = 2; GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); return; } GNUNET_SCHEDULER_cancel (die_task); GNUNET_SCHEDULER_add_now (&end_task, NULL); }
/** * Create a new private key by reading it from a file. If the * files does not exist, create a new key and write it to the * file. Caller must free return value. Note that this function * can not guarantee that another process might not be trying * the same operation on the same file at the same time. * If the contents of the file * are invalid the old file is deleted and a fresh key is * created. * * @param filename name of file to use to store the key * @return new private key, NULL on error (for example, * permission denied) */ struct GNUNET_CRYPTO_EddsaPrivateKey * GNUNET_CRYPTO_eddsa_key_create_from_file (const char *filename) { struct GNUNET_CRYPTO_EddsaPrivateKey *priv; struct GNUNET_DISK_FileHandle *fd; unsigned int cnt; int ec; uint64_t fs; if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) return NULL; while (GNUNET_YES != GNUNET_DISK_file_test (filename)) { fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_FAILIFEXISTS, GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE); if (NULL == fd) { if (EEXIST == errno) { if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { /* must exist but not be accessible, fail for good! */ if (0 != ACCESS (filename, R_OK)) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", filename); else GNUNET_break (0); /* what is going on!? */ return NULL; } continue; } LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); return NULL; } cnt = 0; while (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey), GNUNET_YES)) { short_wait (); if (0 == ++cnt % 10) { ec = errno; LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not acquire lock on file `%s': %s...\n"), filename, STRERROR (ec)); } } LOG (GNUNET_ERROR_TYPE_INFO, _("Creating a new private key. This may take a while.\n")); priv = GNUNET_CRYPTO_eddsa_key_create (); GNUNET_assert (NULL != priv); GNUNET_assert (sizeof (*priv) == GNUNET_DISK_file_write (fd, priv, sizeof (*priv))); GNUNET_DISK_file_sync (fd); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); return priv; } /* key file exists already, read it! */ fd = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, GNUNET_DISK_PERM_NONE); if (NULL == fd) { LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "open", filename); return NULL; } cnt = 0; while (1) { if (GNUNET_YES != GNUNET_DISK_file_lock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey), GNUNET_NO)) { if (0 == ++cnt % 60) { ec = errno; LOG (GNUNET_ERROR_TYPE_ERROR, _("Could not acquire lock on file `%s': %s...\n"), filename, STRERROR (ec)); LOG (GNUNET_ERROR_TYPE_ERROR, _ ("This may be ok if someone is currently generating a private key.\n")); } short_wait (); continue; } if (GNUNET_YES != GNUNET_DISK_file_test (filename)) { /* eh, what!? File we opened is now gone!? */ LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "stat", filename); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd)); return NULL; } if (GNUNET_OK != GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES)) fs = 0; if (fs < sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)) { /* maybe we got the read lock before the key generating * process had a chance to get the write lock; give it up! */ if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); if (0 == ++cnt % 10) { LOG (GNUNET_ERROR_TYPE_ERROR, _("When trying to read key file `%s' I found %u bytes but I need at least %u.\n"), filename, (unsigned int) fs, (unsigned int) sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); LOG (GNUNET_ERROR_TYPE_ERROR, _("This may be ok if someone is currently generating a key.\n")); } short_wait (); /* wait a bit longer! */ continue; } break; } fs = sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey); priv = GNUNET_malloc (fs); GNUNET_assert (fs == GNUNET_DISK_file_read (fd, priv, fs)); if (GNUNET_YES != GNUNET_DISK_file_unlock (fd, 0, sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey))) LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fcntl", filename); GNUNET_assert (GNUNET_YES == GNUNET_DISK_file_close (fd)); return priv; }
/** * Initialize the database connections and associated * data structures (create tables and indices * as needed as well). * * @param plugin the plugin context (state for this module) * @return GNUNET_OK on success */ static int database_setup (struct Plugin *plugin) { char *afsdir; char *key; char *sub_system; const char *peer_id; char *peer; char *value; char *expiry; struct GNUNET_DISK_FileHandle *fh; struct GNUNET_PEERSTORE_Record *entry; struct GNUNET_HashCode hkey; size_t size; char *buffer; char *line; if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "peerstore-flat", "FILENAME", &afsdir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, "peerstore-flat", "FILENAME"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_DISK_file_test (afsdir)) { if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (afsdir)) { GNUNET_break (0); GNUNET_free (afsdir); return GNUNET_SYSERR; } } /* afsdir should be UTF-8-encoded. If it isn't, it's a bug */ plugin->fn = afsdir; fh = GNUNET_DISK_file_open (afsdir, GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_READWRITE, GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ); if (NULL == fh) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to initialize file: %s.\n"), afsdir); return GNUNET_SYSERR; } /* Load data from file into hashmap */ plugin->hm = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO); if (GNUNET_SYSERR == GNUNET_DISK_file_size (afsdir, &size, GNUNET_YES, GNUNET_YES)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to get filesize: %s.\n"), afsdir); return GNUNET_SYSERR; } buffer = GNUNET_malloc (size + 1); if (GNUNET_SYSERR == GNUNET_DISK_file_read (fh, buffer, size)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Unable to read file: %s.\n"), afsdir); GNUNET_DISK_file_close (fh); GNUNET_free (buffer); return GNUNET_SYSERR; } buffer[size] = '\0'; GNUNET_DISK_file_close (fh); if (0 < size) { line = strtok (buffer, "\n"); while (line != NULL) { sub_system = strtok (line, ","); if (NULL == sub_system) break; peer = strtok (NULL, ","); if (NULL == peer) break; key = strtok (NULL, ","); if (NULL == key) break; value = strtok (NULL, ","); if (NULL == value) break; expiry = strtok (NULL, ","); if (NULL == expiry) break; entry = GNUNET_new (struct GNUNET_PEERSTORE_Record); entry->sub_system = GNUNET_strdup (sub_system); entry->key = GNUNET_strdup (key); GNUNET_STRINGS_base64_decode (peer, strlen (peer), (char**)&entry->peer); entry->value_size = GNUNET_STRINGS_base64_decode (value, strlen (value), (char**)&entry->value); if (GNUNET_SYSERR == GNUNET_STRINGS_fancy_time_to_absolute (expiry, entry->expiry)) { GNUNET_free (entry->sub_system); GNUNET_free (entry->key); GNUNET_free (entry->peer); GNUNET_free (entry); break; } peer_id = GNUNET_i2s (entry->peer); GNUNET_CRYPTO_hash (peer_id, strlen (peer_id), &hkey); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_put (plugin->hm, &hkey, entry, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE)); } }
/** * Read from the helper-process * * @param cls handle to the helper process */ static void helper_read (void *cls) { struct GNUNET_HELPER_Handle *h = cls; char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN; ssize_t t; h->read_task = NULL; t = GNUNET_DISK_file_read (h->fh_from_helper, &buf, sizeof (buf)); if (t < 0) { /* On read-error, restart the helper */ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Error reading from `%s': %s\n"), h->binary_name, STRERROR (errno)); if (NULL != h->exp_cb) { h->exp_cb (h->cb_cls); GNUNET_HELPER_stop (h, GNUNET_NO); return; } stop_helper (h, GNUNET_NO); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, h->retry_back_off), &restart_task, h); return; } if (0 == t) { /* this happens if the helper is shut down via a signal, so it is not a "hard" error */ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got 0 bytes from helper `%s' (EOF)\n", h->binary_name); if (NULL != h->exp_cb) { h->exp_cb (h->cb_cls); GNUNET_HELPER_stop (h, GNUNET_NO); return; } stop_helper (h, GNUNET_NO); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, h->retry_back_off), &restart_task, h); return; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got %u bytes from helper `%s'\n", (unsigned int) t, h->binary_name); h->read_task = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, h->fh_from_helper, &helper_read, h); if (GNUNET_SYSERR == GNUNET_SERVER_mst_receive (h->mst, NULL, buf, t, GNUNET_NO, GNUNET_NO)) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to parse inbound message from helper `%s'\n"), h->binary_name); if (NULL != h->exp_cb) { h->exp_cb (h->cb_cls); GNUNET_HELPER_stop (h, GNUNET_NO); return; } stop_helper (h, GNUNET_NO); /* Restart the helper */ h->restart_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, h->retry_back_off), &restart_task, h); return; } }