Hi, the attached patch adds a function to download.c to start a
downloads when you don't know the file size yet. Apparently this is
needed for magnet links and tiger tree hashes.
I did it by adding a boolean variable to the download and file_info
structs called "file_size_known". This way we can check if the file
size is already known or not later on when we can learn the actual file size, when
we're checking if we're done downloading, or if we want to calculate progress,
remaining time, etc.
It is not wholly complete in that there are places where we use the
filesize that I have not added explicit checks for an unknown filesize. I'm not very
clear on how tiger tree hashes or magnet links will use this and what we'd want to do
in those cases, etc.
BUT: This hopefully won't cause any problems in the way gtkg currently works. Only
once we start adding downloads with unknown filesizes should the incompleteness/bugs
in this code become apparent :)
Sorry to give a partial implementation of something but I'm thinking
this will be useful (hopefully) for the folks working on tiger tree
hashing or magnet links and will save you some time in implementing
those.
Right now, from what I can tell, even if we were to have a download
start with no filesize, the way I've implemented it, it shouldn't
actually crash anything. It may result in funny progress bars,
incorrect "time remaining" displays, and it may prematurely finish for downloads that
don't have a file_size specified. I tried to add
"Fixme"'s in places I think we'll be especially problematic.
Right now it doesn't have any code to get the content-length from a
magnet link or to determine the end of a chunked-transfer encoding
download. Mostly because I don't know how to do that stuff.
Also, I'm happy to do more work on this, I just don't know enough to do much more at
this point.
Emile
ps. please send personal replies to [EMAIL PROTECTED]
? gtk-gnutella-current/src/Makefile
? gtk-gnutella-current/src/getdate.c
? gtk-gnutella-current/src/gtk-gnutella
Index: gtk-gnutella-current/src/dmesh.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/dmesh.c,v
retrieving revision 1.84
diff -u -r1.84 dmesh.c
--- gtk-gnutella-current/src/dmesh.c 10 Jun 2004 20:39:14 -0000 1.84
+++ gtk-gnutella-current/src/dmesh.c 2 Jul 2004 04:32:33 -0000
@@ -2228,7 +2228,7 @@
* `size': the original file size
*/
void dmesh_multiple_downloads(
- gchar *sha1, guint32 size, struct dl_file_info *fi)
+ gchar *sha1, guint32 size, gboolean file_size_known, struct dl_file_info *fi)
{
dmesh_urlinfo_t buffer[DMESH_MAX];
dmesh_urlinfo_t *p;
@@ -2246,8 +2246,12 @@
printf("ALT-LOC queuing from MESH: %s\n",
dmesh_urlinfo_to_gchar(p));
- download_auto_new(p->name, size, p->idx, p->ip, p->port,
- blank_guid, NULL, sha1, now, FALSE, fi, NULL);
+ if (file_size_known)
+ download_auto_new(p->name, size, p->idx, p->ip, p->port,
+ blank_guid, NULL, sha1, now, FALSE, TRUE, fi, NULL);
+ else
+ download_auto_new(p->name, size, p->idx, p->ip, p->port,
+ blank_guid, NULL, sha1, now, FALSE, FALSE, fi, NULL);
}
}
Index: gtk-gnutella-current/src/dmesh.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/dmesh.h,v
retrieving revision 1.24
diff -u -r1.24 dmesh.h
--- gtk-gnutella-current/src/dmesh.h 10 Jun 2004 20:39:15 -0000 1.24
+++ gtk-gnutella-current/src/dmesh.h 2 Jul 2004 04:32:33 -0000
@@ -93,7 +93,8 @@
const gchar *vendor, struct dl_file_info *fi, gboolean request);
void dmesh_multiple_downloads(
- gchar *sha1, guint32 size, struct dl_file_info *fi);
+ gchar *sha1, guint32 size, gboolean file_size_known,
+ struct dl_file_info *fi);
void dmesh_check_results_set(gnet_results_set_t *rs);
@@ -103,4 +104,3 @@
#endif /* _dmesh_h_ */
/* vi: set ts=4: */
-
Index: gtk-gnutella-current/src/downloads.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/downloads.c,v
retrieving revision 1.373
diff -u -r1.373 downloads.c
--- gtk-gnutella-current/src/downloads.c 21 Jun 2004 21:00:44 -0000 1.373
+++ gtk-gnutella-current/src/downloads.c 2 Jul 2004 04:32:34 -0000
@@ -1326,7 +1326,8 @@
file_info_remove_source(fi, d, FALSE); /* Keep it around for others */
fi = file_info_get(
- d->file_name, save_file_path, d->file_size, d->sha1);
+ d->file_name, save_file_path, d->file_size, d->sha1,
+ d->file_size_known);
file_info_add_source(fi, d);
fi->lifecount++;
@@ -3313,8 +3314,8 @@
gchar *file, guint32 size, guint32 record_index,
guint32 ip, guint16 port, gchar *guid, gchar *hostname,
gchar *sha1, time_t stamp,
- gboolean push, gboolean interactive, struct dl_file_info *file_info,
- gnet_host_vec_t *proxies)
+ gboolean push, gboolean interactive, gboolean file_size_known,
+ struct dl_file_info *file_info, gnet_host_vec_t *proxies)
{
struct dl_server *server;
struct download *d;
@@ -3388,12 +3389,16 @@
d->file_name = file_name;
d->escaped_name = url_escape_cntrl(file_name);
+ if (FALSE == file_size_known)
+ size = 1; /* Dummy value to prevent divide by zero errors, etc. */
+
+ d->file_size_known = file_size_known;
+ d->file_size = size;
+
/*
* Note: size and skip will be filled by download_pick_chunk() later
* if we use swarming.
*/
-
- d->file_size = size; /* Never changes */
d->size = size; /* Will be changed if range requested */
d->record_index = record_index;
d->file_desc = -1;
@@ -3417,7 +3422,8 @@
*/
fi = file_info == NULL ?
- file_info_get(file_name, save_file_path, size, sha1) : file_info;
+ file_info_get(file_name, save_file_path, size, sha1, file_size_known)
+ : file_info;
if (fi->flags & FI_F_SUSPEND)
d->flags |= DL_F_SUSPENDED;
@@ -3493,8 +3499,9 @@
void download_auto_new(gchar *file, guint32 size, guint32 record_index,
guint32 ip, guint16 port, gchar *guid, gchar *hostname,
- gchar *sha1, time_t stamp, gboolean push,
- struct dl_file_info *fi, gnet_host_vec_t *proxies)
+ gchar *sha1, time_t stamp, gboolean push,
+ gboolean file_size_known, struct dl_file_info *fi,
+ gnet_host_vec_t *proxies)
{
gchar *file_name;
const char *reason;
@@ -3531,8 +3538,13 @@
file_name = atom_str_get(file);
- (void) create_download(file_name, size, record_index, ip, port,
- guid, hostname, sha1, stamp, push, FALSE, fi, proxies);
+ if (file_size_known)
+ create_download(file_name, size, record_index, ip, port,
+ guid, hostname, sha1, stamp, push, FALSE, TRUE, fi, proxies);
+ else
+ create_download(file_name, size, record_index, ip, port,
+ guid, hostname, sha1, stamp, push, FALSE, FALSE, fi, proxies);
+
return;
abort_download:
@@ -3724,10 +3736,28 @@
struct dl_file_info *fi, gnet_host_vec_t *proxies)
{
return NULL != create_download(file, size, record_index, ip, port, guid,
- hostname, sha1, stamp, push, TRUE, fi, proxies);
+ hostname, sha1, stamp, push, TRUE, TRUE, fi, proxies);
}
/*
+ * download_new_unknown_size
+ *
+ * Create a new download if the size is unknown
+ *
+ */
+gboolean download_new_unknown_size(gchar *file, guint32 record_index,
+ guint32 ip, guint16 port, gchar *guid, gchar *hostname,
+ gchar *sha1, time_t stamp, gboolean push,
+ struct dl_file_info *fi, gnet_host_vec_t *proxies)
+{
+ guint32 size = 1;
+
+ return NULL != create_download(file, size, record_index, ip, port, guid,
+ hostname, sha1, stamp, push, TRUE, FALSE, fi, proxies);
+}
+
+
+/*
* download_orphan_new
*
* Fake a new download for an existing file that is marked complete in
@@ -3737,7 +3767,7 @@
gchar *file, guint32 size, gchar *sha1, struct dl_file_info *fi)
{
(void) create_download(file, size, 0, 0, 0, blank_guid, NULL, sha1,
- time(NULL), FALSE, TRUE, fi, NULL);
+ time(NULL), FALSE, TRUE, TRUE, fi, NULL);
}
/*
@@ -4538,6 +4568,11 @@
* on a persistent connection where we'll be able to request
* another chunk data of data.
*
+ *
+ * FIXME: This won't work if the fileinfo doesn't have a specified
+ * file size. --- Emile
+ *
+ *
* The only remaining possibility is that we have reached a zone
* where a competing download is busy (aggressive swarming on),
* and since we cannot tell the remote HTTP server that we wish
@@ -7518,7 +7553,7 @@
d = create_download(d_name, d_size, d_index, d_ip, d_port, d_guid,
d_hostname, has_sha1 ? sha1_digest : NULL, 1, FALSE, FALSE,
- NULL, NULL);
+ TRUE, NULL, NULL);
if (d == NULL) {
g_warning("ignored dup download at line #%d (server %s)",
Index: gtk-gnutella-current/src/downloads.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/downloads.h,v
retrieving revision 1.103
diff -u -r1.103 downloads.h
--- gtk-gnutella-current/src/downloads.h 10 Jun 2004 21:32:33 -0000 1.103
+++ gtk-gnutella-current/src/downloads.h 2 Jul 2004 04:32:34 -0000
@@ -160,6 +160,7 @@
guint32 flags;
+ gboolean file_size_known; /* File size known? */
gboolean keep_alive; /* Keep HTTP connection? */
gboolean visible; /* The download is visible in the GUI */
gboolean push; /* Currently in push mode */
Index: gtk-gnutella-current/src/downloads_gui.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/downloads_gui.c,v
retrieving revision 1.75
diff -u -r1.75 downloads_gui.c
--- gtk-gnutella-current/src/downloads_gui.c 10 Jun 2004 20:51:13 -0000 1.75
+++ gtk-gnutella-current/src/downloads_gui.c 2 Jul 2004 04:32:35 -0000
@@ -563,6 +563,7 @@
*/
void download_gui_add(struct download *d)
{
+ const gchar *UNKNOWN_SIZE_STR = "unknown size";
const gchar *titles[6], *titles_parent[6];
GtkCTreeNode *new_node, *parent;
GdkColor *color;
@@ -601,7 +602,12 @@
titles[c_queue_filename] = file_name;
titles[c_queue_server] = vendor;
titles[c_queue_status] = "";
- titles[c_queue_size] = short_size(d->file_info->size);
+
+ if (d->file_info->file_size_known)
+ titles[c_queue_size] = short_size(d->file_info->size);
+ else
+ titles[c_queue_size] = UNKNOWN_SIZE_STR;
+
titles[c_queue_host] = download_get_hostname(d);
@@ -724,7 +730,11 @@
titles[c_dl_filename] = file_name;
titles[c_dl_server] = vendor;
titles[c_dl_status] = "";
- titles[c_dl_size] = short_size(d->file_info->size);
+
+ if (d->file_info->file_size_known)
+ titles[c_dl_size] = short_size(d->file_info->size);
+ else
+ titles[c_dl_size] = UNKNOWN_SIZE_STR;
titles[c_dl_range] = "";
titles[c_dl_host] = download_get_hostname(d);
Index: gtk-gnutella-current/src/downloads_gui2.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/downloads_gui2.c,v
retrieving revision 1.31
diff -u -r1.31 downloads_gui2.c
--- gtk-gnutella-current/src/downloads_gui2.c 29 Jun 2004 16:04:49 -0000 1.31
+++ gtk-gnutella-current/src/downloads_gui2.c 2 Jul 2004 04:32:35 -0000
@@ -636,6 +636,7 @@
void download_gui_add(download_t *d)
{
const gchar *vendor;
+ const gchar *UNKNOWN_SIZE_STR = "unknown size";
GHashTable *ht;
GtkTreeView *treeview;
GtkTreeIter *parent;
@@ -686,7 +687,11 @@
d_file_name = file_info_readable_filename(d->file_info);
d_file_name = lazy_locale_to_utf8(
(gchar *) d_file_name, 0); /* Override const */
- d_file_size = short_size(d->file_info->size);
+
+ if (d->file_info->file_size_known)
+ d_file_size = short_size(d->file_info->size);
+ else
+ d_file_size = UNKNOWN_SIZE_STR;
} else {
download_t *drecord;
@@ -774,7 +779,11 @@
d_file_name = file_info_readable_filename(d->file_info);
d_file_name = lazy_locale_to_utf8(
(gchar *) d_file_name, 0); /* Override const */
- d_file_size = short_size(d->file_info->size);
+
+ if (d->file_info->file_size_known)
+ d_file_size = short_size(d->file_info->size);
+ else
+ d_file_size = UNKNOWN_SIZE_STR;
} else {
download_t *drecord;
Index: gtk-gnutella-current/src/drop.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/drop.c,v
retrieving revision 1.1
diff -u -r1.1 drop.c
--- gtk-gnutella-current/src/drop.c 24 Jun 2004 06:52:49 -0000 1.1
+++ gtk-gnutella-current/src/drop.c 2 Jul 2004 04:32:35 -0000
@@ -254,12 +254,9 @@
if (dl.ready) {
g_message("file=\"%s\"", dl.file);
- /* TODO: It's not possible to start a download without knowing
- * the filesize in advance. *ARRRGS* */
-#if 0
- download_new(dl.file, ?, URN_INDEX, dl.ip, dl.port, blank_guid,
- dl.hostname, dl.sha1, time(NULL), FALSE, NULL, NULL);
-#endif
+
+ download_new_unknown_size(dl.file, URN_INDEX, dl.ip, dl.port,
+ blank_guid, dl.hostname, dl.sha1, time(NULL), FALSE, NULL, NULL);
}
return TRUE;
Index: gtk-gnutella-current/src/fileinfo.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/fileinfo.c,v
retrieving revision 1.135
diff -u -r1.135 fileinfo.c
--- gtk-gnutella-current/src/fileinfo.c 20 Jun 2004 21:53:39 -0000 1.135
+++ gtk-gnutella-current/src/fileinfo.c 2 Jul 2004 04:32:35 -0000
@@ -1009,6 +1009,10 @@
sf->file_path = atom_str_get(path);
sf->file_name = filename;
sf->file_name_len = strlen(fi->file_name);
+
+ /* FIXME: Do we need to add anything here now that fileinfos can have an
+ unknown length? --- Emile
+ */
sf->file_size = fi->size;
sf->file_index = URN_INDEX;
sf->mtime = fi->last_flush;
@@ -2241,7 +2245,8 @@
* The `sha1' is the known SHA1 for the file (NULL if unknown).
*/
static struct dl_file_info *file_info_create(
- gchar *file, const gchar *path, guint32 size, const gchar *sha1)
+ gchar *file, const gchar *path, guint32 size, const gchar *sha1,
+ gboolean file_size_known)
{
struct dl_file_info *fi;
struct stat st;
@@ -2304,7 +2309,8 @@
*/
file_info_hash_remove(fi);
- new_fi = file_info_create(fi->file_name, fi->path, fi->size, fi->sha1);
+ new_fi = file_info_create(fi->file_name, fi->path, fi->size, fi->sha1,
+ fi->file_size_known);
/*
* Copy old aliases to new structure.
@@ -2350,7 +2356,8 @@
* `file' is the file name on the server.
*/
struct dl_file_info *file_info_get(
- gchar *file, const gchar *path, guint32 size, gchar *sha1)
+ gchar *file, const gchar *path, guint32 size, gchar *sha1,
+ gboolean file_size_known)
{
struct dl_file_info *fi;
gchar *outname;
@@ -2438,6 +2445,9 @@
fi_free(fi);
fi = NULL;
}
+ /* FIXME: Do we need to add something here because fileinfos can have
+ an unknown size --- Emile
+ */
else if (fi->size < size) {
/*
* Existing file is smaller than the total size of this file.
@@ -2466,14 +2476,14 @@
*/
if (fi == NULL) {
- fi = file_info_create(outname, path, size, sha1);
+ fi = file_info_create(outname, path, size, sha1, file_size_known);
fi_alias(fi, file, FALSE);
}
file_info_hash_insert(fi);
if (sha1)
- dmesh_multiple_downloads(sha1, size, fi);
+ dmesh_multiple_downloads(sha1, size, file_size_known, fi);
atom_str_free(outname);
@@ -3410,7 +3420,7 @@
return;
download_auto_new(file_name, fi->size, idx, ip, port, blank_guid, NULL,
- sha1, time(NULL), FALSE, fi, NULL);
+ sha1, time(NULL), FALSE, TRUE, fi, NULL);
}
/*
Index: gtk-gnutella-current/src/fileinfo.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/fileinfo.h,v
retrieving revision 1.37
diff -u -r1.37 fileinfo.h
--- gtk-gnutella-current/src/fileinfo.h 10 Jun 2004 08:01:11 -0000 1.37
+++ gtk-gnutella-current/src/fileinfo.h 2 Jul 2004 04:32:35 -0000
@@ -58,6 +58,7 @@
GSList *chunklist; /* List of ranges within file */
guint32 generation; /* Generation number, incremented on disk update */
struct shared_file *sf; /* When PFSP-server is enabled, share this file */
+ gboolean file_size_known; /* File size known? */
gboolean use_swarming; /* Use swarming? */
gboolean dirty; /* Does it need saving? */
gboolean dirty_status; /* Notify about status change on next interval */
@@ -114,7 +115,8 @@
void file_info_reset(struct dl_file_info *fi);
void file_info_recreate(struct download *d);
struct dl_file_info *file_info_get(
- gchar *file, const gchar *path, guint32 size, gchar *sha1);
+ gchar *file, const gchar *path, guint32 size, gchar *sha1,
+ gboolean file_size_known);
void file_info_strip_binary(struct dl_file_info *fi);
void file_info_strip_binary_from_file(
struct dl_file_info *fi, const gchar *file);
@@ -144,4 +146,3 @@
gchar *file, guint32 size, gchar *sha1);
#endif /* _fileinfo_h_ */
-
Index: gtk-gnutella-current/src/gnet_downloads.h
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/gnet_downloads.h,v
retrieving revision 1.2
diff -u -r1.2 gnet_downloads.h
--- gtk-gnutella-current/src/gnet_downloads.h 8 Jun 2004 18:57:43 -0000 1.2
+++ gtk-gnutella-current/src/gnet_downloads.h 2 Jul 2004 04:32:35 -0000
@@ -38,7 +38,7 @@
gboolean, struct dl_file_info *, gnet_host_vec_t *);
void download_auto_new(gchar *,
guint32, guint32, guint32, guint16, gchar *, gchar *, gchar *, time_t,
- gboolean, struct dl_file_info *, gnet_host_vec_t *);
+ gboolean, gboolean, struct dl_file_info *, gnet_host_vec_t *);
void download_index_changed(guint32, guint16, gchar *, guint32, guint32);
#define URN_INDEX 0xffffffff /* Marking index, indicates URN instead */
Index: gtk-gnutella-current/src/search.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/search.c,v
retrieving revision 1.186
diff -u -r1.186 search.c
--- gtk-gnutella-current/src/search.c 5 Jun 2004 03:43:37 -0000 1.186
+++ gtk-gnutella-current/src/search.c 2 Jul 2004 04:32:36 -0000
@@ -1620,7 +1620,7 @@
download_auto_new(rc->name, rc->size, URN_INDEX, h->ip,
h->port, blank_guid, rs->hostname,
- rc->sha1, rs->stamp, FALSE, fi, rs->proxies);
+ rc->sha1, rs->stamp, FALSE, TRUE, fi, rs->proxies);
if (rs->proxies != NULL)
search_free_proxies(rs);
@@ -1658,7 +1658,7 @@
download_auto_new(rc->name, rc->size, rc->index, rs->ip, rs->port,
rs->guid, rs->hostname,
- rc->sha1, rs->stamp, need_push, fi, rs->proxies);
+ rc->sha1, rs->stamp, need_push, TRUE, fi, rs->proxies);
if (rs->proxies != NULL)
Index: gtk-gnutella-current/src/search_gui_common.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/search_gui_common.c,v
retrieving revision 1.42
diff -u -r1.42 search_gui_common.c
--- gtk-gnutella-current/src/search_gui_common.c 22 Jun 2004 22:26:35 -0000 1.42
+++ gtk-gnutella-current/src/search_gui_common.c 2 Jul 2004 04:32:36 -0000
@@ -597,7 +597,7 @@
download_auto_new(rc->name, rc->size, URN_INDEX, h->ip,
h->port, blank_guid, rs->hostname,
- rc->sha1, rs->stamp, FALSE, NULL, NULL);
+ rc->sha1, rs->stamp, FALSE, TRUE, NULL, NULL);
}
search_gui_free_alt_locs(rc);
@@ -849,7 +849,7 @@
FILTER_PROP_STATE_DO)
) {
download_auto_new(rc->name, rc->size, rc->index, rs->ip, rs->port,
- rs->guid, rs->hostname, rc->sha1, rs->stamp, need_push,
+ rs->guid, rs->hostname, rc->sha1, rs->stamp, need_push, TRUE,
NULL, rs->proxies);
if (rs->proxies != NULL)
Index: gtk-gnutella-current/src/visual_progress_gui.c
===================================================================
RCS file: /cvsroot/gtk-gnutella/gtk-gnutella-current/src/visual_progress_gui.c,v
retrieving revision 1.24
diff -u -r1.24 visual_progress_gui.c
--- gtk-gnutella-current/src/visual_progress_gui.c 1 Jul 2004 18:49:47 -0000 1.24
+++ gtk-gnutella-current/src/visual_progress_gui.c 2 Jul 2004 04:32:36 -0000
@@ -119,6 +119,12 @@
*/
g_assert(v->file_size);
+
+ /* FIXME: This should now be totally screwed up for fileinfo's with an
+ unknown size. Their size will be set to 1 but we shouldn't rely on that.
+ --- Emile.
+ */
+
s_from = (gfloat) from * v->context->widget->allocation.width
/ v->file_size;
s_to = (gfloat) to * v->context->widget->allocation.width