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