can be found there - [1].
[1] http://lrn.no-ip.info/other/gnunet_download_tie.log
* Response from FS service with a result for a previous FS search.
* Note that queries for DBLOCKS and IBLOCKS that have received a
* single response are considered done. This message is transmitted
- * between peers as well as between the service and a client.
+ * between peers.
*/
struct PutMessage
{
/* this is followed by the actual encrypted content */
+};
+
+/**
+ * Response from FS service with a result for a previous FS search.
+ * Note that queries for DBLOCKS and IBLOCKS that have received a
+ * single response are considered done. This message is transmitted
+ * between the service and a client.
+ */
+struct ClientPutMessage
+{
+
+ /**
+ * Message type will be GNUNET_MESSAGE_TYPE_FS_PUT.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Type of the block (in big endian). Should never be zero.
+ */
+ uint32_t type GNUNET_PACKED;
+
+ /**
+ * When does this result expire?
+ */
+ struct GNUNET_TIME_AbsoluteNBO expiration;
+
+ /**
+ * When was the last time we've tried to download this block?
+ * (FOREVER if unknown/not relevant)
+ */
+ struct GNUNET_TIME_AbsoluteNBO last_transmission;
+
+ /* this is followed by the actual encrypted content */
+
};
GNUNET_NETWORK_STRUCT_END
unsigned int nug_gen;
};
-
#endif
/* end of fs_api.h */
pi->value.download.uri = dc->uri;
pi->value.download.filename = dc->filename;
pi->value.download.size = dc->length;
+ /* FIXME: Fix duration calculation to account for pauses */
pi->value.download.duration =
GNUNET_TIME_absolute_get_duration (dc->start_time);
pi->value.download.completed = dc->completed;
*/
int do_store;
+ struct GNUNET_TIME_Absolute last_transmission;
+
};
dr->depth) ? GNUNET_BLOCK_TYPE_FS_DBLOCK : GNUNET_BLOCK_TYPE_FS_IBLOCK;
prc.query = chk->query;
prc.do_store = do_store;
+ prc.last_transmission = GNUNET_TIME_UNIT_FOREVER_ABS;
process_result_with_request (&prc, &chk->key, dr);
return GNUNET_OK;
}
pi.value.download.specifics.progress.data_len = prc->size;
pi.value.download.specifics.progress.depth = dr->depth;
pi.value.download.specifics.progress.trust_offered = 0;
+ if (prc->last_transmission.abs_value != GNUNET_TIME_UNIT_FOREVER_ABS.abs_value)
+ pi.value.download.specifics.progress.block_download_duration =
+ GNUNET_TIME_absolute_get_duration (prc->last_transmission);
+ else
+ pi.value.download.specifics.progress.block_download_duration.rel_value =
+ GNUNET_TIME_UNIT_FOREVER_REL.rel_value;
GNUNET_FS_download_make_status_ (&pi, dc);
GNUNET_assert (dc->completed <= dc->length);
if (dr->depth == 0)
*
* @param dc our download context
* @param type type of the result
+ * @param last_transmission when was this block requested the last time? (FOREVER if unknown/not applicable)
* @param data the (encrypted) response
* @param size size of data
*/
static void
process_result (struct GNUNET_FS_DownloadContext *dc,
- enum GNUNET_BLOCK_Type type, const void *data, size_t size)
+ enum GNUNET_BLOCK_Type type,
+ struct GNUNET_TIME_Absolute last_transmission,
+ const void *data, size_t size)
{
struct ProcessResultClosure prc;
prc.size = size;
prc.type = type;
prc.do_store = GNUNET_YES;
+ prc.last_transmission = last_transmission;
GNUNET_CRYPTO_hash (data, size, &prc.query);
#if DEBUG_DOWNLOAD
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
receive_results (void *cls, const struct GNUNET_MessageHeader *msg)
{
struct GNUNET_FS_DownloadContext *dc = cls;
- const struct PutMessage *cm;
+ const struct ClientPutMessage *cm;
uint16_t msize;
if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) ||
- (sizeof (struct PutMessage) > ntohs (msg->size)))
+ (sizeof (struct ClientPutMessage) > ntohs (msg->size)))
{
GNUNET_break (msg == NULL);
try_reconnect (dc);
return;
}
msize = ntohs (msg->size);
- cm = (const struct PutMessage *) msg;
- process_result (dc, ntohl (cm->type), &cm[1],
- msize - sizeof (struct PutMessage));
+ cm = (const struct ClientPutMessage *) msg;
+ process_result (dc, ntohl (cm->type),
+ GNUNET_TIME_absolute_ntoh (cm->last_transmission), &cm[1],
+ msize - sizeof (struct ClientPutMessage));
if (dc->client == NULL)
return; /* fatal error */
/* continue receiving */
receive_results (void *cls, const struct GNUNET_MessageHeader *msg)
{
struct GNUNET_FS_SearchContext *sc = cls;
- const struct PutMessage *cm;
+ const struct ClientPutMessage *cm;
uint16_t msize;
if ((NULL == msg) || (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_FS_PUT) ||
- (ntohs (msg->size) <= sizeof (struct PutMessage)))
+ (ntohs (msg->size) <= sizeof (struct ClientPutMessage)))
{
try_reconnect (sc);
return;
msize = ntohs (msg->size);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Receiving %u bytes of result from fs service\n", msize);
- cm = (const struct PutMessage *) msg;
+ cm = (const struct ClientPutMessage *) msg;
process_result (sc, ntohl (cm->type),
GNUNET_TIME_absolute_ntoh (cm->expiration), &cm[1],
- msize - sizeof (struct PutMessage));
+ msize - sizeof (struct ClientPutMessage));
/* continue receiving */
GNUNET_CLIENT_receive (sc->client, &receive_results, sc,
GNUNET_TIME_UNIT_FOREVER_REL);
static void *
progress_cb (void *cls, const struct GNUNET_FS_ProgressInfo *info)
{
- char *s;
+ char *s, *s2;
char *t;
switch (info->status)
if (verbose)
{
s = GNUNET_STRINGS_relative_time_to_string (info->value.download.eta);
+ if (info->value.download.specifics.progress.block_download_duration.rel_value
+ == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
+ s2 = GNUNET_strdup (_("<unknown time>"));
+ else
+ s2 = GNUNET_STRINGS_relative_time_to_string (
+ info->value.download.specifics.progress.block_download_duration);
t = GNUNET_STRINGS_byte_size_fancy (info->value.download.completed *
1000LL /
(info->value.download.
duration.rel_value + 1));
FPRINTF (stdout,
- _("Downloading `%s' at %llu/%llu (%s remaining, %s/s)\n"),
+ _("Downloading `%s' at %llu/%llu (%s remaining, %s/s). Block took %s to download\n"),
info->value.download.filename,
(unsigned long long) info->value.download.completed,
- (unsigned long long) info->value.download.size, s, t);
+ (unsigned long long) info->value.download.size, s, t, s2);
GNUNET_free (s);
+ GNUNET_free (s2);
GNUNET_free (t);
}
break;
handle_p2p_reply (void *cls, enum GNUNET_BLOCK_EvaluationResult eval,
struct GSF_PendingRequest *pr, uint32_t reply_anonymity_level,
struct GNUNET_TIME_Absolute expiration,
+ struct GNUNET_TIME_Absolute last_transmission,
enum GNUNET_BLOCK_Type type, const void *data,
size_t data_len)
{
* @param pr handle to the original pending request
* @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
* @param expiration when does 'data' expire?
+ * @param last_transmission when was the last time we've tried to download this block? (FOREVER if unknown)
* @param type type of the block
* @param data response data, NULL on request expiration
* @param data_len number of bytes in data
struct GSF_PendingRequest *pr,
uint32_t reply_anonymity_level,
struct GNUNET_TIME_Absolute expiration,
+ struct GNUNET_TIME_Absolute last_transmission,
enum GNUNET_BLOCK_Type type, const void *data,
size_t data_len)
{
struct ClientRequest *cr = cls;
struct GSF_LocalClient *lc;
- struct PutMessage *pm;
+ struct ClientPutMessage *pm;
const struct GSF_PendingRequestData *prd;
size_t msize;
GNUNET_NO);
GNUNET_assert (pr == cr->pr);
lc = cr->lc;
- msize = sizeof (struct PutMessage) + data_len;
+ msize = sizeof (struct ClientPutMessage) + data_len;
{
char buf[msize];
- pm = (struct PutMessage *) buf;
+ pm = (struct ClientPutMessage *) buf;
pm->header.type = htons (GNUNET_MESSAGE_TYPE_FS_PUT);
pm->header.size = htons (msize);
pm->type = htonl (type);
pm->expiration = GNUNET_TIME_absolute_hton (expiration);
+ pm->last_transmission = GNUNET_TIME_absolute_hton (last_transmission);
memcpy (&pm[1], data, data_len);
GSF_local_client_transmit_ (lc, &pm->header);
}
GNUNET_free (pp);
}
+/**
+ * Get the last transmission attempt time for the request plan list
+ * referenced by @rpr_head, that was sent to @sender
+ *
+ * @param rpr_head request plan reference list to check.
+ * @param sender the peer that we've sent the request to.
+ * @param result the timestamp to fill.
+ * @return GNUNET_YES if @result was changed, GNUNET_NO otherwise.
+ */
+int
+GSF_request_plan_reference_get_last_transmission_ (
+ struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender,
+ struct GNUNET_TIME_Absolute *result)
+{
+ struct GSF_RequestPlanReference *rpr;
+ for (rpr = rpr_head; rpr; rpr = rpr->next)
+ {
+ if (rpr->rp->pp->cp == sender)
+ {
+ *result = rpr->rp->last_transmission;
+ return GNUNET_YES;
+ }
+ }
+ return GNUNET_NO;
+}
/**
* Notify the plan about a request being done; destroy all entries
void
GSF_plan_notify_request_done_ (struct GSF_PendingRequest *pr);
+/**
+ * Get the last transmission attempt time for the request plan list
+ * referenced by @rpr_head, that was sent to @sender
+ *
+ * @param rpr_head request plan reference list to check.
+ * @param sender the peer that we've sent the request to.
+ * @param result the timestamp to fill.
+ * @return GNUNET_YES if @result was changed, GNUNET_NO otherwise.
+ */
+int
+GSF_request_plan_reference_get_last_transmission_ (
+ struct GSF_RequestPlanReference *rpr_head, struct GSF_ConnectedPeer *sender,
+ struct GNUNET_TIME_Absolute *result);
/**
* Initialize plan subsystem.
break; /* let the request live briefly... */
if (NULL != dpr->rh)
dpr->rh (dpr->rh_cls, GNUNET_BLOCK_EVALUATION_REQUEST_VALID, dpr,
- UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_BLOCK_TYPE_ANY,
- NULL, 0);
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_ABS, GNUNET_TIME_UNIT_FOREVER_ABS,
+ GNUNET_BLOCK_TYPE_ANY, NULL, 0);
GSF_pending_request_cancel_ (dpr, GNUNET_YES);
}
}
return pr;
}
-
/**
* Obtain the public data associated with a pending request
*
struct ProcessReplyClosure *prq = cls;
struct GSF_PendingRequest *pr = value;
GNUNET_HashCode chash;
+ struct GNUNET_TIME_Absolute last_transmission;
if (NULL == pr->rh)
return GNUNET_YES;
GNUNET_LOAD_update (GSF_rt_entry_lifetime,
GNUNET_TIME_absolute_get_duration (pr->
public_data.start_time).rel_value);
+ if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission))
+ last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value;
/* pass on to other peers / local clients */
pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration,
- prq->type, prq->data, prq->size);
+ last_transmission, prq->type, prq->data, prq->size);
return GNUNET_YES;
case GNUNET_BLOCK_EVALUATION_OK_DUPLICATE:
GNUNET_STATISTICS_update (GSF_stats,
pr->public_data.results_found++;
prq->request_found = GNUNET_YES;
/* finally, pass on to other peer / local client */
+ if (!GSF_request_plan_reference_get_last_transmission_ (pr->public_data.rpr_head, prq->sender, &last_transmission))
+ last_transmission.abs_value = GNUNET_TIME_UNIT_FOREVER_ABS.abs_value;
pr->rh (pr->rh_cls, prq->eval, pr, prq->anonymity_level, prq->expiration,
- prq->type, prq->data, prq->size);
+ last_transmission, prq->type, prq->data, prq->size);
return GNUNET_YES;
}
* @param pr handle to the original pending request
* @param reply_anonymity_level anonymity level for the reply, UINT32_MAX for "unknown"
* @param expiration when does 'data' expire?
+ * @param last_transmission the last time we've tried to get this block (FOREVER if unknown)
* @param type type of the block
* @param data response data, NULL on request expiration
* @param data_len number of bytes in data
uint32_t reply_anonymity_level,
struct GNUNET_TIME_Absolute
expiration,
+ struct GNUNET_TIME_Absolute
+ last_transmission,
enum GNUNET_BLOCK_Type type,
const void *data,
size_t data_len);
*/
unsigned int trust_offered;
+ /**
+ * How much time passed between us asking for this block and
+ * actually getting it? GNUNET_TIME_UNIT_FOREVER_REL if unknown.
+ */
+ struct GNUNET_TIME_Relative block_download_duration;
+
} progress;
/**