frostwire / frostwire-jlibtorrent

A swig Java interface for libtorrent by the makers of FrostWire. Develop libtorrent based apps with the joy of coding in Java.
http://www.frostwire.com
MIT License
446 stars 137 forks source link

incorrect handling of file priorities for magnet #180

Closed proninyaroslav closed 6 years ago

proninyaroslav commented 6 years ago

Hi. I got this cyclic crash after reproducing this problem https://github.com/proninyaroslav/libretorrent/issues/111 . The problem is that jlibtorrent incorrectly handling the list of ignored files and downloads them. TorrentHanle.filePriorities() returns the correct file priorities, but they do not coincide with reality, because ignored files are being downloaded.

10-28 11:34:32.742 14485 14545 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x30 in tid 14545 (av.libretorrent)
10-28 11:34:32.743   361   361 W         : debuggerd: handling request: pid=14485 uid=10138 gid=10138 tid=14545
10-28 11:34:32.823 15562 15562 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-28 11:34:32.823 15562 15562 F DEBUG   : LineageOS Version: '14.1-20171009-NIGHTLY-angler'
10-28 11:34:32.823 15562 15562 F DEBUG   : Build fingerprint: 'google/angler/angler:7.1.2/N2G48C/4104010:user/release-keys'
10-28 11:34:32.823 15562 15562 F DEBUG   : Revision: '0'
10-28 11:34:32.823 15562 15562 F DEBUG   : ABI: 'arm64'
10-28 11:34:32.823 15562 15562 F DEBUG   : pid: 14485, tid: 14545, name: av.libretorrent  >>> org.proninyaroslav.libretorrent <<<
10-28 11:34:32.823 15562 15562 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x30
10-28 11:34:32.823 15562 15562 F DEBUG   :     x0   0000000000000030  x1   0000007eb4371890  x2   0000000000000020  x3   0000000000000000
10-28 11:34:32.823 15562 15562 F DEBUG   :     x4   000000000000003b  x5   0000007eb4371800  x6   7461647055207372  x7   204f4941202d2065
10-28 11:34:32.823 15562 15562 F DEBUG   :     x8   0000000000000001  x9   000000000000003b  x10  000000000000003b  x11  000000000000003b
10-28 11:34:32.823 15562 15562 F DEBUG   :     x12  0000007ec81e9000  x13  0000000000000170  x14  000000000000000c  x15  0000000000000000
10-28 11:34:32.823 15562 15562 F DEBUG   :     x16  0000007eb4d7c158  x17  0000007ed1bb75f8  x18  0000000000000000  x19  0000007eb4371800
10-28 11:34:32.823 15562 15562 F DEBUG   :     x20  0000000000000020  x21  0000007eb4371890  x22  000000000000003b  x23  0000000000000000
10-28 11:34:32.823 15562 15562 F DEBUG   :     x24  0000007ec808c1c0  x25  0000007eb4371d10  x26  0000000000000001  x27  0000000000000020
10-28 11:34:32.823 15562 15562 F DEBUG   :     x28  0000000000000000  x29  0000007eb4371780  x30  0000007eb4bcc278
10-28 11:34:32.823 15562 15562 F DEBUG   :     sp   0000007eb4371780  pc   0000007ed1bb75f8  pstate 0000000080000000
10-28 11:34:32.833 15562 15562 F DEBUG   : 
10-28 11:34:32.833 15562 15562 F DEBUG   : backtrace:
10-28 11:34:32.833 15562 15562 F DEBUG   :     #00 pc 000000000006a5f8  /system/lib64/libc.so (pthread_mutex_lock)
10-28 11:34:32.833 15562 15562 F DEBUG   :     #01 pc 0000000000455274  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so (_ZNSt6__ndk15mutex4lockEv+8)
10-28 11:34:32.833 15562 15562 F DEBUG   :     #02 pc 000000000025f2a0  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #03 pc 00000000001dcb88  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #04 pc 00000000001dea58  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #05 pc 00000000001dd0c0  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #06 pc 00000000001dc320  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #07 pc 0000000000164afc  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #08 pc 00000000001647ec  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #09 pc 0000000000164fd0  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #10 pc 000000000016518c  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #11 pc 0000000000169c90  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.833 15562 15562 F DEBUG   :     #12 pc 0000000000165b10  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.834 15562 15562 F DEBUG   :     #13 pc 000000000016a0a4  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.834 15562 15562 F DEBUG   :     #14 pc 000000000016a2e8  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.834 15562 15562 F DEBUG   :     #15 pc 000000000017173c  /data/app/org.proninyaroslav.libretorrent-2/lib/arm64/libjlibtorrent.so
10-28 11:34:32.834 15562 15562 F DEBUG   :     #16 pc 0000000000069c7c  /system/lib64/libc.so (_ZL15__pthread_startPv+208)
10-28 11:34:32.834 15562 15562 F DEBUG   :     #17 pc 000000000001dc34  /system/lib64/libc.so (__start_thread+16)
10-28 11:34:33.062   361   361 W         : debuggerd: resuming target 14485
aldenml commented 6 years ago

I will need some help to test this, I will release another version with debug symbols, but if you can reproduce the crash in an arm 32 bits, I already have the debug symbols for it.

aldenml commented 6 years ago

Hi @proninyaroslav, 1.2.0.13-RC12 is out, do you mind send me a crash report with the new version?

aldenml commented 6 years ago

We are already having a great number of this error in our reports CC @gubatron

proninyaroslav commented 6 years ago

Hi. I could not catch crash, but the problem with incorrect priorities remains.

aldenml commented 6 years ago

See https://github.com/arvidn/libtorrent/issues/2489

aldenml commented 6 years ago

@proninyaroslav the crash is fixed in 1.2.0.13-RC14, but the issue of the inconsistency, still didn't have time to look at it

proninyaroslav commented 6 years ago

So fix is already ready and I can test it?

aldenml commented 6 years ago

no, still not ready

aldenml commented 6 years ago

hi @proninyaroslav can you tell me if this error is happening with the methods from SessionManager, or a custom one outside jlibtorrent? btw, 1.2.0.14 is out

proninyaroslav commented 6 years ago

I already tested. Suppose I have 2 files in the torrent. One file has a size of 5 MB, and the second file has a size of 1 MB. I select the second file, start downloading. In the end, both files are downloaded, although the priorities returned by TorrentHandle.filePriorities () are correct (ignore for first and normal for second file). TorrentStatus.getTotalWanted () returns 6 MB, although it should return 1 MB. You can check it on this torrent magnet:?xt=urn:btih:AD838261E23F84886E1219EDF53A8B608A8D5820&dn=Microsoft+Windows+10+v1703+AIO+8+in+1+Aprile+2017.torrent. Try downloading only .txt file.

aldenml commented 6 years ago

I just tested, and it downloads only the smaller file. Are you sure you are using one of our methods? and not a custom one?

proninyaroslav commented 6 years ago

Hmm, that seems strange. I use only SessionManager and TorrentHandle methods. I think I'll have to make a more detailed log.

aldenml commented 6 years ago

yes please, provide as much info as you can

proninyaroslav commented 6 years ago

I think that the problem is in TorrentHandle.prioritizeFiles(), since the priorities after calling this method don't change.

aldenml commented 6 years ago

that call is an "async" one, if you query the vector immediately after setting it, you will see no change

proninyaroslav commented 6 years ago

I get priorities every STATS alert (for test).

proninyaroslav commented 6 years ago

Priorities don't change for magnet's TorrentHandle, which received metadata and was launched for download. I'll try to find an error in my code, maybe I'm using this method incorrectly.

aldenml commented 6 years ago

if you find the same behavior in the SessionManager#downloads, report back please

proninyaroslav commented 6 years ago

Yes, it only happens with magnets. I noticed that using the TorrentHandle after getting metadata (without recreating) is a bad idea, since it contains a lot of errors, including this error #174.

proninyaroslav commented 6 years ago

A small offtopic, sorry. I have a question about using SessionManager.fetchMagnet: let's say I have a SessionManager as a singleton. I need an indefinite time to wait for the fetching of magnet. Is it possible to implement asynchronousSessionManager.fetchMagnet in a separate thread for multiple magnets at the same time?

aldenml commented 6 years ago

at this moment, you could wrap fetchMagnet in your own thread to simulate the async task, and that's fine because I made it thread safe, but I doubt that would scale well. The fundamental problem is that I assumed that "fetching a magnet" is an expensive job inside libtorrent, and in some sense it is. Also, we actually don't want (or need) such a big scale for our own use; it is not fast in nature either, since query the DHT is not that trivial.

I do think fetchMagnet warrants some rethinking in order to address this and other limitations. Ideas are welcome, and all of them can be tested outside SessionManager or changing the source code, since swig() give you the full low level API.

proninyaroslav commented 6 years ago

Thanks for clarifying. Yes, until this point I've used a low level API to bypass the limitations of fetchMagnet, but alas, these two problems don't allow me to use the low level API at the moment.

aldenml commented 6 years ago

these two problems don't allow me to use the low level API at the moment.

Which ones?

proninyaroslav commented 6 years ago

174 and this issue.

aldenml commented 6 years ago

I see, I though they are more related to the java high level API than the low level one

proninyaroslav commented 6 years ago

Hi. I checked some torrents and magnets and TorrentHandle.prioritizeFiles doesn't always work correctly. After changing the priority, I still get the old priorities from the TorrentHandle.filePriorities() method and the ignored files continue to be downloaded. I created a small test sample for this. As you can see after adding a torrent, I try to change the priority of the first file, but the priority does not change in 2 minutes, although the torrent was downloaded in a minute.

Waiting for nodes in DHT (10 seconds)...
DHT contains 95 nodes
Fetching the magnet uri, please wait...
Torrent added
Expected priorities:
priority=IGNORE  file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

[20:30:45] Current priorities:
priority=FOUR    file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

...

[20:31:09] Current priorities:
priority=FOUR    file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

Torrent finished

[20:31:10] Current priorities:
priority=FOUR    file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

...

[20:32:06] Current priorities:
priority=FOUR    file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

Code:

private static final String MAGNET = "magnet:?xt=urn:btih:bff641545f7ba0d5cdd1517d068885f7612aad5b&dn=rutor.info&tr=udp://opentor.org:2710&tr=udp://opentor.org:2710&tr=http://retracker.local/announce";
SessionManager s = new SessionManager();
CountDownLatch signal = new CountDownLatch(1);
s.addListener(new AlertListener() {
        @Override
        public int[] types()
        {
                return null;
        }

        @Override
        public void alert(Alert<?> alert)
        {
                switch (alert.type()) {
                        case ADD_TORRENT:
                                System.out.println("Torrent added");
                                TorrentHandle th = ((AddTorrentAlert) alert).handle();
                                th.resume();

                                TorrentInfo ti = th.torrentFile();
                                Priority[] p = th.filePriorities();
                                p[0] = Priority.IGNORE;

                                System.out.println("Expected priorities:");
                                for (int i = 0; i < ti.numFiles(); i++)
                                        System.out.println(String.format("priority=%-8sfile=%s",
                                                                         p[i],
                                                                         ti.files().fileName(i)));
                                System.out.println();
                                th.prioritizeFiles(p);
                                break;
                        case STATS:
                                th = ((StatsAlert) alert).handle();
                                ti = th.torrentFile();
                                p = th.filePriorities();
                                System.out.println(String.format("[%s] Current priorities:",
                                                                 new Time(System.currentTimeMillis())));
                                for (int i = 0; i < ti.numFiles(); i++)
                                       System.out.println(String.format("priority=%-8sfile=%s",
                                                                        p[i],
                                                                        ti.files().fileName(i)));
                                System.out.println();
                                break;
                        case TORRENT_FINISHED:
                                System.out.println("Torrent finished\n");
                                break;
                }
            }
        });
        s.start();

        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
                @Override
                public void run()
                {
                        long nodes = s.stats().dhtNodes();
                        if (nodes >= 10) {
                                System.out.println("DHT contains " + nodes + " nodes");
                                signal.countDown();
                                timer.cancel();
                        }
                }
        }, 0, 1000);

        System.out.println("Waiting for nodes in DHT (10 seconds)...");
        boolean r = signal.await(10, TimeUnit.SECONDS);
        if (!r) {
                System.out.println("DHT bootstrap timeout");
                System.exit(0);
        }

        System.out.println("Fetching the magnet uri, please wait...");
        byte[] data = s.fetchMagnet(MAGNET, 30, true);
        if (data == null) {
                System.out.println("data == null");
                s.stop();
                return;
        }
        File f = File.createTempFile("test", "torrent");
        FileOutputStream fos = new FileOutputStream(f);
        fos.write(data);
        s.download(new TorrentInfo(f), new File(System.getProperty("user.dir")));

        System.in.read();
        s.stop();
aldenml commented 6 years ago

Hi @proninyaroslav, I found a bug I introduced a few commits ago, it should be fixed now with https://github.com/frostwire/frostwire-jlibtorrent/commit/cdc037c3c24d4cf3995f468473941acd1d48bdc1. I will release an RC version to test soon.

aldenml commented 6 years ago

1.2.0.15-RC1 is out, but don't use it, something is off with the LTO optimization

aldenml commented 6 years ago

@proninyaroslav 1.2.0.15-RC2 is out, give it a try and let us know

proninyaroslav commented 6 years ago

Thanks, I will test as soon as it appears in maven.

aldenml commented 6 years ago

it's already

proninyaroslav commented 6 years ago

It works:

Expected priorities:
priority=IGNORE  file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt

[17:43:54] Current priorities:
priority=IGNORE  file=Play Claw 3.exe
priority=FOUR    file=FFF.NFO
priority=FOUR    file=FILE_ID.DIZ
priority=FOUR    file=PlayClaw.3.0.build.2048_KEYGEN-FFF.exe
priority=FOUR    file=установка.txt
aldenml commented 6 years ago

Closing this?