Search in sources :

Example 1 with PEPeerControl

use of com.biglybt.core.peer.impl.PEPeerControl in project BiglyBT by BiglySoftware.

the class HTTPNetworkConnectionWebSeed method decodeHeader.

@Override
protected void decodeHeader(final HTTPMessageDecoder decoder, final String header) throws IOException {
    if (switching) {
        Debug.out("new header received while paused");
        throw (new IOException("Bork"));
    }
    if (!isSeed()) {
        return;
    }
    PEPeerControl control = getPeerControl();
    try {
        int pos = header.indexOf(NL);
        String line = header.substring(4, pos);
        pos = line.lastIndexOf(' ');
        String url = line.substring(0, pos).trim();
        pos = url.indexOf('?');
        if (pos != -1) {
            url = url.substring(pos + 1);
        }
        StringTokenizer tok = new StringTokenizer(url, "&");
        int piece = -1;
        List<int[]> ranges = new ArrayList<>();
        while (tok.hasMoreElements()) {
            String token = tok.nextToken();
            pos = token.indexOf('=');
            if (pos != -1) {
                String lhs = token.substring(0, pos).toLowerCase(MessageText.LOCALE_ENGLISH);
                String rhs = token.substring(pos + 1);
                if (lhs.equals("info_hash")) {
                    final byte[] old_hash = control.getHash();
                    final byte[] new_hash = URLDecoder.decode(rhs, "ISO-8859-1").getBytes("ISO-8859-1");
                    if (!Arrays.equals(new_hash, old_hash)) {
                        switching = true;
                        decoder.pauseInternally();
                        flushRequests(new flushListener() {

                            private boolean triggered;

                            @Override
                            public void flushed() {
                                synchronized (this) {
                                    if (triggered) {
                                        return;
                                    }
                                    triggered = true;
                                }
                                getManager().reRoute(HTTPNetworkConnectionWebSeed.this, old_hash, new_hash, header);
                            }
                        });
                        return;
                    }
                } else if (lhs.equals("piece")) {
                    try {
                        piece = Integer.parseInt(rhs);
                    } catch (Throwable e) {
                        throw (new IOException("Invalid piece number '" + rhs + "'"));
                    }
                } else if (lhs.equals("ranges")) {
                    StringTokenizer range_tok = new StringTokenizer(rhs, ",");
                    while (range_tok.hasMoreTokens()) {
                        String range = range_tok.nextToken();
                        int sep = range.indexOf('-');
                        if (sep == -1) {
                            throw (new IOException("Invalid range specification '" + rhs + "'"));
                        }
                        try {
                            ranges.add(new int[] { Integer.parseInt(range.substring(0, sep)), Integer.parseInt(range.substring(sep + 1)) });
                        } catch (Throwable e) {
                            throw (new IOException("Invalid range specification '" + rhs + "'"));
                        }
                    }
                }
            }
        }
        if (piece == -1) {
            throw (new IOException("Piece number not specified"));
        }
        boolean keep_alive = header.toLowerCase(MessageText.LOCALE_ENGLISH).contains("keep-alive");
        int this_piece_size = control.getPieceLength(piece);
        if (ranges.size() == 0) {
            ranges.add(new int[] { 0, this_piece_size - 1 });
        }
        long[] offsets = new long[ranges.size()];
        long[] lengths = new long[ranges.size()];
        long piece_offset = piece * (long) control.getPieceLength(0);
        for (int i = 0; i < ranges.size(); i++) {
            int[] range = ranges.get(i);
            int start = range[0];
            int end = range[1];
            if (start < 0 || start >= this_piece_size || end < 0 || end >= this_piece_size || start > end) {
                throw (new IOException("Invalid range specification '" + start + "-" + end + "'"));
            }
            offsets[i] = piece_offset + start;
            lengths[i] = (end - start) + 1;
        }
        addRequest(new httpRequest(offsets, lengths, 0, false, keep_alive));
    } catch (Throwable e) {
        Debug.outNoStack("Decode of '" + (header.length() > 128 ? (header.substring(0, 128) + "...") : header) + "' - " + Debug.getNestedExceptionMessageAndStack(e));
        if (e instanceof IOException) {
            throw ((IOException) e);
        } else {
            throw (new IOException("Decode failed: " + Debug.getNestedExceptionMessage(e)));
        }
    }
}
Also used : ArrayList(java.util.ArrayList) IOException(java.io.IOException) StringTokenizer(java.util.StringTokenizer) PEPeerControl(com.biglybt.core.peer.impl.PEPeerControl)

Example 2 with PEPeerControl

use of com.biglybt.core.peer.impl.PEPeerControl in project BiglyBT by BiglySoftware.

the class HTTPNetworkConnection method addRequest.

protected void addRequest(httpRequest request) throws IOException {
    last_http_activity_time = SystemTime.getCurrentTime();
    PEPeerControl control = getPeerControl();
    if (!sent_handshake) {
        sent_handshake = true;
        decoder.addMessage(new BTHandshake(control.getHash(), peer_id, BTHandshake.BT_RESERVED_MODE, (byte) 1));
        byte[] bits = new byte[(control.getPieces().length + 7) / 8];
        DirectByteBuffer buffer = new DirectByteBuffer(ByteBuffer.wrap(bits));
        decoder.addMessage(new BTBitfield(buffer, (byte) 1));
    }
    synchronized (outstanding_requests) {
        http_requests.add(request);
    }
    submitBTRequests();
}
Also used : PEPeerControl(com.biglybt.core.peer.impl.PEPeerControl)

Example 3 with PEPeerControl

use of com.biglybt.core.peer.impl.PEPeerControl in project BiglyBT by BiglySoftware.

the class HTTPNetworkConnection method submitBTRequests.

protected void submitBTRequests() throws IOException {
    PEPeerControl control = getPeerControl();
    long piece_size = control.getPieceLength(0);
    synchronized (outstanding_requests) {
        while (outstanding_requests.size() < MAX_OUTSTANDING_BT_REQUESTS && http_requests.size() > 0) {
            httpRequest http_request = (httpRequest) http_requests.get(0);
            long[] offsets = http_request.getModifiableOffsets();
            long[] lengths = http_request.getModifiableLengths();
            int index = http_request.getIndex();
            long offset = offsets[index];
            long length = lengths[index];
            int this_piece_number = (int) (offset / piece_size);
            int this_piece_size = control.getPieceLength(this_piece_number);
            int offset_in_piece = (int) (offset - (this_piece_number * piece_size));
            int space_this_piece = this_piece_size - offset_in_piece;
            int request_size = (int) Math.min(length, space_this_piece);
            request_size = Math.min(request_size, max_read_block_size);
            addBTRequest(new BTRequest(this_piece_number, offset_in_piece, request_size, (byte) 1), http_request);
            if (request_size == length) {
                if (index == offsets.length - 1) {
                    http_requests.remove(0);
                } else {
                    http_request.setIndex(index + 1);
                }
            } else {
                offsets[index] += request_size;
                lengths[index] -= request_size;
            }
        }
    }
}
Also used : PEPeerControl(com.biglybt.core.peer.impl.PEPeerControl)

Example 4 with PEPeerControl

use of com.biglybt.core.peer.impl.PEPeerControl in project BiglyBT by BiglySoftware.

the class HTTPNetworkConnectionFile method decodeHeader.

@Override
protected void decodeHeader(HTTPMessageDecoder decoder, final String header) throws IOException {
    if (switching) {
        Debug.out("new header received while paused");
        throw (new IOException("Bork"));
    }
    if (!isSeed()) {
        return;
    }
    PEPeerControl control = getPeerControl();
    DiskManager dm = control.getDiskManager();
    if (dm == null) {
        Debug.out("Disk manager is null");
        throw (new IOException("Disk manager unavailable"));
    }
    TOTorrent to_torrent = dm.getTorrent();
    char[] chars = header.toCharArray();
    int last_pos = 0;
    int line_num = 0;
    String target_str = null;
    DiskManagerFileInfo target_file = null;
    long file_offset = 0;
    List<long[]> ranges = new ArrayList<>();
    boolean keep_alive = false;
    for (int i = 1; i < chars.length; i++) {
        if (chars[i - 1] == '\r' && chars[i] == '\n') {
            String line = new String(chars, last_pos, i - last_pos).trim();
            last_pos = i;
            line_num++;
            if (line_num == 1) {
                line = line.substring(line.indexOf("files/") + 6);
                int hash_end = line.indexOf("/");
                final byte[] old_hash = control.getHash();
                final byte[] new_hash = URLDecoder.decode(line.substring(0, hash_end), "ISO-8859-1").getBytes("ISO-8859-1");
                if (!Arrays.equals(new_hash, old_hash)) {
                    switching = true;
                    decoder.pauseInternally();
                    flushRequests(new flushListener() {

                        private boolean triggered;

                        @Override
                        public void flushed() {
                            synchronized (this) {
                                if (triggered) {
                                    return;
                                }
                                triggered = true;
                            }
                            getManager().reRoute(HTTPNetworkConnectionFile.this, old_hash, new_hash, header);
                        }
                    });
                    return;
                }
                line = line.substring(hash_end + 1);
                line = line.substring(0, line.lastIndexOf(' '));
                String file = line;
                if (to_torrent.isSimpleTorrent()) {
                    // optimise for simple torrents. also support the case where
                    // client has the hash but doesn't know the file name
                    target_file = dm.getFiles()[0];
                } else {
                    target_str = file;
                    StringTokenizer tok = new StringTokenizer(file, "/");
                    List<byte[]> bits = new ArrayList<>();
                    while (tok.hasMoreTokens()) {
                        bits.add(URLDecoder.decode(tok.nextToken(), "ISO-8859-1").getBytes("ISO-8859-1"));
                    }
                    if (!to_torrent.isSimpleTorrent() && bits.size() > 1) {
                        if (Arrays.equals(to_torrent.getName(), (byte[]) bits.get(0))) {
                            bits.remove(0);
                        }
                    }
                    DiskManagerFileInfo[] files = dm.getFiles();
                    file_offset = 0;
                    for (int j = 0; j < files.length; j++) {
                        TOTorrentFile torrent_file = files[j].getTorrentFile();
                        byte[][] comps = torrent_file.getPathComponents();
                        if (comps.length == bits.size()) {
                            boolean match = true;
                            for (int k = 0; k < comps.length; k++) {
                                if (!Arrays.equals(comps[k], (byte[]) bits.get(k))) {
                                    match = false;
                                    break;
                                }
                            }
                            if (match) {
                                target_file = files[j];
                                break;
                            }
                        }
                        file_offset += torrent_file.getLength();
                    }
                }
            } else {
                line = line.toLowerCase(MessageText.LOCALE_ENGLISH);
                if (line.startsWith("range") && target_file != null) {
                    line = line.substring(5).trim();
                    if (line.startsWith(":")) {
                        String range_str = line.substring(1).trim();
                        if (range_str.startsWith("bytes=")) {
                            long file_length = target_file.getLength();
                            StringTokenizer tok2 = new StringTokenizer(range_str.substring(6), ",");
                            while (tok2.hasMoreTokens()) {
                                String range = tok2.nextToken();
                                try {
                                    int pos = range.indexOf('-');
                                    if (pos != -1) {
                                        String lhs = range.substring(0, pos);
                                        String rhs = range.substring(pos + 1);
                                        long start;
                                        long end;
                                        if (lhs.length() == 0) {
                                            // -222 is last 222 bytes of file
                                            end = file_length - 1;
                                            start = file_length - Long.parseLong(rhs);
                                        } else if (rhs.length() == 0) {
                                            end = file_length - 1;
                                            start = Long.parseLong(lhs);
                                        } else {
                                            start = Long.parseLong(lhs);
                                            end = Long.parseLong(rhs);
                                        }
                                        ranges.add(new long[] { start, end });
                                    }
                                } catch (Throwable e) {
                                }
                            }
                        }
                        if (ranges.size() == 0) {
                            log("Invalid range specification: '" + line + "'");
                            sendAndClose(getManager().getRangeNotSatisfiable());
                            return;
                        }
                    }
                } else if (line.contains("keep-alive")) {
                    keep_alive = true;
                }
            }
        }
    }
    if (target_file == null) {
        log("Failed to find file '" + target_str + "'");
        sendAndClose(getManager().getNotFound());
        return;
    }
    try {
        String name = target_file.getFile(true).getName();
        int pos = name.lastIndexOf(".");
        if (pos != -1) {
            setContentType(HTTPUtils.guessContentTypeFromFileType(name.substring(pos + 1)));
        }
    } catch (Throwable e) {
    }
    long file_length = target_file.getLength();
    boolean partial_content = ranges.size() > 0;
    if (!partial_content) {
        ranges.add(new long[] { 0, file_length - 1 });
    }
    long[] offsets = new long[ranges.size()];
    long[] lengths = new long[ranges.size()];
    for (int i = 0; i < ranges.size(); i++) {
        long[] range = (long[]) ranges.get(i);
        long start = range[0];
        long end = range[1];
        if (start < 0 || start >= file_length || end < 0 || end >= file_length || start > end) {
            log("Invalid range specification: '" + start + "-" + end + "'");
            sendAndClose(getManager().getRangeNotSatisfiable());
            return;
        }
        offsets[i] = file_offset + start;
        lengths[i] = (end - start) + 1;
    }
    addRequest(new httpRequest(offsets, lengths, file_length, partial_content, keep_alive));
}
Also used : DiskManagerFileInfo(com.biglybt.core.disk.DiskManagerFileInfo) ArrayList(java.util.ArrayList) IOException(java.io.IOException) DiskManager(com.biglybt.core.disk.DiskManager) TOTorrentFile(com.biglybt.core.torrent.TOTorrentFile) StringTokenizer(java.util.StringTokenizer) TOTorrent(com.biglybt.core.torrent.TOTorrent) PEPeerControl(com.biglybt.core.peer.impl.PEPeerControl)

Example 5 with PEPeerControl

use of com.biglybt.core.peer.impl.PEPeerControl in project BiglyBT by BiglySoftware.

the class PeerManager method updateStats.

@Override
public void updateStats(Set types, Map values) {
    if (types.contains(CoreStats.ST_PEER_MANAGER_COUNT)) {
        values.put(CoreStats.ST_PEER_MANAGER_COUNT, new Long(registered_legacy_managers.size()));
    }
    if (types.contains(CoreStats.ST_PEER_MANAGER_PEER_COUNT) || types.contains(CoreStats.ST_PEER_MANAGER_PEER_SNUBBED_COUNT) || types.contains(CoreStats.ST_PEER_MANAGER_PEER_STALLED_DISK_COUNT)) {
        long total_peers = 0;
        long total_snubbed_peers = 0;
        long total_stalled_pending_load = 0;
        try {
            managers_mon.enter();
            Iterator<List<PeerManagerRegistrationImpl>> it = registered_legacy_managers.values().iterator();
            while (it.hasNext()) {
                List<PeerManagerRegistrationImpl> registrations = it.next();
                Iterator<PeerManagerRegistrationImpl> it2 = registrations.iterator();
                while (it2.hasNext()) {
                    PeerManagerRegistrationImpl reg = it2.next();
                    PEPeerControl control = reg.getActiveControl();
                    if (control != null) {
                        total_peers += control.getNbPeers();
                        total_snubbed_peers += control.getNbPeersSnubbed();
                        total_stalled_pending_load += control.getNbPeersStalledPendingLoad();
                    }
                }
            }
        } finally {
            managers_mon.exit();
        }
        if (types.contains(CoreStats.ST_PEER_MANAGER_PEER_COUNT)) {
            values.put(CoreStats.ST_PEER_MANAGER_PEER_COUNT, new Long(total_peers));
        }
        if (types.contains(CoreStats.ST_PEER_MANAGER_PEER_SNUBBED_COUNT)) {
            values.put(CoreStats.ST_PEER_MANAGER_PEER_SNUBBED_COUNT, new Long(total_snubbed_peers));
        }
        if (types.contains(CoreStats.ST_PEER_MANAGER_PEER_STALLED_DISK_COUNT)) {
            values.put(CoreStats.ST_PEER_MANAGER_PEER_STALLED_DISK_COUNT, new Long(total_stalled_pending_load));
        }
    }
}
Also used : PEPeerControl(com.biglybt.core.peer.impl.PEPeerControl)

Aggregations

PEPeerControl (com.biglybt.core.peer.impl.PEPeerControl)5 IOException (java.io.IOException)2 ArrayList (java.util.ArrayList)2 StringTokenizer (java.util.StringTokenizer)2 DiskManager (com.biglybt.core.disk.DiskManager)1 DiskManagerFileInfo (com.biglybt.core.disk.DiskManagerFileInfo)1 TOTorrent (com.biglybt.core.torrent.TOTorrent)1 TOTorrentFile (com.biglybt.core.torrent.TOTorrentFile)1