/** * Function called for all addresses and peers to find the minimum and * maximum (averaged) values for a given quality property. Given * those, we can then calculate the normalized score. * * @param cls the `struct PropertyRange` * @param h which peer are we looking at (ignored) * @param k the address for that peer * @return #GNUNET_OK (continue to iterate) */ static int find_min_max_it (void *cls, const struct GNUNET_PeerIdentity *h, void *k) { struct PropertyRange *pr = cls; const struct ATS_Address *a = k; pr->max.utilization_out = GNUNET_MAX (pr->max.utilization_out, a->properties.utilization_out); pr->max.utilization_in = GNUNET_MAX (pr->max.utilization_in, a->properties.utilization_in); pr->max.distance = GNUNET_MAX (pr->max.distance, a->properties.distance); pr->max.delay = GNUNET_TIME_relative_max (pr->max.delay, a->properties.delay); pr->min.utilization_out = GNUNET_MIN (pr->min.utilization_out, a->properties.utilization_out); pr->min.utilization_in = GNUNET_MIN (pr->min.utilization_in, a->properties.utilization_in); pr->min.distance = GNUNET_MIN (pr->min.distance, a->properties.distance); pr->min.delay = GNUNET_TIME_relative_min (pr->min.delay, a->properties.delay); return GNUNET_OK; }
/** * Grow an array. Grows old by (*oldCount-newCount)*elementSize bytes * and sets *oldCount to newCount. * * @param old address of the pointer to the array * *old may be NULL * @param elementSize the size of the elements of the array * @param oldCount address of the number of elements in the *old array * @param newCount number of elements in the new array, may be 0 * @param filename where in the code was the call to GNUNET_array_grow() * @param linenumber where in the code was the call to GNUNET_array_grow() */ void GNUNET_xgrow_ (void **old, size_t elementSize, unsigned int *oldCount, unsigned int newCount, const char *filename, int linenumber) { void *tmp; size_t size; GNUNET_assert_at (INT_MAX / elementSize > newCount, filename, linenumber); size = newCount * elementSize; if (0 == size) { tmp = NULL; } else { tmp = GNUNET_xmalloc_ (size, filename, linenumber); if (NULL != *old) { GNUNET_memcpy (tmp, *old, elementSize * GNUNET_MIN(*oldCount, newCount)); } } if (NULL != *old) { GNUNET_xfree_ (*old, filename, linenumber); } *old = tmp; *oldCount = newCount; }
/** * Compute the MIN of two bandwidth values. * * @param b1 first value * @param b2 second value * @return the min of b1 and b2 */ struct GNUNET_BANDWIDTH_Value32NBO GNUNET_BANDWIDTH_value_min (struct GNUNET_BANDWIDTH_Value32NBO b1, struct GNUNET_BANDWIDTH_Value32NBO b2) { return GNUNET_BANDWIDTH_value_init (GNUNET_MIN (ntohl (b1.value__), ntohl (b2.value__))); }
/** * Execute a transmission context. If there is * an error in the transmission, the #GNUNET_SERVER_receive_done() * method will be called with an error code (#GNUNET_SYSERR), * otherwise with #GNUNET_OK. * * @param tc transmission context to use * @param timeout when to time out and abort the transmission */ void GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, struct GNUNET_TIME_Relative timeout) { tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total), timeout, &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } }
/** * Callback method used with libcurl * Method is called when libcurl needs to read data during sending * * @param stream pointer where to write data * @param size size of an individual element * @param nmemb count of elements that can be written to the buffer * @param cls source pointer, passed to the libcurl handle * @return bytes written to stream, returning 0 will terminate connection! */ static size_t client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; struct Plugin *plugin = s->plugin; struct HTTP_Message *msg = s->msg_head; size_t len; if (GNUNET_YES != exist_session(plugin, s)) { GNUNET_break (0); return 0; } if (NULL == msg) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Nothing to send! Suspending PUT handle!\n", s->client_put); s->client_put_paused = GNUNET_YES; return CURL_READFUNC_PAUSE; } /* data to send */ GNUNET_assert (msg->pos < msg->size); /* calculate how much fits in buffer */ len = GNUNET_MIN (msg->size - msg->pos, size * nmemb); memcpy (stream, &msg->buf[msg->pos], len); msg->pos += len; if (msg->pos == msg->size) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Client: %p Message with %u bytes sent, removing message from queue\n", s->client_put, msg->size, msg->pos); /* Calling transmit continuation */ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); GNUNET_free (msg); } return len; }
/** * Helper function for incremental transmission of the response. */ static size_t transmit_response (void *cls, size_t size, void *buf) { struct GNUNET_SERVER_TransmitContext *tc = cls; size_t msize; if (NULL == buf) { GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); return 0; } if (tc->total - tc->off > size) msize = size; else msize = tc->total - tc->off; memcpy (buf, &tc->buf[tc->off], msize); tc->off += msize; if (tc->total == tc->off) { GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); GNUNET_SERVER_client_drop (tc->client); GNUNET_free_non_null (tc->buf); GNUNET_free (tc); } else { if (NULL == GNUNET_SERVER_notify_transmit_ready (tc->client, GNUNET_MIN (MIN_BLOCK_SIZE, tc->total - tc->off), GNUNET_TIME_absolute_get_remaining (tc->timeout), &transmit_response, tc)) { GNUNET_break (0); GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); } } return msize; }
/** * 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; }
static void measurement_stop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned long long delta; unsigned long long throughput_out; unsigned long long throughput_in; unsigned long long max_quota_in; unsigned long long max_quota_out; unsigned long long quota_delta; enum GNUNET_ErrorType kind = GNUNET_ERROR_TYPE_DEBUG; measure_task = NULL; FPRINTF (stdout, "%s", "\n"); running = GNUNET_NO; delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us; throughput_out = total_bytes_sent * 1000000LL / delta; /* convert to bytes/s */ throughput_in = total_bytes_recv * 1000000LL / delta; /* convert to bytes/s */ max_quota_in = GNUNET_MIN (current_quota_p1_in, current_quota_p2_in); max_quota_out = GNUNET_MIN (current_quota_p1_out, current_quota_p2_out); if (max_quota_out < max_quota_in) quota_delta = max_quota_in / 3; else quota_delta = max_quota_out / 3; if ((throughput_out > (max_quota_out + quota_delta)) || (throughput_in > (max_quota_in + quota_delta))) ok = 1; /* fail */ else ok = 0; /* pass */ GNUNET_STATISTICS_get (p1.stats, "core", "# discarded CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded lower priority CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, NULL); GNUNET_STATISTICS_get (p1.stats, "core", "# discarded lower priority CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p1); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded lower priority CORE_SEND requests", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); GNUNET_STATISTICS_get (p2.stats, "core", "# discarded lower priority CORE_SEND request bytes", GNUNET_TIME_UNIT_FOREVER_REL, NULL, &print_stat, &p2); if (ok != 0) kind = GNUNET_ERROR_TYPE_ERROR; switch (test) { case SYMMETRIC: GNUNET_log (kind, "Core quota compliance test with symmetric quotas: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; case ASYMMETRIC_SEND_LIMITED: GNUNET_log (kind, "Core quota compliance test with limited sender quota: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; case ASYMMETRIC_RECV_LIMITED: GNUNET_log (kind, "Core quota compliance test with limited receiver quota: %s\n", (0 == ok) ? "PASSED" : "FAILED"); break; }; GNUNET_log (kind, "Peer 1 send rate: %llu b/s (%llu bytes in %llu ms)\n", throughput_out, total_bytes_sent, delta); GNUNET_log (kind, "Peer 1 send quota: %llu b/s\n", current_quota_p1_out); GNUNET_log (kind, "Peer 2 receive rate: %llu b/s (%llu bytes in %llu ms)\n", throughput_in, total_bytes_recv, delta); GNUNET_log (kind, "Peer 2 receive quota: %llu b/s\n", current_quota_p2_in); /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. inbound quota allowed: %llu b/s\n",max_quota_in ); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. outbound quota allowed: %llu b/s\n",max_quota_out); */ GNUNET_SCHEDULER_cancel (err_task); err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); }
/** * Consider using the path @a p for the tunnel @a t. * The tunnel destination is at offset @a off in path @a p. * * @param cls our tunnel * @param path a path to our destination * @param off offset of the destination on path @a path * @return #GNUNET_YES (should keep iterating) */ static int consider_path_cb (void *cls, struct CadetPeerPath *path, unsigned int off) { struct CadetTunnel *t = cls; unsigned int min_length = UINT_MAX; GNUNET_CONTAINER_HeapCostType max_desire = 0; struct CadetTConnection *ct; /* Check if we care about the new path. */ for (ct = t->connection_head; NULL != ct; ct = ct->next) { struct CadetPeerPath *ps; ps = GCC_get_path (ct->cc); if (ps == path) return GNUNET_YES; /* duplicate */ min_length = GNUNET_MIN (min_length, GCPP_get_length (ps)); max_desire = GNUNET_MAX (max_desire, GCPP_get_desirability (ps)); } /* FIXME: not sure we should really just count 'num_connections' here, as they may all have consistently failed to connect. */ /* We iterate by increasing path length; if we have enough paths and this one is more than twice as long than what we are currently using, then ignore all of these super-long ones! */ if ( (t->num_connections > DESIRED_CONNECTIONS_PER_TUNNEL) && (min_length * 2 < off) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ignoring paths of length %u, they are way too long.\n", min_length * 2); return GNUNET_NO; } /* If we have enough paths and this one looks no better, ignore it. */ if ( (t->num_connections >= DESIRED_CONNECTIONS_PER_TUNNEL) && (min_length < GCPP_get_length (path)) && (max_desire > GCPP_get_desirability (path)) ) { GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ignoring path (%u/%llu) to %s, got something better already.\n", GCPP_get_length (path), (unsigned long long) GCPP_get_desirability (path), GCP_2s (t->destination)); return GNUNET_YES; } /* Path is interesting (better by some metric, or we don't have enough paths yet). */ ct = GNUNET_new (struct CadetTConnection); ct->created = GNUNET_TIME_absolute_get (); ct->t = t; ct->cc = GCC_create (t->destination, path, ct, &connection_ready_cb, t); /* FIXME: schedule job to kill connection (and path?) if it takes too long to get ready! (And track performance data on how long other connections took with the tunnel!) => Note: to be done within 'connection'-logic! */ GNUNET_CONTAINER_DLL_insert (t->connection_head, t->connection_tail, ct); t->num_connections++; return GNUNET_YES; }
/** * Add incoming data to the receive buffer and call the * callback for all complete messages. * * @param mst tokenizer to use * @param client_identity ID of client for which this is a buffer * @param buf input data to add * @param size number of bytes in buf * @param purge should any excess bytes in the buffer be discarded * (i.e. for packet-based services like UDP) * @param one_shot only call callback once, keep rest of message in buffer * @return GNUNET_OK if we are done processing (need more data) * GNUNET_NO if one_shot was set and we have another message ready * GNUNET_SYSERR if the data stream is corrupt */ int GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, void *client_identity, const char *buf, size_t size, int purge, int one_shot) { const struct GNUNET_MessageHeader *hdr; size_t delta; uint16_t want; char *ibuf; int need_align; unsigned long offset; int ret; GNUNET_assert (mst->off <= mst->pos); GNUNET_assert (mst->pos <= mst->curr_buf); LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst receives %u bytes with %u bytes already in private buffer\n", (unsigned int) size, (unsigned int) (mst->pos - mst->off)); ret = GNUNET_OK; ibuf = (char *) mst->hdr; while (mst->pos > 0) { do_align: GNUNET_assert (mst->pos >= mst->off); if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || (0 != (mst->off % ALIGN_FACTOR))) { /* need to align or need more space */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { delta = GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - (mst->pos - mst->off), size); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); return GNUNET_SYSERR; } if ( (mst->curr_buf - mst->off < want) && (mst->off > 0) ) { /* can get more space by moving */ mst->pos -= mst->off; memmove (ibuf, &ibuf[mst->off], mst->pos); mst->off = 0; } if (mst->curr_buf < want) { /* need to get more space by growing buffer */ GNUNET_assert (0 == mst->off); mst->hdr = GNUNET_realloc (mst->hdr, want); ibuf = (char *) mst->hdr; mst->curr_buf = want; } hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; if (mst->pos - mst->off < want) { delta = GNUNET_MIN (want - (mst->pos - mst->off), size); GNUNET_assert (mst->pos + delta <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, delta); mst->pos += delta; buf += delta; size -= delta; } if (mst->pos - mst->off < want) { if (purge) { mst->off = 0; mst->pos = 0; } return GNUNET_OK; } if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; mst->off += want; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; if (mst->off == mst->pos) { /* reset to beginning of buffer, it's free right now! */ mst->off = 0; mst->pos = 0; } } GNUNET_assert (0 == mst->pos); while (size > 0) { LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst has %u bytes left in inbound buffer\n", (unsigned int) size); if (size < sizeof (struct GNUNET_MessageHeader)) break; offset = (unsigned long) buf; need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO; if (GNUNET_NO == need_align) { /* can try to do zero-copy and process directly from original buffer */ hdr = (const struct GNUNET_MessageHeader *) buf; want = ntohs (hdr->size); if (want < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); mst->off = 0; return GNUNET_SYSERR; } if (size < want) break; /* or not: buffer incomplete, so copy to private buffer... */ if (one_shot == GNUNET_SYSERR) { /* cannot call callback again, but return value saying that * we have another full message in the buffer */ ret = GNUNET_NO; goto copy; } if (one_shot == GNUNET_YES) one_shot = GNUNET_SYSERR; if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) return GNUNET_SYSERR; buf += want; size -= want; } else { /* need to copy to private buffer to align; * yes, we go a bit more spagetti than usual here */ goto do_align; } } copy: if ((size > 0) && (!purge)) { if (size + mst->pos > mst->curr_buf) { mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos); ibuf = (char *) mst->hdr; mst->curr_buf = size + mst->pos; } GNUNET_assert (size + mst->pos <= mst->curr_buf); memcpy (&ibuf[mst->pos], buf, size); mst->pos += size; } if (purge) { mst->off = 0; mst->pos = 0; } LOG (GNUNET_ERROR_TYPE_DEBUG, "Server-mst leaves %u bytes in private buffer\n", (unsigned int) (mst->pos - mst->off)); return ret; }
/** * Callback method used with libcurl * Method is called when libcurl needs to read data during sending * * @param stream pointer where to write data * @param size size of an individual element * @param nmemb count of elements that can be written to the buffer * @param cls source pointer, passed to the libcurl handle * @return bytes written to stream, returning 0 will terminate connection! */ static size_t client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) { struct Session *s = cls; struct HTTP_Client_Plugin *plugin = s->plugin; struct HTTP_Message *msg = s->msg_head; size_t len; char *stat_txt; if (GNUNET_YES != client_exist_session (plugin, s)) { GNUNET_break (0); return 0; } if (GNUNET_YES == s->put_tmp_disconnecting) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, "Session %p/connection %p: disconnect due to inactivity\n", s, s->client_put); return 0; } if (NULL == msg) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Session %p/connection %p: nothing to send, suspending\n", s, s->client_put); s->put_disconnect_task = GNUNET_SCHEDULER_add_delayed (PUT_DISCONNECT_TIMEOUT, &client_put_disconnect, s); s->put_paused = GNUNET_YES; return CURL_READFUNC_PAUSE; } /* data to send */ GNUNET_assert (msg->pos < msg->size); /* calculate how much fits in buffer */ len = GNUNET_MIN (msg->size - msg->pos, size * nmemb); memcpy (stream, &msg->buf[msg->pos], len); msg->pos += len; if (msg->pos == msg->size) { GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Session %p/connection %p: sent message with %u bytes sent, removing message from queue\n", s, s->client_put, msg->size, msg->pos); /* Calling transmit continuation */ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); if (NULL != msg->transmit_cont) msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK, msg->size, msg->size + s->overhead); s->overhead = 0; GNUNET_free (msg); } GNUNET_asprintf (&stat_txt, "# bytes currently in %s_client buffers", plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, -len, GNUNET_NO); GNUNET_free (stat_txt); GNUNET_asprintf (&stat_txt, "# bytes transmitted via %s_client", plugin->protocol); GNUNET_STATISTICS_update (plugin->env->stats, stat_txt, len, GNUNET_NO); GNUNET_free (stat_txt); client_reschedule_session_timeout (s); return len; }