Search in sources :

Example 1 with BDecoder

use of org.klomp.snark.bencode.BDecoder in project i2p.i2p by i2p.

the class KRPC method receiveMessage.

// /// Reception.....
/**
 *  @param from dest or null if it didn't come in on signed port
 */
private void receiveMessage(Destination from, int fromPort, byte[] payload) {
    try {
        InputStream is = new ByteArrayInputStream(payload);
        BDecoder dec = new BDecoder(is);
        BEValue bev = dec.bdecodeMap();
        Map<String, BEValue> map = bev.getMap();
        if (_log.shouldLog(Log.DEBUG))
            _log.debug("Got KRPC message " + bev.toString());
        // Lazy here, just let missing Map entries throw NPEs, caught below
        byte[] msgIDBytes = map.get("t").getBytes();
        MsgID mID = new MsgID(msgIDBytes);
        String type = map.get("y").getString();
        if (type.equals("q")) {
            // queries must be repliable
            String method = map.get("q").getString();
            Map<String, BEValue> args = map.get("a").getMap();
            receiveQuery(mID, from, fromPort, method, args);
        } else if (type.equals("r") || type.equals("e")) {
            // get dest from id->dest map
            ReplyWaiter waiter = _sentQueries.remove(mID);
            if (waiter != null) {
                // TODO verify waiter NID and port?
                if (type.equals("r")) {
                    Map<String, BEValue> response = map.get("r").getMap();
                    receiveResponse(waiter, response);
                } else {
                    List<BEValue> error = map.get("e").getList();
                    receiveError(waiter, error);
                }
            } else {
                if (_log.shouldLog(Log.WARN))
                    _log.warn("Rcvd msg with no one waiting: " + bev.toString());
            }
        } else {
            if (_log.shouldLog(Log.WARN))
                _log.warn("Unknown msg type rcvd: " + bev.toString());
            throw new InvalidBEncodingException("Unknown type: " + type);
        }
    // success
    /**
     *        } catch (InvalidBEncodingException e) {
     *        } catch (IOException e) {
     *        } catch (ArrayIndexOutOfBoundsException e) {
     *        } catch (IllegalArgumentException e) {
     *        } catch (ClassCastException e) {
     *        } catch (NullPointerException e) {
     **
     */
    } catch (Exception e) {
        if (_log.shouldLog(Log.WARN))
            _log.warn("Receive error for message", e);
    }
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) BEValue(org.klomp.snark.bencode.BEValue) I2PInvalidDatagramException(net.i2p.client.datagram.I2PInvalidDatagramException) NoSuchElementException(java.util.NoSuchElementException) DataFormatException(net.i2p.data.DataFormatException) IOException(java.io.IOException) I2PSessionException(net.i2p.client.I2PSessionException) InvalidBEncodingException(org.klomp.snark.bencode.InvalidBEncodingException) InvalidBEncodingException(org.klomp.snark.bencode.InvalidBEncodingException) ByteArrayInputStream(java.io.ByteArrayInputStream) BDecoder(org.klomp.snark.bencode.BDecoder) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 2 with BDecoder

use of org.klomp.snark.bencode.BDecoder in project i2p.i2p by i2p.

the class ExtensionHandler method handleMetadata.

/**
 * REF: BEP 9
 * @since 0.8.4
 */
private static void handleMetadata(Peer peer, PeerListener listener, byte[] bs, Log log) {
    if (log.shouldLog(Log.DEBUG))
        log.debug("Got metadata msg from " + peer);
    try {
        InputStream is = new ByteArrayInputStream(bs);
        BDecoder dec = new BDecoder(is);
        BEValue bev = dec.bdecodeMap();
        Map<String, BEValue> map = bev.getMap();
        int type = map.get("msg_type").getInt();
        int piece = map.get("piece").getInt();
        MagnetState state = peer.getMagnetState();
        if (type == TYPE_REQUEST) {
            if (log.shouldLog(Log.DEBUG))
                log.debug("Got request for " + piece + " from: " + peer);
            byte[] pc;
            int totalSize;
            synchronized (state) {
                pc = state.getChunk(piece);
                totalSize = state.getSize();
            }
            sendPiece(peer, piece, pc, totalSize);
            // Do this here because PeerConnectionOut only reports for PIECE messages
            peer.uploaded(pc.length);
            listener.uploaded(peer, pc.length);
        } else if (type == TYPE_DATA) {
            // On close reading of BEP 9, this is the total metadata size.
            // Prior to 0.9.21, we sent the piece size, so we can't count on it.
            // just ignore it. The actual length will be verified in saveChunk()
            // int size = map.get("total_size").getInt();
            // if (log.shouldLog(Log.DEBUG))
            // log.debug("Got data for " + piece + " length " + size + " from: " + peer);
            boolean done;
            int chk = -1;
            synchronized (state) {
                if (state.isComplete())
                    return;
                int len = is.available();
                peer.downloaded(len);
                listener.downloaded(peer, len);
                // this checks the size
                done = state.saveChunk(piece, bs, bs.length - len, len);
                if (log.shouldLog(Log.INFO))
                    log.info("Got chunk " + piece + " from " + peer);
                if (!done)
                    chk = state.getNextRequest();
            }
            // out of the lock
            if (done) {
                // check to see if the MagnetState has it
                if (log.shouldLog(Log.WARN))
                    log.warn("Got last chunk from " + peer);
            } else {
                // get the next chunk
                if (log.shouldLog(Log.INFO))
                    log.info("Request chunk " + chk + " from " + peer);
                sendRequest(peer, chk);
            }
        } else if (type == TYPE_REJECT) {
            if (log.shouldLog(Log.WARN))
                log.warn("Got reject msg from " + peer);
            peer.disconnect(false);
        } else {
            if (log.shouldLog(Log.WARN))
                log.warn("Got unknown metadata msg from " + peer);
            peer.disconnect(false);
        }
    } catch (Exception e) {
        if (log.shouldLog(Log.INFO))
            log.info("Metadata ext. msg. exception from " + peer, e);
        // fatal ?
        peer.disconnect(false);
    }
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) BDecoder(org.klomp.snark.bencode.BDecoder) BEValue(org.klomp.snark.bencode.BEValue)

Example 3 with BDecoder

use of org.klomp.snark.bencode.BDecoder in project i2p.i2p by i2p.

the class ExtensionHandler method handlePEX.

/**
 * Can't find a published standard for this anywhere.
 * See the libtorrent code.
 * Here we use the "added" key as a single string of concatenated
 * 32-byte peer hashes.
 * added.f and dropped unsupported
 * @since 0.8.4
 */
private static void handlePEX(Peer peer, PeerListener listener, byte[] bs, Log log) {
    if (log.shouldLog(Log.DEBUG))
        log.debug("Got PEX msg from " + peer);
    try {
        InputStream is = new ByteArrayInputStream(bs);
        BDecoder dec = new BDecoder(is);
        BEValue bev = dec.bdecodeMap();
        Map<String, BEValue> map = bev.getMap();
        bev = map.get("added");
        if (bev == null)
            return;
        byte[] ids = bev.getBytes();
        if (ids.length < HASH_LENGTH)
            return;
        int len = Math.min(ids.length, (I2PSnarkUtil.MAX_CONNECTIONS - 1) * HASH_LENGTH);
        List<PeerID> peers = new ArrayList<PeerID>(len / HASH_LENGTH);
        for (int off = 0; off < len; off += HASH_LENGTH) {
            byte[] hash = new byte[HASH_LENGTH];
            System.arraycopy(ids, off, hash, 0, HASH_LENGTH);
            if (DataHelper.eq(hash, peer.getPeerID().getDestHash()))
                continue;
            PeerID pID = new PeerID(hash, listener.getUtil());
            peers.add(pID);
        }
        // could include ourselves, listener must remove
        listener.gotPeers(peer, peers);
    } catch (Exception e) {
        if (log.shouldLog(Log.INFO))
            log.info("PEX msg exception from " + peer, e);
    // peer.disconnect(false);
    }
}
Also used : ByteArrayInputStream(java.io.ByteArrayInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) BDecoder(org.klomp.snark.bencode.BDecoder) ArrayList(java.util.ArrayList) BEValue(org.klomp.snark.bencode.BEValue)

Example 4 with BDecoder

use of org.klomp.snark.bencode.BDecoder in project i2p.i2p by i2p.

the class MagnetState method buildMetaInfo.

/**
 *  @return true if this was the last piece
 *  @throws NullPointerException IllegalArgumentException, IOException, ...
 */
private MetaInfo buildMetaInfo() throws Exception {
    // top map has nothing in it but the info map (no announce)
    Map<String, BEValue> map = new HashMap<String, BEValue>();
    InputStream is = new ByteArrayInputStream(metainfoBytes);
    BDecoder dec = new BDecoder(is);
    BEValue bev = dec.bdecodeMap();
    map.put("info", bev);
    MetaInfo newmeta = new MetaInfo(map);
    if (!DataHelper.eq(newmeta.getInfoHash(), infohash)) {
        // Disaster. Start over. ExtensionHandler will catch
        // the IOE and disconnect the peer, hopefully we will
        // find a new peer.
        // TODO: Count fails and give up eventually
        have = new BitField(totalChunks);
        requested = new BitField(totalChunks);
        throw new IOException("info hash mismatch");
    }
    return newmeta;
}
Also used : HashMap(java.util.HashMap) ByteArrayInputStream(java.io.ByteArrayInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) InputStream(java.io.InputStream) BDecoder(org.klomp.snark.bencode.BDecoder) IOException(java.io.IOException) BEValue(org.klomp.snark.bencode.BEValue)

Example 5 with BDecoder

use of org.klomp.snark.bencode.BDecoder in project i2p.i2p by i2p.

the class MetaInfo method getNameAndInfoHash.

/**
 * Efficiently returns the name and the 20 byte SHA1 hash of the info dictionary in a torrent file
 * Caller must close stream.
 *
 * @param infoHashOut 20-byte out parameter
 * @since 0.8.5
 */
public static String getNameAndInfoHash(InputStream in, byte[] infoHashOut) throws IOException {
    BDecoder bd = new BDecoder(in);
    Map<String, BEValue> m = bd.bdecodeMap().getMap();
    BEValue ibev = m.get("info");
    if (ibev == null)
        throw new InvalidBEncodingException("Missing info map");
    Map<String, BEValue> i = ibev.getMap();
    BEValue rvbev = i.get("name");
    if (rvbev == null)
        throw new InvalidBEncodingException("Missing name");
    byte[] h = bd.get_special_map_digest();
    System.arraycopy(h, 0, infoHashOut, 0, 20);
    return rvbev.getString();
}
Also used : InvalidBEncodingException(org.klomp.snark.bencode.InvalidBEncodingException) BDecoder(org.klomp.snark.bencode.BDecoder) BEValue(org.klomp.snark.bencode.BEValue)

Aggregations

BDecoder (org.klomp.snark.bencode.BDecoder)8 BEValue (org.klomp.snark.bencode.BEValue)8 ByteArrayInputStream (java.io.ByteArrayInputStream)7 InputStream (java.io.InputStream)7 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 IOException (java.io.IOException)2 List (java.util.List)2 Map (java.util.Map)2 InvalidBEncodingException (org.klomp.snark.bencode.InvalidBEncodingException)2 NoSuchElementException (java.util.NoSuchElementException)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 I2PSessionException (net.i2p.client.I2PSessionException)1 I2PInvalidDatagramException (net.i2p.client.datagram.I2PInvalidDatagramException)1 DataFormatException (net.i2p.data.DataFormatException)1 Comment (org.klomp.snark.comments.Comment)1