use of com.biglybt.core.peer.impl.PEPeerTransport in project BiglyBT by BiglySoftware.
the class ClientStatsView method addPeer.
protected void addPeer(PEPeer peer) {
byte[] bloomId;
long now = SystemTime.getCurrentTime();
// Bloom Filter is based on the first 8 bytes of peer id + ip address
// This captures more duplicates than peer id because most clients
// randomize their peer id on restart. IP address, however, changes
// less often.
byte[] address = null;
byte[] peerId = peer.getId();
InetAddress ip = peer.getAlternativeIPv6();
if (ip == null) {
try {
ip = AddressUtils.getByName(peer.getIp());
address = ip.getAddress();
} catch (Throwable e) {
String ipString = peer.getIp();
if (ipString != null) {
address = ByteFormatter.intToByteArray(ipString.hashCode());
}
}
} else {
address = ip.getAddress();
}
if (address == null) {
bloomId = peerId;
} else {
bloomId = new byte[8 + address.length];
System.arraycopy(peerId, 0, bloomId, 0, 8);
System.arraycopy(address, 0, bloomId, 8, address.length);
}
synchronized (mapData) {
// break on month.. assume user didn't last use this on the same month in a different year
calendar.setTimeInMillis(now);
int thisMonth = calendar.get(Calendar.MONTH);
if (thisMonth != lastAddMonth) {
if (lastAddMonth == 0) {
lastAddMonth = thisMonth;
} else {
String s = new SimpleDateFormat("yyyy-MM").format(new Date(lastAdd));
String filename = CONFIG_FILE_ARCHIVE.replace("%1", s);
save(filename);
lastAddMonth = thisMonth;
lastAdd = 0;
bloomFilter = BloomFilterFactory.createRotating(BloomFilterFactory.createAddOnly(BLOOMFILTER_SIZE), 2);
bloomFilterPeerId = BloomFilterFactory.createRotating(BloomFilterFactory.createAddOnly(BLOOMFILTER_PEERID_SIZE), 2);
overall = new ClientStatsOverall();
mapData.clear();
if (tv != null) {
tv.removeAllTableRows();
}
totalTime = 0;
startedListeningOn = 0;
}
}
String id = getID(peer);
ClientStatsDataSource stat;
stat = mapData.get(id);
boolean needNew = stat == null;
if (needNew) {
stat = new ClientStatsDataSource();
stat.overall = overall;
stat.client = id;
mapData.put(id, stat);
}
boolean inBloomFilter = bloomFilter.contains(bloomId) || bloomFilterPeerId.contains(peerId);
if (!inBloomFilter) {
bloomFilter.add(bloomId);
bloomFilterPeerId.add(peerId);
lastAdd = now;
synchronized (overall) {
overall.count++;
}
stat.count++;
}
stat.current++;
long existingBytesReceived = peer.getStats().getTotalDataBytesReceived();
long existingBytesSent = peer.getStats().getTotalDataBytesSent();
long existingBytesDiscarded = peer.getStats().getTotalBytesDiscarded();
if (existingBytesReceived > 0) {
stat.bytesReceived -= existingBytesReceived;
if (stat.bytesReceived < 0) {
stat.bytesReceived = 0;
}
}
if (existingBytesSent > 0) {
stat.bytesSent -= existingBytesSent;
if (stat.bytesSent < 0) {
stat.bytesSent = 0;
}
}
if (existingBytesDiscarded > 0) {
stat.bytesDiscarded -= existingBytesDiscarded;
if (stat.bytesDiscarded < 0) {
stat.bytesDiscarded = 0;
}
}
if (peer instanceof PEPeerTransport) {
PeerItem identity = ((PEPeerTransport) peer).getPeerItemIdentity();
if (identity != null) {
String network = identity.getNetwork();
if (network != null) {
Map<String, Object> map = stat.perNetworkStats.get(network);
if (map == null) {
map = new HashMap<>();
stat.perNetworkStats.put(network, map);
}
if (!inBloomFilter) {
long count = MapUtils.getMapLong(map, "count", 0);
map.put("count", count + 1);
}
if (existingBytesReceived > 0) {
long bytesReceived = MapUtils.getMapLong(map, "bytesReceived", 0);
bytesReceived -= existingBytesReceived;
if (bytesReceived < 0) {
bytesReceived = 0;
}
map.put("bytesReceived", bytesReceived);
}
if (existingBytesSent > 0) {
long bytesSent = MapUtils.getMapLong(map, "bytesSent", 0);
bytesSent -= existingBytesSent;
if (bytesSent < 0) {
bytesSent = 0;
}
map.put("bytesSent", bytesSent);
}
if (existingBytesDiscarded > 0) {
long bytesDiscarded = MapUtils.getMapLong(map, "bytesDiscarded", 0);
bytesDiscarded -= existingBytesDiscarded;
if (bytesDiscarded < 0) {
bytesDiscarded = 0;
}
map.put("bytesDiscarded", bytesDiscarded);
}
}
}
}
if (tv != null) {
if (needNew) {
tv.addDataSource(stat);
} else {
TableRowCore row = tv.getRow(stat);
if (row != null) {
row.invalidate();
}
}
}
}
}
use of com.biglybt.core.peer.impl.PEPeerTransport in project BiglyBT by BiglySoftware.
the class PEPeerTransportProtocol method decodeBTHandshake.
protected void decodeBTHandshake(BTHandshake handshake) {
if (Logger.isEnabled())
Logger.log(new LogEvent(this, LOGID, "Received handshake with reserved bytes: " + ByteFormatter.nicePrint(handshake.getReserved(), false)));
PeerIdentityDataID my_peer_data_id = manager.getPeerIdentityDataID();
if (getConnectionState() == CONNECTION_FULLY_ESTABLISHED) {
handshake.destroy();
closeConnectionInternally("peer sent another handshake after the initial connect");
}
if (!Arrays.equals(manager.getTargetHash(), handshake.getDataHash())) {
closeConnectionInternally("handshake has wrong infohash");
handshake.destroy();
return;
}
peer_id = handshake.getPeerId();
// Decode a client identification string from the given peerID
this.client_peer_id = this.client = StringInterner.intern(PeerClassifier.getClientDescription(peer_id, network));
// make sure the client type is not banned
if (!PeerClassifier.isClientTypeAllowed(client)) {
closeConnectionInternally(client + " client type not allowed to connect, banned");
handshake.destroy();
return;
}
// make sure we are not connected to ourselves
if (Arrays.equals(manager.getPeerId(), peer_id)) {
// make sure we dont do it again
manager.peerVerifiedAsSelf(this);
closeConnectionInternally("given peer id matches myself");
handshake.destroy();
return;
}
// make sure we are not already connected to this peer
boolean sameIdentity = PeerIdentityManager.containsIdentity(my_peer_data_id, peer_id, getPort());
boolean sameIP = false;
// allow loopback connects for co-located proxy-based connections and testing
boolean same_allowed = COConfigurationManager.getBooleanParameter("Allow Same IP Peers") || ip.equals("127.0.0.1");
if (!same_allowed) {
if (PeerIdentityManager.containsIPAddress(my_peer_data_id, ip)) {
sameIP = true;
}
}
if (sameIdentity) {
boolean close = true;
PEPeerTransport existing = manager.getTransportFromIdentity(peer_id);
if (existing != null) {
String existing_ip = existing.getIp();
if (connection.isLANLocal()) {
if (!existing.isLANLocal() || ((existing_ip.endsWith(".1") || existing_ip.endsWith(".254")) && !existing_ip.equals(ip))) {
// so drop the existing connection if it is an external (non lan-local) one
String msg = "Dropping existing non-lanlocal peer connection [" + existing + "] in favour of [" + this + "]";
Debug.outNoStack(msg);
manager.removePeer(existing, msg);
close = false;
}
} else {
boolean this_ipv6 = ip.contains(":");
boolean existing_ipv6 = existing_ip.contains(":");
if (this_ipv6 != existing_ipv6) {
boolean close_existing;
if (prefer_ipv6) {
close_existing = this_ipv6;
} else {
close_existing = existing_ipv6;
}
if (close_existing) {
String msg = "Dropping existing peer connection [" + existing + "] in favour of [" + this + "]";
manager.removePeer(existing, msg);
close = false;
}
}
}
}
if (close) {
if (Constants.IS_CVS_VERSION) {
try {
List<PEPeer> peers = manager.getPeers();
String dup_str = "?";
boolean dup_ip = false;
for (PEPeer p : peers) {
if (p == this) {
continue;
}
byte[] id = p.getId();
if (Arrays.equals(id, peer_id)) {
dup_ip = p.getIp().equals(getIp());
dup_str = p.getClient() + "/" + p.getClientNameFromExtensionHandshake() + "/" + p.getIp() + "/" + p.getPort();
break;
}
}
String my_str = getClient() + "/" + getIp() + "/" + getPort();
if (!dup_ip) {
Debug.outNoStack("Duplicate peer id detected: id=" + ByteFormatter.encodeString(peer_id) + ": this=" + my_str + ",other=" + dup_str);
}
} catch (Throwable e) {
}
}
closeConnectionInternally("peer matches already-connected peer id");
handshake.destroy();
return;
}
}
if (sameIP) {
closeConnectionInternally("peer matches already-connected IP address, duplicate connections not allowed");
handshake.destroy();
return;
}
// make sure we haven't reached our connection limit
boolean max_reached = manager.getMaxNewConnectionsAllowed(network) == 0;
if (max_reached && !manager.doOptimisticDisconnect(isLANLocal(), isPriorityConnection(), network)) {
int[] _con_max = manager.getMaxConnections();
int con_max = _con_max[0] + _con_max[1];
final String msg = "too many existing peer connections [p" + PeerIdentityManager.getIdentityCount(my_peer_data_id) + "/g" + PeerIdentityManager.getTotalIdentityCount() + ", pmx" + PeerUtils.MAX_CONNECTIONS_PER_TORRENT + "/gmx" + PeerUtils.MAX_CONNECTIONS_TOTAL + "/dmx" + con_max + "]";
// System.out.println( msg );
closeConnectionInternally(msg);
handshake.destroy();
return;
}
try {
closing_mon.enter();
if (closing) {
final String msg = "connection already closing";
closeConnectionInternally(msg);
handshake.destroy();
return;
}
if (!PeerIdentityManager.addIdentity(my_peer_data_id, peer_id, getPort(), ip)) {
closeConnectionInternally("peer matches already-connected peer id");
handshake.destroy();
return;
}
identityAdded = true;
} finally {
closing_mon.exit();
}
if (Logger.isEnabled())
Logger.log(new LogEvent(this, LOGID, "In: has sent their handshake"));
// Let's store the reserved bits somewhere so they can be examined later (externally).
handshake_reserved_bytes = handshake.getReserved();
/*
* Waiting until we've received the initiating-end's full handshake, before sending back our own,
* really should be the "proper" behavior. However, classic BT trackers running NAT checking will
* only send the first 48 bytes (up to infohash) of the peer handshake, skipping peerid, which means
* we'll never get their complete handshake, and thus never reply, which causes the NAT check to fail.
* So, we need to send our handshake earlier, after we've verified the infohash.
*
if( incoming ) { //wait until we've received their handshake before sending ours
sendBTHandshake();
}
*/
this.ml_dht_enabled = (handshake_reserved_bytes[7] & 0x01) == 1;
// disable fast if we have per-torrent upload limit as it is non-trivial to enforce for choked fast-start
// transfers as peer is in the multi-peer upload group (as choked) and in this mode the limit isn't
// enforced
fast_extension_enabled = BTHandshake.FAST_EXTENSION_ENABLED && manager.getUploadRateLimitBytesPerSecond() == 0 && (handshake_reserved_bytes[7] & 0x04) != 0;
messaging_mode = decideExtensionProtocol(handshake);
// extended protocol processing
if (messaging_mode == MESSAGING_AZMP) {
/**
* We log when a non-Azureus client claims to support extended messaging...
* Obviously other Azureus clients do, so there's no point logging about them!
*/
if (Logger.isEnabled() && !client.contains("Azureus") && !client.contains(Constants.BIGLYBT_NAME)) {
Logger.log(new LogEvent(this, LOGID, "Handshake claims extended AZ " + "messaging support... enabling AZ mode."));
}
// Ignore the handshake setting - wait for the AZHandshake to indicate
// support instead.
this.ml_dht_enabled = false;
Transport transport = connection.getTransport();
int padding_mode;
if (transport.isEncrypted()) {
if (transport.isTCP()) {
padding_mode = AZMessageEncoder.PADDING_MODE_NORMAL;
} else {
padding_mode = AZMessageEncoder.PADDING_MODE_MINIMAL;
}
} else {
padding_mode = AZMessageEncoder.PADDING_MODE_NONE;
}
connection.getIncomingMessageQueue().setDecoder(new AZMessageDecoder());
connection.getOutgoingMessageQueue().setEncoder(new AZMessageEncoder(padding_mode));
// We will wait until we get the Az handshake before considering the connection
// initialised.
this.sendAZHandshake();
handshake.destroy();
} else if (messaging_mode == MESSAGING_LTEP) {
if (Logger.isEnabled()) {
Logger.log(new LogEvent(this, LOGID, "Enabling LT extension protocol support..."));
}
connection.getIncomingMessageQueue().setDecoder(new LTMessageDecoder());
connection.getOutgoingMessageQueue().setEncoder(new LTMessageEncoder(this));
generateSessionId();
if (!is_metadata_download) {
this.initPostConnection(handshake);
}
this.sendLTHandshake();
} else {
this.client = ClientIdentifier.identifyBTOnly(this.client_peer_id, this.handshake_reserved_bytes);
connection.getIncomingMessageQueue().getDecoder().resumeDecoding();
this.initPostConnection(handshake);
}
}
use of com.biglybt.core.peer.impl.PEPeerTransport in project BiglyBT by BiglySoftware.
the class HTTPNetworkManager method reRoute.
protected void reRoute(final HTTPNetworkConnection old_http_connection, final byte[] old_hash, final byte[] new_hash, final String header) {
final NetworkConnection old_connection = old_http_connection.getConnection();
PeerManagerRegistration reg_data = PeerManager.getSingleton().manualMatchHash(old_connection.getEndpoint().getNotionalAddress(), new_hash);
if (reg_data == null) {
old_http_connection.close("Re-routing failed - registration not found");
return;
}
final Transport transport = old_connection.detachTransport();
old_http_connection.close("Switching torrents");
final NetworkConnection new_connection = NetworkManager.getSingleton().bindTransport(transport, new HTTPMessageEncoder(), new HTTPMessageDecoder(header));
PeerManager.getSingleton().manualRoute(reg_data, new_connection, new PeerManagerRoutingListener() {
@Override
public boolean routed(PEPeerTransport peer) {
HTTPNetworkConnection new_http_connection;
if (header.contains("/webseed")) {
new_http_connection = new HTTPNetworkConnectionWebSeed(HTTPNetworkManager.this, new_connection, peer);
} else if (header.contains("/files/")) {
new_http_connection = new HTTPNetworkConnectionFile(HTTPNetworkManager.this, new_connection, peer);
} else {
return (false);
}
// fake a wakeup so pre-read header is processed
new_http_connection.readWakeup();
return (true);
}
});
}
use of com.biglybt.core.peer.impl.PEPeerTransport in project BiglyBT by BiglySoftware.
the class PeersGraphicView method refresh.
protected void refresh() {
synchronized (dm_data_lock) {
if (canvas == null || canvas.isDisposed()) {
return;
}
Rectangle bounds = canvas.getClientArea();
if (bounds.width <= 0 || bounds.height <= 0) {
return;
}
if (arrow_refresher == null) {
arrow_refresher = SimpleTimer.addPeriodicEvent("PGV:AR", 100, (ev) -> {
Utils.execSWTThread(() -> {
if (canvas.isDisposed()) {
synchronized (dm_data_lock) {
if (arrow_refresher != null) {
arrow_refresher.cancel();
arrow_refresher = null;
}
}
return;
}
arrow_redraw_pending = true;
canvas.redraw();
});
});
}
Point panelSize = canvas.getSize();
boolean clearImage = img == null || img.isDisposed() || img.getBounds().width != bounds.width || img.getBounds().height != bounds.height;
if (clearImage) {
if (img != null && !img.isDisposed()) {
img.dispose();
}
// System.out.println("clear " + img);
img = new Image(canvas.getDisplay(), bounds.width, bounds.height);
}
GC gc = new GC(img);
Color canvasBG = Utils.isDarkAppearanceNative() ? canvas.getBackground() : Colors.white;
try {
int pw = panelSize.x;
int ph = panelSize.y;
int num_dms = dm_data.length;
if (num_dms == 0 || pw == 0 || ph == 0) {
gc.setBackground(canvasBG);
gc.fillRectangle(bounds);
return;
}
int h_cells;
int v_cells;
if (ph <= pw) {
v_cells = 1;
h_cells = pw / ph;
double f = Math.sqrt(((double) num_dms) / (v_cells * h_cells));
int factor = (int) Math.ceil(f);
h_cells *= factor;
v_cells = factor;
} else {
v_cells = ph / pw;
h_cells = 1;
double f = Math.sqrt(((double) num_dms) / (v_cells * h_cells));
int factor = (int) Math.ceil(f);
v_cells *= factor;
h_cells = factor;
}
ph = h_cells == 1 ? (ph / num_dms) : (ph / v_cells);
pw = v_cells == 1 ? (pw / num_dms) : (pw / h_cells);
// System.out.println( h_cells + "*" + v_cells + ": " + pw + "*" + ph );
Point mySize = new Point(pw, ph);
mySizeCache = mySize;
int num = 0;
Point lastOffset = null;
for (ManagerData data : dm_data) {
DownloadManager manager = data.manager;
PEPeer[] sortedPeers;
try {
data.peers_mon.enter();
List<PEPeerTransport> connectedPeers = new ArrayList<>();
for (PEPeer peer : data.peers) {
if (peer_filter.acceptPeer(peer)) {
if (peer instanceof PEPeerTransport) {
PEPeerTransport peerTransport = (PEPeerTransport) peer;
if (peerTransport.getConnectionState() == PEPeerTransport.CONNECTION_FULLY_ESTABLISHED)
connectedPeers.add(peerTransport);
}
}
}
sortedPeers = connectedPeers.toArray(new PEPeer[connectedPeers.size()]);
} finally {
data.peers_mon.exit();
}
if (sortedPeers == null)
return;
for (int i = 0; i < 3; i++) {
try {
Arrays.sort(sortedPeers, peerComparator);
break;
} catch (IllegalArgumentException e) {
// can happen as peer data can change during sort and result in 'comparison method violates its general contract' error
}
}
int h = num % h_cells;
int v = num / h_cells;
Point myOffset = new Point(h * pw, v * ph);
manager.setUserData(DM_DATA_CACHE_KEY, new Object[] { myOffset, sortedPeers });
render(manager, data, gc, sortedPeers, mySize, myOffset);
num++;
lastOffset = myOffset;
}
int rem_x = panelSize.x - (lastOffset.x + mySize.x);
if (rem_x > 0) {
gc.setBackground(canvasBG);
gc.fillRectangle(lastOffset.x + mySize.x, lastOffset.y, rem_x, mySize.y);
}
int rem_y = panelSize.y - (lastOffset.y + mySize.y);
if (rem_y > 0) {
gc.setBackground(canvasBG);
gc.fillRectangle(0, lastOffset.y + mySize.y, panelSize.x, rem_y);
}
} finally {
gc.dispose();
full_redraw_pending = true;
canvas.redraw();
}
}
}
use of com.biglybt.core.peer.impl.PEPeerTransport in project BiglyBT by BiglySoftware.
the class ClientStatsView method peerRemoved.
@Override
public void peerRemoved(PEPeer peer) {
synchronized (mapData) {
ClientStatsDataSource stat = mapData.get(getID(peer));
if (stat != null) {
stat.current--;
String network = null;
if (peer instanceof PEPeerTransport) {
PeerItem identity = ((PEPeerTransport) peer).getPeerItemIdentity();
if (identity != null) {
network = identity.getNetwork();
}
}
stat.bytesReceived += peer.getStats().getTotalDataBytesReceived();
stat.bytesSent += peer.getStats().getTotalDataBytesSent();
stat.bytesDiscarded += peer.getStats().getTotalBytesDiscarded();
if (network != null) {
Map<String, Object> map = stat.perNetworkStats.get(network);
if (map == null) {
map = new HashMap<>();
stat.perNetworkStats.put(network, map);
}
long bytesReceived = MapUtils.getMapLong(map, "bytesReceived", 0);
map.put("bytesReceived", bytesReceived + peer.getStats().getTotalDataBytesReceived());
long bytesSent = MapUtils.getMapLong(map, "bytesSent", 0);
map.put("bytesSent", bytesSent + peer.getStats().getTotalDataBytesSent());
long bytesDiscarded = MapUtils.getMapLong(map, "bytesDiscarded", 0);
map.put("bytesDiscarded", bytesDiscarded + peer.getStats().getTotalBytesDiscarded());
}
if (tv != null) {
TableRowCore row = tv.getRow(stat);
if (row != null) {
row.invalidate();
}
}
}
}
}
Aggregations