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);
}
}
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);
}
}
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);
}
}
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;
}
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();
}
Aggregations