├── BDecoder.java ├── BEncoder.java ├── BitExt.java ├── Bits.java ├── ClientHttpRequest.java ├── ConListenerInterface.java ├── ConnectionListener.java ├── ConnectionManager.java ├── Constants.java ├── DLRateComparator.java ├── DTListener.java ├── DownloadManager.java ├── DownloadTask.java ├── ExampleCreateTorrent.java ├── ExampleDownloadFiles.java ├── ExamplePublish.java ├── ExampleShareFiles.java ├── IOManager.java ├── IncomingListener.java ├── LogManager.java ├── Message.java ├── MessageReceiver.java ├── MessageSender.java ├── Message_HS.java ├── Message_PP.java ├── OutgoingListener.java ├── Peer.java ├── PeerProtocol.java ├── PeerUpdateListener.java ├── PeerUpdater.java ├── Piece.java ├── TorrentFile.java ├── TorrentProcessor.java ├── ULRateComparator.java └── Utils.java /BDecoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BeDecoder.java 3 | * 4 | * Created on May 30, 2003, 2:44 PM 5 | * Copyright (C) 2003, 2004, 2005, 2006 Aelitis, All Rights Reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (at your option) any later version. 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | * 19 | * AELITIS, SAS au capital de 46,603.30 euros 20 | * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. 21 | */ 22 | 23 | package jBittorrentAPI; 24 | 25 | import java.io.*; 26 | import java.nio.*; 27 | import java.util.*; 28 | 29 | /** 30 | * A set of utility methods to decode a bencoded array of byte into a Map. 31 | * integer are represented as Long, String as byte[], dictionnaries as Map, and list as List. 32 | * 33 | * @author TdC_VgA 34 | * 35 | */ 36 | public class BDecoder { 37 | 38 | private boolean recovery_mode; 39 | 40 | 41 | public static Map 42 | decode( 43 | byte[] data) 44 | 45 | throws IOException { 46 | return (new BDecoder().decodeByteArray(data)); 47 | } 48 | 49 | public static Map 50 | decode( 51 | BufferedInputStream is) 52 | 53 | throws IOException { 54 | return (new BDecoder().decodeStream(is)); 55 | } 56 | 57 | 58 | public 59 | BDecoder() { 60 | } 61 | 62 | public Map 63 | decodeByteArray( 64 | byte[] data) 65 | 66 | throws IOException { 67 | return (decode(new ByteArrayInputStream(data))); 68 | } 69 | 70 | public Map 71 | decodeStream( 72 | BufferedInputStream data) 73 | 74 | throws IOException { 75 | Object res = decodeInputStream(data, 0); 76 | 77 | if (res == null) { 78 | 79 | throw (new IOException("BDecoder: zero length file")); 80 | 81 | } else if (!(res instanceof Map)) { 82 | 83 | throw (new IOException("BDecoder: top level isn't a Map")); 84 | } 85 | 86 | return ((Map) res); 87 | } 88 | 89 | private Map 90 | decode( 91 | ByteArrayInputStream data) 92 | 93 | throws IOException { 94 | Object res = decodeInputStream(data, 0); 95 | 96 | if (res == null) { 97 | 98 | throw (new IOException("BDecoder: zero length file")); 99 | 100 | } else if (!(res instanceof Map)) { 101 | 102 | throw (new IOException("BDecoder: top level isn't a Map")); 103 | } 104 | 105 | return ((Map) res); 106 | } 107 | 108 | private Object 109 | decodeInputStream( 110 | InputStream bais, 111 | int nesting) 112 | 113 | throws IOException { 114 | if (nesting == 0 && !bais.markSupported()) { 115 | 116 | throw new IOException("InputStream must support the mark() method"); 117 | } 118 | 119 | //set a mark 120 | bais.mark(Integer.MAX_VALUE); 121 | 122 | //read a byte 123 | int tempByte = bais.read(); 124 | 125 | //decide what to do 126 | switch (tempByte) { 127 | case 'd': 128 | 129 | //create a new dictionary object 130 | Map tempMap = new HashMap(); 131 | 132 | try { 133 | //get the key 134 | byte[] tempByteArray = null; 135 | 136 | while ((tempByteArray = (byte[]) decodeInputStream(bais, 137 | nesting + 1)) != null) { 138 | 139 | //decode some more 140 | 141 | Object value = decodeInputStream(bais, nesting + 1); 142 | 143 | //add the value to the map 144 | 145 | CharBuffer cb = Constants.BYTE_CHARSET.decode(ByteBuffer. 146 | wrap(tempByteArray)); 147 | 148 | String key = new String(cb.array(), 0, cb.limit()); 149 | 150 | tempMap.put(key, value); 151 | } 152 | 153 | bais.mark(Integer.MAX_VALUE); 154 | tempByte = bais.read(); 155 | bais.reset(); 156 | if (nesting > 0 && tempByte == -1) { 157 | 158 | throw (new IOException( 159 | "BDecoder: invalid input data, 'e' missing from end of dictionary")); 160 | } 161 | } catch (Throwable e) { 162 | 163 | if (!recovery_mode) { 164 | 165 | if (e instanceof IOException) { 166 | 167 | throw ((IOException) e); 168 | } 169 | 170 | throw (new IOException(e.toString())); 171 | } 172 | } 173 | 174 | //return the map 175 | return tempMap; 176 | 177 | case 'l': 178 | 179 | //create the list 180 | List tempList = new ArrayList(); 181 | 182 | try { 183 | //create the key 184 | Object tempElement = null; 185 | while ((tempElement = decodeInputStream(bais, nesting + 1)) != null) { 186 | //add the element 187 | tempList.add(tempElement); 188 | } 189 | 190 | bais.mark(Integer.MAX_VALUE); 191 | tempByte = bais.read(); 192 | bais.reset(); 193 | if (nesting > 0 && tempByte == -1) { 194 | 195 | throw (new IOException( 196 | "BDecoder: invalid input data, 'e' missing from end of list")); 197 | } 198 | } catch (Throwable e) { 199 | 200 | if (!recovery_mode) { 201 | 202 | if (e instanceof IOException) { 203 | 204 | throw ((IOException) e); 205 | } 206 | 207 | throw (new IOException(e.toString())); 208 | } 209 | } 210 | 211 | //return the list 212 | return tempList; 213 | 214 | case 'e': 215 | case -1: 216 | return null; 217 | 218 | case 'i': 219 | return new Long(getNumberFromStream(bais, 'e')); 220 | 221 | case '0': 222 | case '1': 223 | case '2': 224 | case '3': 225 | case '4': 226 | case '5': 227 | case '6': 228 | case '7': 229 | case '8': 230 | case '9': 231 | 232 | //move back one 233 | bais.reset(); 234 | 235 | //get the string 236 | return getByteArrayFromStream(bais); 237 | 238 | default: { 239 | 240 | int rem_len = bais.available(); 241 | 242 | if (rem_len > 256) { 243 | 244 | rem_len = 256; 245 | } 246 | 247 | byte[] rem_data = new byte[rem_len]; 248 | 249 | bais.read(rem_data); 250 | 251 | throw (new IOException( 252 | "BDecoder: unknown command '" + tempByte + ", remainder = " + 253 | new String(rem_data))); 254 | } 255 | } 256 | } 257 | 258 | private long getNumberFromStream(InputStream bais, char parseChar) throws 259 | IOException { 260 | StringBuffer sb = new StringBuffer(3); 261 | 262 | int tempByte = bais.read(); 263 | while ((tempByte != parseChar) && (tempByte >= 0)) { 264 | sb.append((char) tempByte); 265 | tempByte = bais.read(); 266 | } 267 | 268 | //are we at the end of the stream? 269 | if (tempByte < 0) { 270 | return -1; 271 | } 272 | 273 | return Long.parseLong(sb.toString()); 274 | } 275 | 276 | // This one causes lots of "Query Information" calls to the filesystem 277 | private long getNumberFromStreamOld(InputStream bais, char parseChar) throws 278 | IOException { 279 | int length = 0; 280 | 281 | //place a mark 282 | bais.mark(Integer.MAX_VALUE); 283 | 284 | int tempByte = bais.read(); 285 | while ((tempByte != parseChar) && (tempByte >= 0)) { 286 | tempByte = bais.read(); 287 | length++; 288 | } 289 | 290 | //are we at the end of the stream? 291 | if (tempByte < 0) { 292 | return -1; 293 | } 294 | 295 | //reset the mark 296 | bais.reset(); 297 | 298 | //get the length 299 | byte[] tempArray = new byte[length]; 300 | int count = 0; 301 | int len = 0; 302 | 303 | //get the string 304 | while (count != length && 305 | (len = bais.read(tempArray, count, length - count)) > 0) { 306 | count += len; 307 | } 308 | 309 | //jump ahead in the stream to compensate for the : 310 | bais.skip(1); 311 | 312 | //return the value 313 | 314 | CharBuffer cb = Constants.DEFAULT_CHARSET.decode(ByteBuffer.wrap( 315 | tempArray)); 316 | 317 | String str_value = new String(cb.array(), 0, cb.limit()); 318 | 319 | return Long.parseLong(str_value); 320 | } 321 | 322 | private byte[] getByteArrayFromStream(InputStream bais) throws IOException { 323 | int length = (int) getNumberFromStream(bais, ':'); 324 | 325 | if (length < 0) { 326 | return null; 327 | } 328 | 329 | // note that torrent hashes can be big (consider a 55GB file with 2MB pieces 330 | // this generates a pieces hash of 1/2 meg 331 | 332 | if (length > 8 * 1024 * 1024) { 333 | 334 | throw (new IOException("Byte array length too large (" + length + 335 | ")")); 336 | } 337 | 338 | byte[] tempArray = new byte[length]; 339 | int count = 0; 340 | int len = 0; 341 | //get the string 342 | while (count != length && 343 | (len = bais.read(tempArray, count, length - count)) > 0) { 344 | count += len; 345 | } 346 | 347 | if (count != tempArray.length) { 348 | throw (new IOException( 349 | "BDecoder::getByteArrayFromStream: truncated")); 350 | } 351 | 352 | return tempArray; 353 | } 354 | 355 | public void 356 | setRecoveryMode( 357 | boolean r) { 358 | recovery_mode = r; 359 | } 360 | 361 | private void 362 | print( 363 | PrintWriter writer, 364 | Object obj) { 365 | print(writer, obj, "", false); 366 | } 367 | 368 | private void 369 | print( 370 | PrintWriter writer, 371 | Object obj, 372 | String indent, 373 | boolean skip_indent) { 374 | String use_indent = skip_indent ? "" : indent; 375 | 376 | if (obj instanceof Long) { 377 | 378 | writer.println(use_indent + obj); 379 | 380 | } else if (obj instanceof byte[]) { 381 | 382 | byte[] b = (byte[]) obj; 383 | 384 | if (b.length == 20) { 385 | writer.println(use_indent + " { " + b + " }"); 386 | } else if (b.length < 64) { 387 | writer.println(new String(b)); 388 | } else { 389 | writer.println("[byte array length " + b.length); 390 | } 391 | 392 | } else if (obj instanceof String) { 393 | 394 | writer.println(use_indent + obj); 395 | 396 | } else if (obj instanceof List) { 397 | 398 | List l = (List) obj; 399 | 400 | writer.println(use_indent + "["); 401 | 402 | for (int i = 0; i < l.size(); i++) { 403 | 404 | writer.print(indent + " (" + i + ") "); 405 | 406 | print(writer, l.get(i), indent + " ", true); 407 | } 408 | 409 | writer.println(indent + "]"); 410 | 411 | } else { 412 | 413 | Map m = (Map) obj; 414 | 415 | Iterator it = m.keySet().iterator(); 416 | 417 | while (it.hasNext()) { 418 | 419 | String key = (String) it.next(); 420 | 421 | if (key.length() > 256) { 422 | writer.print(indent + key.substring(0, 256) + "... = "); 423 | } else { 424 | writer.print(indent + key + " = "); 425 | } 426 | 427 | print(writer, m.get(key), indent + " ", true); 428 | } 429 | } 430 | } 431 | 432 | private static void 433 | print( 434 | File f, 435 | File output) { 436 | try { 437 | BDecoder decoder = new BDecoder(); 438 | 439 | decoder.setRecoveryMode(false); 440 | 441 | PrintWriter pw = new PrintWriter(new FileWriter(output)); 442 | 443 | decoder.print(pw, 444 | decoder.decodeStream(new BufferedInputStream(new 445 | FileInputStream(f)))); 446 | 447 | pw.flush(); 448 | 449 | } catch (Throwable e) { 450 | 451 | e.printStackTrace(); 452 | } 453 | } 454 | 455 | public static void 456 | main( 457 | String[] args) { 458 | print(new File( 459 | "C:/Temp/8565658FA6C187A602A5360A69F11933624DD9B5.dat.bak"), 460 | new File("C:/Temp/bdecoder.log")); 461 | } 462 | } 463 | -------------------------------------------------------------------------------- /BEncoder.java: -------------------------------------------------------------------------------- 1 | /* 2 | * BEncoder.java 3 | * 4 | * Created on June 4, 2003, 10:17 PM 5 | * Copyright (C) 2003, 2004, 2005, 2006 Aelitis, All Rights Reserved. 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License 9 | * as published by the Free Software Foundation; either version 2 10 | * of the License, or (at your option) any later version. 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program; if not, write to the Free Software 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 | * 19 | * AELITIS, SAS au capital de 46,603.30 euros 20 | * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France. 21 | */ 22 | 23 | package jBittorrentAPI; 24 | 25 | import java.io.*; 26 | import java.nio.*; 27 | import java.util.*; 28 | 29 | /** 30 | * A set of utility methods to encode a Map into a bencoded array of byte. 31 | * integer are represented as Long, String as byte[], dictionnaries as Map, and list as List. 32 | * 33 | * @author TdC_VgA 34 | */ 35 | public class 36 | BEncoder { 37 | public static byte[] encode(Map object) throws IOException { 38 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 39 | new BEncoder().encode(baos, object); 40 | return baos.toByteArray(); 41 | } 42 | 43 | private void 44 | encode( 45 | ByteArrayOutputStream baos, 46 | Object object) 47 | 48 | throws IOException { 49 | 50 | if (object instanceof String || object instanceof Float) { 51 | 52 | String tempString = (object instanceof String) ? (String) object : 53 | String.valueOf((Float) object); 54 | 55 | ByteBuffer bb = Constants.DEFAULT_CHARSET.encode(tempString); 56 | 57 | write(baos, 58 | Constants.DEFAULT_CHARSET.encode(String.valueOf(bb.limit()))); 59 | 60 | baos.write(':'); 61 | 62 | write(baos, bb); 63 | 64 | } else if (object instanceof Map) { 65 | 66 | Map tempMap = (Map) object; 67 | 68 | SortedMap tempTree = null; 69 | 70 | // unfortunately there are some occasions where we want to ensure that 71 | // the 'key' of the map is not mangled by assuming its UTF-8 encodable. 72 | // In particular the response from a tracker scrape request uses the 73 | // torrent hash as the KEY. Hence the introduction of the type below 74 | // to allow the constructor of the Map to indicate that the keys should 75 | // be extracted using a BYTE_ENCODING 76 | 77 | boolean byte_keys = false; //object instanceof ByteEncodedKeyHashMap; 78 | 79 | //write the d 80 | baos.write('d'); 81 | 82 | //are we sorted? 83 | if (tempMap instanceof TreeMap) { 84 | 85 | tempTree = (TreeMap) tempMap; 86 | 87 | } else { 88 | 89 | //do map sorting here 90 | 91 | tempTree = new TreeMap(tempMap); 92 | } 93 | 94 | Iterator it = tempTree.entrySet().iterator(); 95 | 96 | while (it.hasNext()) { 97 | 98 | Map.Entry entry = (Map.Entry) it.next(); 99 | 100 | Object o_key = entry.getKey(); 101 | 102 | Object value = entry.getValue(); 103 | 104 | if (value != null) { 105 | 106 | if (o_key instanceof byte[]) { 107 | 108 | encode(baos, (byte[]) o_key); 109 | 110 | encode(baos, value); 111 | 112 | } else { 113 | 114 | String key = (String) o_key; 115 | 116 | if (byte_keys) { 117 | 118 | try { 119 | 120 | encode(baos, Constants.BYTE_CHARSET.encode(key)); 121 | 122 | encode(baos, tempMap.get(key)); 123 | 124 | } catch (UnsupportedEncodingException e) { 125 | 126 | throw (new IOException( 127 | "BEncoder: unsupport encoding: " + 128 | e.getMessage())); 129 | } 130 | 131 | } else { 132 | 133 | encode(baos, key); // Key goes in as UTF-8 134 | 135 | encode(baos, value); 136 | } 137 | } 138 | } 139 | } 140 | 141 | baos.write('e'); 142 | 143 | } else if (object instanceof List) { 144 | 145 | List tempList = (List) object; 146 | 147 | //write out the l 148 | 149 | baos.write('l'); 150 | 151 | for (int i = 0; i < tempList.size(); i++) { 152 | 153 | encode(baos, tempList.get(i)); 154 | } 155 | 156 | baos.write('e'); 157 | 158 | } else if (object instanceof Long) { 159 | 160 | Long tempLong = (Long) object; 161 | //write out the l 162 | baos.write('i'); 163 | write(baos, Constants.DEFAULT_CHARSET.encode(tempLong.toString())); 164 | baos.write('e'); 165 | } else if (object instanceof Integer) { 166 | 167 | Integer tempInteger = (Integer) object; 168 | //write out the l 169 | baos.write('i'); 170 | write(baos, Constants.DEFAULT_CHARSET.encode(tempInteger.toString())); 171 | baos.write('e'); 172 | 173 | } else if (object instanceof byte[]) { 174 | 175 | byte[] tempByteArray = (byte[]) object; 176 | write(baos, 177 | Constants.DEFAULT_CHARSET.encode(String.valueOf(tempByteArray. 178 | length))); 179 | baos.write(':'); 180 | baos.write(tempByteArray); 181 | 182 | } else if (object instanceof ByteBuffer) { 183 | 184 | ByteBuffer bb = (ByteBuffer) object; 185 | write(baos, 186 | Constants.DEFAULT_CHARSET.encode(String.valueOf(bb.limit()))); 187 | baos.write(':'); 188 | write(baos, bb); 189 | } 190 | } 191 | 192 | protected void 193 | write( 194 | OutputStream os, 195 | ByteBuffer bb) 196 | 197 | throws IOException { 198 | os.write(bb.array(), 0, bb.limit()); 199 | } 200 | 201 | private static boolean 202 | objectsAreIdentical( 203 | Object o1, 204 | Object o2) { 205 | if (o1 == null && o2 == null) { 206 | 207 | return (true); 208 | 209 | } else if (o1 == null || o2 == null) { 210 | 211 | return (false); 212 | } 213 | 214 | if (o1 instanceof Integer) { 215 | o1 = new Long(((Integer) o1).longValue()); 216 | } 217 | if (o2 instanceof Integer) { 218 | o2 = new Long(((Integer) o2).longValue()); 219 | } 220 | 221 | if (o1 instanceof Float) { 222 | o1 = String.valueOf((Float) o1); 223 | } 224 | if (o2 instanceof Float) { 225 | o2 = String.valueOf((Float) o2); 226 | } 227 | 228 | if (o1.getClass() != o2.getClass()) { 229 | 230 | return (false); 231 | } 232 | 233 | if (o1 instanceof Long) { 234 | 235 | return (o1.equals(o2)); 236 | 237 | } else if (o1 instanceof byte[]) { 238 | 239 | return (Arrays.equals((byte[]) o1, (byte[]) o2)); 240 | 241 | } else if (o1 instanceof ByteBuffer) { 242 | 243 | return (o1.equals(o2)); 244 | 245 | } else if (o1 instanceof String) { 246 | 247 | return (o1.equals(o2)); 248 | 249 | } else if (o1 instanceof List) { 250 | 251 | return (listsAreIdentical((List) o1, (List) o2)); 252 | 253 | } else if (o1 instanceof Map) { 254 | 255 | return (mapsAreIdentical((Map) o1, (Map) o2)); 256 | 257 | } else { 258 | 259 | System.err.println("Invalid type: " + o1); 260 | return (false); 261 | } 262 | } 263 | 264 | public static boolean 265 | listsAreIdentical( 266 | List list1, 267 | List list2) { 268 | if (list1 == null && list2 == null) { 269 | 270 | return (true); 271 | 272 | } else if (list1 == null || list2 == null) { 273 | 274 | return (false); 275 | } 276 | 277 | if (list1.size() != list2.size()) { 278 | 279 | return (false); 280 | } 281 | 282 | for (int i = 0; i < list1.size(); i++) { 283 | 284 | if (!objectsAreIdentical(list1.get(i), list2.get(i))) { 285 | 286 | return (false); 287 | } 288 | } 289 | 290 | return (true); 291 | } 292 | 293 | public static boolean 294 | mapsAreIdentical( 295 | Map map1, 296 | Map map2) { 297 | if (map1 == null && map2 == null) { 298 | 299 | return (true); 300 | 301 | } else if (map1 == null || map2 == null) { 302 | 303 | return (false); 304 | } 305 | 306 | if (map1.size() != map2.size()) { 307 | 308 | return (false); 309 | } 310 | 311 | Iterator it = map1.keySet().iterator(); 312 | 313 | while (it.hasNext()) { 314 | 315 | Object key = it.next(); 316 | 317 | Object v1 = map1.get(key); 318 | Object v2 = map2.get(key); 319 | 320 | if (!objectsAreIdentical(v1, v2)) { 321 | 322 | return (false); 323 | } 324 | } 325 | 326 | return (true); 327 | } 328 | } 329 | -------------------------------------------------------------------------------- /BitExt.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | import java.util.ArrayList; 42 | 43 | /** 44 | * 45 | */ 46 | public class BitExt { 47 | 48 | /** 49 | * @param args No arguments should be provided 50 | */ 51 | public static void main(String[] args) { 52 | 53 | // Client id: 54 | byte[] myID = Utils.generateID(); 55 | System.out.println("--------------------------------"); 56 | System.out.println("| Extending BitTorrent Project |"); 57 | System.out.println("--------------------------------\r\n"); 58 | System.out.println("Client ID = " + new String(myID) + "\r\n\r\n"); 59 | 60 | IOManager iom = new IOManager(); 61 | String userInput = ""; 62 | 63 | if (iom.readUserInput( 64 | "What you want to do?\r\n\t1) Publish file\r\n\t2) Retrieve file\r\nYour choice : "). 65 | matches("1")) { 66 | 67 | System.out.println("Publishing new files...\r\n"); 68 | 69 | //Publisher p = new Publisher(); 70 | TorrentProcessor tp = new TorrentProcessor(); 71 | ArrayList files = new ArrayList(); 72 | System.out.println( 73 | "Enter the path of files you want to publish, no entry means you're done..."); 74 | do { 75 | userInput = iom.readUserInput("File to publish: "); 76 | if (userInput.matches("")) 77 | break; 78 | else 79 | files.add(userInput); 80 | } while (true); 81 | try { 82 | if (files.size() > 1) 83 | tp.setTorrentData(iom.readUserInput( 84 | "Enter tracker announce url: "), 85 | Integer.parseInt(iom.readUserInput( 86 | "Enter piece length: ")), 87 | iom.readUserInput( 88 | "Enter comment for your torrent: "), 89 | "UTF8", 90 | iom.readUserInput( 91 | "Enter the name of the directory your files will be saved in: "), 92 | files); 93 | else if (files.size() == 1) 94 | tp.setTorrentData(iom.readUserInput( 95 | "Enter tracker announce url: "), 96 | Integer.parseInt(iom.readUserInput( 97 | "Enter piece length: ")), 98 | iom.readUserInput( 99 | "Enter comment for your torrent: "), 100 | "UTF8", 101 | (String) files.get(0)); 102 | 103 | tp.generatePieceHashes(); 104 | IOManager.save(tp.generateTorrent(), 105 | (userInput=iom.readUserInput("Save torrent as: "))); 106 | // ConnectionManager.publish(userInput, "localhost", "", "", "test.torrent", "noInfo", "MyComment", "7"); 107 | } catch (Exception e) { 108 | e.printStackTrace(); 109 | } 110 | 111 | } else { 112 | System.out.println("Retrieving files...\r\n"); 113 | boolean defParam = true; 114 | String host = "torrents.thepiratebay.org"; 115 | int port = 80; 116 | String filename = 117 | "/hashtorrent/3572543.torrent/333.3572543.TPB.torrent"; 118 | String rename = "torrent/naruto333.torrent"; 119 | 120 | boolean detailedTorrentInfo = false; 121 | 122 | if ((userInput = iom.readUserInput( 123 | "Do you want to download a torrent or " + 124 | "use an existing one?\r\n1. Download\r\n2. Use existing\r\nYour choice: ")). 125 | matches("1")) { 126 | 127 | if (!(userInput = iom.readUserInput( 128 | "\r\nWhich file would you like to download?\r\n\t1. Naruto 333" + 129 | "\r\n\t2. Naruto 334\r\n\t3. FF7\r\n\t4. Picture 226\r\n\t" + 130 | "5. Define parameters\r\nYour choice : ")).matches("") && 131 | !userInput.matches("1")) { 132 | if (userInput.matches("2")) { 133 | filename = 134 | "/hashtorrent/3575116.torrent/Naruto_chapter334.3575116.TPB.torrent"; 135 | rename = "torrent/naruto334.torrent"; 136 | } else if (userInput.matches("3")) { 137 | host = "dl.torrentreactor.net"; 138 | filename = "/download.php?id=627079&name=Final%20Fantasy%20VII%20Advent%20Children%20(DUBBED)(ws)(DVDRIP)[TV-M]"; 139 | rename = "torrent/FF7_Dubbed.torrent"; 140 | } else if (userInput.matches("4")) { 141 | filename = 142 | "/hashtorrent/3574174.torrent/Picture_226.jpg.3574174.TPB.torrent"; 143 | rename = "torrent/Picture_226.torrent"; 144 | } else 145 | defParam = false; 146 | } 147 | if (!defParam) { 148 | if (!(userInput = iom.readUserInput( 149 | "Please enter host name [default = dl.torrentreactor.net] : ")). 150 | matches("")) 151 | host = userInput; 152 | if (!(userInput = iom.readUserInput( 153 | "Please enter host port [default = 80] :")).matches( 154 | "")) 155 | port = new Integer(userInput).intValue(); 156 | if (!(userInput = iom.readUserInput( 157 | "Please enter path of the " + 158 | "file to download [default = /download.php?" + 159 | "id=627079&name=Final%20Fantasy%20VII%20Advent%20Children%20(DUBBED)(ws)(DVDRIP)[TV-M]] :")). 160 | matches("")) 161 | filename = userInput; 162 | if (!(userInput = iom.readUserInput( 163 | "Save this file as [default = FF7_Dubbed.torrent] :")). 164 | matches("")) 165 | rename = userInput; 166 | 167 | if (!(userInput = iom.readUserInput( 168 | "Detailed torrent info? Yes/No [default = No]")). 169 | matches("")) { 170 | if (userInput.equalsIgnoreCase("yes") || 171 | userInput.equalsIgnoreCase("y")) 172 | detailedTorrentInfo = true; 173 | } 174 | 175 | } 176 | 177 | // Download torrent file according to given information 178 | ConnectionManager.downloadFile(host, port, filename, rename); 179 | } else { 180 | rename = iom.readUserInput("Enter path to torrent: "); 181 | } 182 | 183 | // Process the torrent file to extract features 184 | try { 185 | TorrentProcessor tp = new TorrentProcessor(); 186 | TorrentFile t = tp.getTorrentFile(tp.parseTorrent(rename)); 187 | System.out.println("Torrent parsed..."); 188 | if (t != null) { 189 | DownloadManager dm = new DownloadManager(t, myID); 190 | System.out.println("DM initiated..."); 191 | dm.startListening(6881, 6889); 192 | System.out.println("Listening started..."); 193 | dm.startTrackerUpdate(); 194 | System.out.println("Updater started..."); 195 | dm.blockUntilCompletion(); 196 | dm.stopTrackerUpdate(); 197 | dm.closeTempFiles(); 198 | } else { 199 | System.err.println( 200 | "Provided file is not a valid torrent file"); 201 | System.err.flush(); 202 | System.exit(1); 203 | } 204 | } catch (Exception e) { 205 | 206 | System.out.println("Error while processing torrent file"); 207 | e.printStackTrace(); 208 | System.exit(2); 209 | } 210 | 211 | } 212 | } 213 | } 214 | 215 | 216 | 217 | 218 | 219 | 220 | -------------------------------------------------------------------------------- /Bits.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | import java.util.BitSet; 40 | 41 | public class Bits { 42 | private boolean[] bits; 43 | 44 | public Bits(int length){ 45 | this.bits = new boolean[length]; 46 | } 47 | public Bits(byte[] b) { 48 | this.bits = Utils.byteArray2BitArray(b); 49 | } 50 | public Bits(){} 51 | 52 | public Bits and(Bits b){ 53 | if(this.length() != b.length()){ 54 | System.err.println("Error during and operation: bits length doesn't match"); 55 | return null; 56 | } 57 | Bits temp = new Bits(this.length()); 58 | for(int i = 0; i < this.length(); i++) 59 | temp.set(i, this.get(i) && b.get(i)); 60 | return temp; 61 | } 62 | 63 | public Bits or(Bits b){ 64 | if(this.length() != b.length()){ 65 | System.err.println("Error during and operation: bits length doesn't match"); 66 | return null; 67 | } 68 | Bits temp = new Bits(this.length()); 69 | for(int i = 0; i < this.length(); i++) 70 | temp.set(i, this.get(i) || b.get(i)); 71 | return temp; 72 | } 73 | 74 | 75 | 76 | 77 | public void setBits(boolean[] b){ 78 | this.bits = b; 79 | } 80 | 81 | public int length(){ 82 | return this.bits.length; 83 | } 84 | 85 | public boolean[] getBits(){ 86 | return this.bits; 87 | } 88 | 89 | public boolean get(int i){ 90 | return this.bits[i]; 91 | } 92 | public void set(int i){ 93 | this.bits[i] = true; 94 | } 95 | public void set(int i, boolean val){ 96 | this.bits[i] = val; 97 | } 98 | 99 | public String toString(){ 100 | String toString = ""; 101 | for(int i = 0; i < this.bits.length; i++) 102 | toString += this.bits[i] ? 1:0; 103 | return toString; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /ConListenerInterface.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.EventListener; 41 | import java.net.Socket; 42 | 43 | public interface ConListenerInterface extends EventListener{ 44 | /** 45 | * Method called when a new connection is accepted and bound to the given socket 46 | * @param s Socket 47 | */ 48 | public void connectionAccepted(Socket s); 49 | } 50 | -------------------------------------------------------------------------------- /ConnectionListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.IOException; 41 | import java.net.ServerSocket; 42 | import java.net.Socket; 43 | import javax.swing.event.EventListenerList; 44 | 45 | /** 46 | * Thread that can listen for remote peers connection tries to this client 47 | * 48 | * @author Baptiste Dubuis 49 | * @version 0.1 50 | */ 51 | public class ConnectionListener extends Thread { 52 | private ServerSocket ss = null; 53 | private int minPort = -1; 54 | private int maxPort = -1; 55 | private int connectedPort = -1; 56 | private final EventListenerList listeners = new EventListenerList(); 57 | private boolean acceptConnection = true; 58 | 59 | public ConnectionListener() {} 60 | public ConnectionListener(int minPort, int maxPort){ 61 | this.minPort = minPort; 62 | this.maxPort = maxPort; 63 | } 64 | 65 | /** 66 | * Returns the port this client is listening on 67 | * @return int 68 | */ 69 | public int getConnectedPort(){ 70 | return this.connectedPort; 71 | } 72 | 73 | /** 74 | * Returns the minimal port number this client will try to listen on 75 | * @return int 76 | */ 77 | public int getMinPort(){ 78 | return this.minPort; 79 | } 80 | 81 | /** 82 | * Returns the maximal port number this client will try to listen on 83 | * @return int 84 | */ 85 | public int getMaxPort(){ 86 | return this.maxPort; 87 | } 88 | 89 | /** 90 | * Sets the minimal port number this client will try to listen on 91 | * @param minPort int 92 | */ 93 | public void setMinPort(int minPort){ 94 | this.minPort = minPort; 95 | } 96 | 97 | /** 98 | * Sets the minimal port number this client will try to listen on 99 | * @param maxPort int 100 | */ 101 | public void setMaxPort(int maxPort){ 102 | this.maxPort = maxPort; 103 | } 104 | 105 | /** 106 | * Try to create a server socket for remote peers to connect on within the 107 | * specified port range 108 | * @param minPort The minimal port number this client should listen on 109 | * @param maxPort The maximal port number this client should listen on 110 | * @return boolean 111 | */ 112 | public boolean connect(int minPort, int maxPort){ 113 | this.minPort = minPort; 114 | this.maxPort = maxPort; 115 | for(int i = minPort; i <= maxPort; i++) 116 | try { 117 | this.ss = new ServerSocket(i); 118 | this.connectedPort = i; 119 | this.setDaemon(true); 120 | this.start(); 121 | return true; 122 | } catch (IOException ioe) {} 123 | return false; 124 | } 125 | 126 | /** 127 | * Try to create a server socket for remote peers to connect on within current 128 | * port range 129 | * @return boolean 130 | */ 131 | public boolean connect(){ 132 | if(this.minPort != -1 && this.maxPort != -1) 133 | return this.connect(this.minPort, this.maxPort); 134 | else 135 | return false; 136 | } 137 | 138 | public void run() { 139 | byte[] b = new byte[0]; 140 | try { 141 | while (true) { 142 | if(this.acceptConnection){ 143 | this.fireConnectionAccepted(ss.accept()); 144 | sleep(1000); 145 | }else{ 146 | synchronized(b){ 147 | System.out.println("No more connection accepted for the moment..."); 148 | b.wait(); 149 | } 150 | } 151 | } 152 | } catch (IOException ioe) { 153 | System.err.println("Error in connection listener: "+ioe.getMessage()); 154 | System.err.flush(); 155 | } catch(InterruptedException ie){ 156 | 157 | } 158 | } 159 | 160 | /** 161 | * Decides if the client should accept or not future connection 162 | * @param accept true if it should accept, false otherwise 163 | */ 164 | public synchronized void setAccept(boolean accept){ 165 | this.acceptConnection = accept; 166 | this.notifyAll(); 167 | } 168 | 169 | 170 | public void addConListenerInterface(ConListenerInterface listener) { 171 | listeners.add(ConListenerInterface.class, listener); 172 | } 173 | 174 | public void removeConListenerInterface(ConListenerInterface listener) { 175 | listeners.remove(ConListenerInterface.class, listener); 176 | } 177 | 178 | public ConListenerInterface[] getConListenerInterfaces() { 179 | return listeners.getListeners(ConListenerInterface.class); 180 | } 181 | 182 | /** 183 | * Method used to send message to all object currently listening on this thread 184 | * when a new connection has been accepted. It provides the socket the connection 185 | * is bound to. 186 | * 187 | * @param s Socket 188 | */ 189 | protected void fireConnectionAccepted(Socket s) { 190 | for (ConListenerInterface listener : getConListenerInterfaces()) { 191 | listener.connectionAccepted(s); 192 | } 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /ConnectionManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.net.*; 41 | import java.io.*; 42 | import java.util.*; 43 | 44 | /** 45 | * Provides methods for interaction with remote host, like downloading or uploading 46 | * files using HTTP protocol. 47 | * @todo Optimize publish method to be able to specify (for example in a xml file) 48 | * the protocol to upload files to a given website 49 | */ 50 | public class ConnectionManager { 51 | 52 | /** 53 | * Download a file from a web site and save it according to the provided path 54 | * @param host Name of the host the torrent is located on 55 | * @param port Port of the host that provides the torrent file 56 | * @param filename Path of the file on the host 57 | * @param renameFile Path where the torrent will be saved 58 | * @return boolean True if the file has been successfully downloaded, false otherwise 59 | */ 60 | public static boolean downloadFile(String host, int port, String filename, 61 | String renameFile) { 62 | try { 63 | URL source = new URL("HTTP", host, port, filename); 64 | //IOManager iom = new IOManager(renameFile); 65 | InputStream is = source.openStream(); 66 | IOManager.saveFromURL(is, renameFile); 67 | is.close(); 68 | return true; 69 | } catch (MalformedURLException murle) { 70 | System.err.println("URL not valid..."); 71 | System.exit(1); 72 | } catch (Exception e) { 73 | System.err.println( 74 | "Unable to download torrent file, host unreachable..."); 75 | e.printStackTrace(); 76 | } 77 | return false; 78 | } 79 | 80 | public static boolean publish(String torrentPath){ 81 | return publish(torrentPath, "", "", "", "", "", "", ""); 82 | } 83 | 84 | public static boolean publish(String torrentPath, String trackerName, 85 | String username, String pwd, String torrentRename, 86 | String info, String comment, String catid) { 87 | URL url; 88 | URLConnection urlConn; 89 | DataOutputStream printout; 90 | DataInputStream input; 91 | int tracker = 1; 92 | if(trackerName.equalsIgnoreCase("")){ 93 | tracker = new Integer(IOManager.readUserInput( 94 | "On which tracker do you want your " + 95 | "torrent to be published?\r\n1. " + 96 | "smartorrent.com\r\n\t2.Localhost\r\nYour choice: ")). 97 | intValue(); 98 | }else if(trackerName.contains("smartorrent")){ 99 | tracker = 1; 100 | }else 101 | tracker = 2; 102 | ClientHttpRequest c = null; 103 | try { 104 | switch (tracker) { 105 | case 2: 106 | c = new ClientHttpRequest( 107 | trackerName); 108 | 109 | c.setParameter("name", torrentRename); 110 | c.setParameter("torrent", new File(torrentPath)); 111 | c.setParameter("info", info); 112 | c.setParameter("comment", comment); 113 | c.post(); 114 | 115 | break; 116 | case 1: 117 | default: 118 | url = new URL("http://www.smartorrent.com/?page=login"); 119 | urlConn = url.openConnection(); 120 | 121 | Map> headers = urlConn.getHeaderFields(); 122 | List values = headers.get("Set-Cookie"); 123 | String cookieValue = null; 124 | for (Iterator iter = values.iterator(); iter.hasNext(); ) { 125 | String v = (((String) iter.next()).split(";"))[0]; 126 | 127 | if (cookieValue == null) 128 | cookieValue = v; 129 | else 130 | cookieValue = cookieValue + ";" + v; 131 | } 132 | url = new URL("http://www.smartorrent.com/?page=login"); 133 | urlConn = url.openConnection(); 134 | urlConn.setDoInput(true); 135 | urlConn.setDoOutput(true); 136 | urlConn.setUseCaches(false); 137 | urlConn.setRequestProperty 138 | ("Content-Type", "application/x-www-form-urlencoded"); 139 | urlConn.setRequestProperty("Referer", 140 | "http://www.smartorrent.com/?page=upload"); 141 | urlConn.setRequestProperty("Cookie", 142 | cookieValue); 143 | printout = new DataOutputStream(urlConn.getOutputStream()); 144 | 145 | String data = URLEncoder.encode("loginreturn", "UTF-8") + "=" + 146 | URLEncoder.encode("/?page=login", "UTF-8"); 147 | data += "&" + URLEncoder.encode("loginusername", "UTF-8") + "=" + 148 | URLEncoder.encode(username, "UTF-8"); 149 | data += "&" + URLEncoder.encode("loginpassword", "UTF-8") + "=" + 150 | URLEncoder.encode(pwd, "UTF-8"); 151 | 152 | printout.writeBytes(data); 153 | printout.flush(); 154 | printout.close(); 155 | 156 | BufferedReader rd = new BufferedReader(new InputStreamReader( 157 | urlConn. 158 | getInputStream())); 159 | while (rd.readLine() != null); 160 | 161 | rd.close(); 162 | 163 | c = new ClientHttpRequest( 164 | "http://www.smartorrent.com/?page=upload"); 165 | String[] cookie = cookieValue.split("="); 166 | c.setCookie(cookie[0], cookie[1]); 167 | c.postCookies(); 168 | 169 | c.setParameter("name", torrentRename); 170 | c.setParameter("torrent", new File(torrentPath)); 171 | c.setParameter("catid", catid); 172 | c.setParameter("info", info); 173 | c.setParameter("comment", comment); 174 | c.setParameter("submit", "Upload"); 175 | c.post(); 176 | return true; 177 | } 178 | } catch (Exception e) { 179 | e.printStackTrace(); 180 | } 181 | 182 | return false; 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /Constants.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.nio.charset.Charset; 41 | import java.util.StringTokenizer; 42 | 43 | /** 44 | * Some useful (or not...) constants used (or not yet...) throughout the program 45 | */ 46 | public class 47 | Constants { 48 | public static final String DEFAULT_ENCODING = "UTF8"; 49 | public static final String BYTE_ENCODING = "ISO-8859-1"; 50 | public static Charset BYTE_CHARSET; 51 | public static Charset DEFAULT_CHARSET; 52 | 53 | static { 54 | try { 55 | 56 | BYTE_CHARSET = Charset.forName(Constants.BYTE_ENCODING); 57 | DEFAULT_CHARSET = Charset.forName(Constants.DEFAULT_ENCODING); 58 | 59 | } catch (Throwable e) { 60 | 61 | e.printStackTrace(); 62 | } 63 | } 64 | 65 | public static final String CLIENT = "jBittorrentAPI 1.0"; 66 | public static String SAVEPATH = "downloads/"; 67 | 68 | public static final String OSName = System.getProperty("os.name"); 69 | 70 | public static final boolean isOSX = OSName.toLowerCase().startsWith( 71 | "mac os"); 72 | public static final boolean isLinux = OSName.equalsIgnoreCase("Linux"); 73 | public static final boolean isSolaris = OSName.equalsIgnoreCase("SunOS"); 74 | public static final boolean isFreeBSD = OSName.equalsIgnoreCase("FreeBSD"); 75 | public static final boolean isWindowsXP = OSName.equalsIgnoreCase( 76 | "Windows XP"); 77 | public static final boolean isWindows95 = OSName.equalsIgnoreCase( 78 | "Windows 95"); 79 | public static final boolean isWindows98 = OSName.equalsIgnoreCase( 80 | "Windows 98"); 81 | public static final boolean isWindowsME = OSName.equalsIgnoreCase( 82 | "Windows ME"); 83 | public static final boolean isWindows9598ME = isWindows95 || isWindows98 || 84 | isWindowsME; 85 | public static final boolean isWindows = OSName.toLowerCase().startsWith( 86 | "windows"); 87 | public static final String JAVA_VERSION = System.getProperty("java.version"); 88 | } 89 | -------------------------------------------------------------------------------- /DLRateComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.*; 41 | 42 | /** 43 | * Compares 2 peers download rate 44 | * 45 | * @author Baptiste Dubuis 46 | * @version 0.1 47 | */ 48 | public class DLRateComparator implements Comparator { 49 | /** 50 | * Compares its two arguments for order. 51 | * 52 | * @param a the first object to be compared. 53 | * @param b the second object to be compared. 54 | * @return a negative integer, zero, or a positive integer as the first 55 | * argument is less than, equal to, or greater than the second. 56 | */ 57 | public int compare(Object a, Object b) { 58 | if (a instanceof Peer && b instanceof Peer) 59 | if (((Peer) a).getDLRate(false) > ((Peer) b).getDLRate(false)) 60 | return -1; 61 | else if (((Peer) a).getDLRate(false) < ((Peer) b).getDLRate(false)) 62 | return 1; 63 | return 0; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /DTListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.EventListener; 41 | import java.util.BitSet; 42 | 43 | /** 44 | * Interface for managing events launched by the DownloadTask class 45 | * 46 | * @author Baptiste Dubuis 47 | * @version 0.1 48 | */ 49 | public interface DTListener extends EventListener{ 50 | public void pieceCompleted(String peerID, int pieceNB, boolean complete); 51 | public void pieceRequested(int pieceNB, boolean requested); 52 | public void taskCompleted(String id, int reason); 53 | public void peerAvailability(String id, BitSet hasPiece); 54 | public void peerReady(String id); 55 | public void peerRequest(String peerID,int piece, int begin, int length); 56 | public void addActiveTask(String id, DownloadTask dt); 57 | } 58 | -------------------------------------------------------------------------------- /ExampleCreateTorrent.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.FileOutputStream; 41 | import java.util.ArrayList; 42 | 43 | /** 44 | * Simple example to show how it is possible to create a new .torrent file to 45 | * share files using bittorrent protocol 46 | */ 47 | class ExampleCreateTorrent{ 48 | public static void main(String[] args){ 49 | if(args.length < 5){ 50 | System.err.println("Wrong parameter number\r\n\r\nUse:\r\n" + 51 | "ExampleCreateTorrent " + 52 | " ... <..> <..> "); 53 | System.exit(0); 54 | } 55 | TorrentProcessor tp = new TorrentProcessor(); 56 | tp.setAnnounceURL(args[1]); 57 | try{ 58 | tp.setPieceLength(Integer.parseInt(args[2])); 59 | }catch(Exception e){ 60 | System.err.println("Piece length must be an integer"); 61 | System.exit(0); 62 | } 63 | int i = 3; 64 | ArrayList files = new ArrayList(); 65 | if(!args[i+1].equalsIgnoreCase("..")){ 66 | tp.setName(args[3]); 67 | i++; 68 | } 69 | while(i < args.length){ 70 | if(args[i].equalsIgnoreCase("..")) 71 | break; 72 | files.add(args[i]); 73 | i++; 74 | } 75 | try{ 76 | tp.addFiles(files); 77 | }catch(Exception e){ 78 | System.err.println( 79 | "Problem when adding files to torrent. Check your data"); 80 | System.exit(0); 81 | } 82 | i++; 83 | String creator = ""; 84 | while(i < args.length){ 85 | if(args[i].equalsIgnoreCase("..")) 86 | break; 87 | creator += args[i]; 88 | i++; 89 | } 90 | tp.setCreator(creator); 91 | i++; 92 | String comment = ""; 93 | while(i < args.length){ 94 | if(args[i].equalsIgnoreCase("..")) 95 | break; 96 | comment += args[i]; 97 | i++; 98 | } 99 | tp.setComment(comment); 100 | try{ 101 | System.out.println("Hashing the files..."); 102 | System.out.flush(); 103 | tp.generatePieceHashes(); 104 | System.out.println("Hash complete... Saving..."); 105 | FileOutputStream fos = new FileOutputStream(args[0]); 106 | fos.write(tp.generateTorrent()); 107 | System.out.println("Torrent created successfully!!!"); 108 | }catch(Exception e){ 109 | System.err.println("Error when writing to the torrent file..."); 110 | System.exit(1); 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /ExampleDownloadFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | /** 41 | * Simple example to show how it is possible to download files using bittorrent 42 | * protocol with a given .torrent file 43 | */ 44 | class ExampleDownloadFiles { 45 | 46 | public ExampleDownloadFiles(String[] args){ 47 | try { 48 | TorrentProcessor tp = new TorrentProcessor(); 49 | 50 | if(args.length < 1){ 51 | System.err.println( 52 | "Incorrect use, please provide the path of the torrent file...\r\n" + 53 | "\r\nCorrect use of ExampleDownloadFiles:\r\n"+ 54 | "ExampleDownloadFiles torrentPath"); 55 | 56 | System.exit(1); 57 | } 58 | TorrentFile t = tp.getTorrentFile(tp.parseTorrent(args[0])); 59 | if(args.length > 1) 60 | Constants.SAVEPATH = args[1]; 61 | if (t != null) { 62 | DownloadManager dm = new DownloadManager(t, Utils.generateID()); 63 | dm.startListening(6881, 6889); 64 | dm.startTrackerUpdate(); 65 | dm.blockUntilCompletion(); 66 | dm.stopTrackerUpdate(); 67 | dm.closeTempFiles(); 68 | } else { 69 | System.err.println( 70 | "Provided file is not a valid torrent file"); 71 | System.err.flush(); 72 | System.exit(1); 73 | } 74 | } catch (Exception e) { 75 | 76 | System.out.println("Error while processing torrent file. Please restart the client"); 77 | //e.printStackTrace(); 78 | System.exit(1); 79 | } 80 | 81 | } 82 | public static void main(String[] args) { 83 | new ExampleDownloadFiles(args); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /ExamplePublish.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.File; 41 | 42 | /** 43 | * Simple example to show how it is possible to publish a .torrent file to a 44 | * tracker 45 | */ 46 | class ExamplePublish{ 47 | public static void main(String[] args){ 48 | if(args.length < 4){ 49 | System.out.println(showHelp()); 50 | System.exit(0); 51 | } 52 | File f = new File(args[0]); 53 | String comment = ""; 54 | for(int i = 4; i < args.length; i++) 55 | comment += args[i]; 56 | try{ 57 | ConnectionManager.publish(args[0], args[1], 58 | args[2], args[3], 59 | f.getName(), "", comment, "7"); 60 | }catch(Exception e){ 61 | System.out.println(showHelp()); 62 | System.exit(0); 63 | } 64 | } 65 | 66 | private static String showHelp() { 67 | return 68 | "ExamplePublish use:\r\n\tExamplePublish " + 69 | "torrentPath trackerUploadURL username password comment\r\n\r\n" + 70 | "If tracker does not need username and password, enter 'none' instead"; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /ExampleShareFiles.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | public class ExampleShareFiles { 41 | public static void main(String[] args){ 42 | new ExampleDownloadFiles(args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /IOManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | 42 | /** 43 | * Utility methods for I/O operations 44 | * 45 | * @author Baptiste Dubuis 46 | * @version 0.1 47 | */ 48 | public class IOManager { 49 | BufferedReader br; 50 | BufferedWriter bw; 51 | //String filename; 52 | static private LogManager lm; 53 | 54 | public IOManager(String filename) { 55 | this.lm = new LogManager("logs/io.log"); 56 | } 57 | 58 | public IOManager() { 59 | this.lm = new LogManager("io.log"); 60 | } 61 | 62 | /** 63 | * Save the byte array into a file with the give filename 64 | * @param data byte[] 65 | * @param filename String 66 | * @return boolean 67 | */ 68 | public static boolean save(byte[] data, String filename) { 69 | try{ 70 | FileOutputStream fos = new FileOutputStream(filename); 71 | fos.write(data, 0, data.length); 72 | fos.flush(); 73 | fos.close(); 74 | return true; 75 | }catch(IOException ioe){} 76 | return false; 77 | } 78 | 79 | /** 80 | * Read all bytes available in the stream 81 | * @param is InputStream 82 | * @return byte[] 83 | */ 84 | public static byte[] readBytesFromStream(InputStream is) { 85 | int c; 86 | String data = ""; 87 | try { 88 | while ((c = is.read()) != -1) 89 | data += (char) c; 90 | } catch (IOException ioe) { 91 | lm.writeLog(ioe.getMessage()); 92 | System.err.println("Problem when reading from stream..."); 93 | ioe.printStackTrace(); 94 | } 95 | return data.getBytes(); 96 | } 97 | 98 | /** 99 | * Read all available bytes from the given file 100 | * @param file File 101 | * @return byte[] 102 | */ 103 | public static byte[] readBytesFromFile(File file) { 104 | long file_size_long = -1; 105 | byte[] file_bytes = null; 106 | InputStream file_stream; 107 | 108 | try { 109 | file_stream = new FileInputStream(file); 110 | 111 | if (!file.exists()) { 112 | System.err.println( 113 | "Error: [TorrentFileHandler.java] The file \"" 114 | + file.getName() 115 | + 116 | "\" does not exist. Please make sure you have the correct path to the file."); 117 | return null; 118 | } 119 | 120 | if (!file.canRead()) { 121 | System.err.println( 122 | "Error: [TorrentFileHandler.java] Cannot read from \"" 123 | + file.getName() 124 | + 125 | "\". Please make sure the file permissions are set correctly."); 126 | return null; 127 | } 128 | 129 | file_size_long = file.length(); 130 | 131 | if (file_size_long > Integer.MAX_VALUE) { 132 | System.err.println( 133 | "Error: [TorrentFileHandler.java] The file \"" + 134 | file.getName() 135 | + "\" is too large to be read by this class."); 136 | return null; 137 | } 138 | file_bytes = new byte[(int) file_size_long]; 139 | int file_offset = 0; 140 | int bytes_read = 0; 141 | 142 | while (file_offset < file_bytes.length 143 | && (bytes_read = file_stream.read(file_bytes, file_offset, 144 | file_bytes.length - 145 | file_offset)) >= 0) { 146 | file_offset += bytes_read; 147 | } 148 | if (file_offset < file_bytes.length) { 149 | throw new IOException("Could not completely read file \"" 150 | + file.getName() + "\"."); 151 | } 152 | 153 | file_stream.close(); 154 | 155 | } catch (FileNotFoundException e) { 156 | System.err 157 | .println("Error: [TorrentFileHandler.java] The file \"" 158 | + file.getName() 159 | + 160 | "\" does not exist. Please make sure you have the correct path to the file."); 161 | return null; 162 | } catch (IOException e) { 163 | System.err 164 | .println("Error: [TorrentFileHandler.java] There was a general, unrecoverable I/O error while reading from \"" 165 | + file.getName() + "\"."); 166 | System.err.println(e.getMessage()); 167 | } 168 | 169 | return file_bytes; 170 | 171 | } 172 | 173 | /** 174 | * Save the bytes in the stream to the file in parameter 175 | * @param is InputStream 176 | * @param filename String 177 | * @throws IOException 178 | */ 179 | public static void saveFromURL(InputStream is, String filename) throws IOException { 180 | FileOutputStream fos = new FileOutputStream(filename); 181 | int c; 182 | boolean noheader = true; 183 | while (true) { 184 | if ((c = is.read()) == -1) 185 | break; 186 | else { 187 | if (noheader) { 188 | fos.write(c); 189 | fos.flush(); 190 | } else { 191 | if (c == '\n' && is.read() == '\r' && is.read() == '\n') 192 | noheader = true; 193 | } 194 | } 195 | } 196 | fos.close(); 197 | } 198 | 199 | /** 200 | * Ask the user for an input 201 | * @param question The question that will be asked to the user 202 | * @return String 203 | */ 204 | public static String readUserInput(String question) { 205 | 206 | System.out.print(question); 207 | // Setup the I/O buffered stream, to read user input from the command line 208 | InputStreamReader isr = new InputStreamReader(System.in); 209 | BufferedReader br = new BufferedReader(isr); 210 | String s = null; 211 | try { 212 | s = br.readLine(); 213 | } catch (IOException ioe) { 214 | System.err.println("An error occured while reading your data"); 215 | return ""; 216 | } 217 | return s; 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /IncomingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.EventListener; 41 | 42 | 43 | public interface IncomingListener extends EventListener{ 44 | /** 45 | * Fired when a new message has been received 46 | * @param m Message 47 | */ 48 | public void messageReceived(Message m); 49 | } 50 | -------------------------------------------------------------------------------- /LogManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | import java.util.*; 42 | 43 | /** 44 | * Utility class to output information to a file 45 | * 46 | * @author Baptiste Dubuis 47 | * @version 0.1 48 | */ 49 | public class LogManager { 50 | private String filename; 51 | private OutputStream os; 52 | public FileWriter fw; 53 | 54 | public LogManager(String logfile) { 55 | this.filename = logfile; 56 | } 57 | 58 | /** 59 | * Write the given string to the file corresponding to this manager 60 | * @param s String 61 | */ 62 | synchronized public void writeLog(String s){ 63 | try{ 64 | this.fw = new FileWriter(this.filename, true); 65 | Date d = new Date(); 66 | 67 | this.fw.write(d+" : "+s+"\r\n"); 68 | this.fw.flush(); 69 | this.fw.close(); 70 | }catch(Exception e){ 71 | System.out.println("Not able to write to log file"); 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /Message.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | /** 41 | * Represent the general structure of a protocol message. It must have a type. 42 | */ 43 | abstract public class Message { 44 | protected int type; 45 | private int priority = 0; 46 | 47 | public Message(){} 48 | 49 | public Message(int type){ 50 | this(type, 0); 51 | } 52 | 53 | public Message(int type, int priority){ 54 | this.type = type; 55 | this.priority = priority; 56 | } 57 | 58 | public int getPriority(){ 59 | return this.priority; 60 | } 61 | 62 | public int getType(){ 63 | return this.type; 64 | } 65 | 66 | abstract public byte[] generate(); 67 | } 68 | -------------------------------------------------------------------------------- /MessageReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | import javax.swing.event.EventListenerList; 42 | 43 | /** 44 | * Thread created to listen for incoming message from remote peers. When data is read, 45 | * message type is determined and a new Message object (either Message_HS or Message_PP) 46 | * is created and passed to the corresponding receiver 47 | */ 48 | public class MessageReceiver extends Thread { 49 | 50 | private boolean run = true; 51 | private InputStream is = null; 52 | private DataInputStream dis = null; 53 | private boolean hsOK = false; 54 | private final EventListenerList listeners = new EventListenerList(); 55 | 56 | /** 57 | * Create a new Message receiver for a given peer 58 | * @param id The id of the peer that has been assigned this receiver 59 | * @param is InputStream 60 | * @throws IOException 61 | */ 62 | public MessageReceiver(String id, InputStream is) throws IOException { 63 | //this.setName("MR_" + id); 64 | this.is = is; 65 | this.dis = new DataInputStream(is); 66 | } 67 | 68 | /** 69 | * Reads bytes from the DataInputStream 70 | * @param data byte[] 71 | * @return int 72 | * 73 | */ 74 | private int read(byte[] data){ 75 | try{ 76 | this.dis.readFully(data); 77 | }catch(IOException ioe){ 78 | return -1; 79 | } 80 | return data.length; 81 | } 82 | 83 | /** 84 | * Reads bytes from theInputStream 85 | * @param data byte[] 86 | * @return int 87 | * @throws IOException 88 | * @throws InterruptedException 89 | * @deprecated 90 | */ 91 | private int read2(byte[] data)throws IOException, InterruptedException{ 92 | int totalread = 0; 93 | int read = 0; 94 | while(totalread != data.length){ 95 | if((read = this.is.read(data, totalread, data.length - totalread)) == -1) 96 | return -1; 97 | totalread += read; 98 | this.sleep(50); 99 | } 100 | return totalread; 101 | } 102 | 103 | /** 104 | * Reads bytes from the input stream. This read method read exactly the number of 105 | * bytes corresponding to the length of the byte array given in parameter 106 | * @param data byte[] 107 | * @return int 108 | * @throws IOException 109 | * @throws InterruptedException 110 | * @throws Exception 111 | * @todo Optimize this method which seems to take too much time... 112 | */ 113 | private int read1(byte[] data) throws IOException, InterruptedException, Exception { 114 | int l = data.length; 115 | byte[] payload = new byte[0]; 116 | int loop = 0; 117 | for (int i = 0; i < l; ) { 118 | loop++; 119 | int available = is.available(); 120 | 121 | if (available < l - i) { 122 | loop++; 123 | byte[] temp = new byte[available]; 124 | if (is.read(temp) == -1){ 125 | return -1; 126 | } 127 | payload = Utils.concat(payload, temp); 128 | i += available; 129 | this.sleep(10); 130 | } else { 131 | byte[] temp = new byte[l - i]; 132 | if (is.read(temp) == -1){ 133 | return -1; 134 | } 135 | payload = Utils.concat(payload, temp); 136 | Utils.copy(payload, data); 137 | return payload.length; 138 | } 139 | } 140 | return -1; 141 | } 142 | 143 | /** 144 | * Reads data from the inputstream, creates new messages according to the 145 | * received data and fires MessageReceived method of the listeners with the 146 | * new message in parameter. Loops as long as the 'run' variable is true 147 | */ 148 | public void run() { 149 | //Message m = null; 150 | int read = 0; 151 | byte[] lengthHS = new byte[1]; 152 | byte[] protocol = new byte[19]; 153 | byte[] reserved = new byte[8]; 154 | byte[] fileID = new byte[20]; 155 | byte[] peerID = new byte[20]; 156 | byte[] length = new byte[4]; 157 | Message_HS hs = new Message_HS(); 158 | Message_PP mess = new Message_PP(); 159 | 160 | while (this.run) { 161 | int l = 1664; 162 | try { 163 | if (!hsOK) { 164 | //System.out.println("Wait for hs"); 165 | 166 | if ((read = this.read(lengthHS)) > 0) { 167 | for (int i = 0; i < 19; i++) 168 | protocol[i] = (byte) is.read(); 169 | for (int i = 0; i < 8; i++) 170 | reserved[i] = (byte) is.read(); 171 | for (int i = 0; i < 20; i++) 172 | fileID[i] = (byte) is.read(); 173 | for (int i = 0; i < 20; i++) 174 | peerID[i] = (byte) is.read(); 175 | 176 | hs.setData(lengthHS, protocol, reserved, 177 | fileID, peerID); 178 | //this.hsOK = true; 179 | } else { 180 | hs = null; 181 | } 182 | } else { 183 | int id; 184 | if ((read = this.read(length)) > 0) { 185 | l = Utils.byteArrayToInt(length); 186 | if (l == 0) { 187 | mess.setData(PeerProtocol.KEEP_ALIVE); 188 | } else { 189 | id = is.read(); 190 | if(id == -1){ 191 | System.err.println("id"); 192 | mess = null; 193 | }else{ 194 | if (l == 1) 195 | mess.setData(id + 1); 196 | else { 197 | l = l - 1; 198 | byte[] payload = new byte[l]; 199 | if (this.read(payload) > 0) 200 | mess.setData(id + 1, payload); 201 | payload = null; 202 | } 203 | } 204 | } 205 | } else { 206 | mess = null; 207 | } 208 | } 209 | } catch (IOException ioe) { 210 | ioe.printStackTrace(); 211 | this.fireMessageReceived(null); 212 | return; 213 | // m = null; 214 | } /*catch (InterruptedException ie) { 215 | this.fireMessageReceived(null); 216 | return; 217 | // m = null; 218 | } */catch (Exception e) { 219 | System.err.println(l+"Error in MessageReceiver..."+e.getMessage() 220 | +" " + e.toString()); 221 | this.fireMessageReceived(null); 222 | return; 223 | // m = null; 224 | } 225 | 226 | if(!this.hsOK){ 227 | this.fireMessageReceived(hs); 228 | this.hsOK = true; 229 | }else{ 230 | this.fireMessageReceived(mess); 231 | } 232 | // m = null; 233 | } 234 | try{ 235 | this.dis.close(); 236 | this.dis = null; 237 | }catch(Exception e){} 238 | 239 | } 240 | 241 | public void addIncomingListener(IncomingListener listener) { 242 | listeners.add(IncomingListener.class, listener); 243 | } 244 | 245 | public void removeIncomingListener(IncomingListener listener) { 246 | listeners.remove(IncomingListener.class, listener); 247 | } 248 | 249 | public IncomingListener[] getIncomingListeners() { 250 | return listeners.getListeners(IncomingListener.class); 251 | } 252 | 253 | protected void fireMessageReceived(Message m) { 254 | for (IncomingListener listener : getIncomingListeners()) { 255 | listener.messageReceived(m); 256 | } 257 | } 258 | 259 | /** 260 | * Stops the current thread by completing the run() method 261 | */ 262 | public void stopThread(){ 263 | this.run = false; 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /MessageSender.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | import java.util.concurrent.TimeUnit; 42 | import java.util.concurrent.LinkedBlockingQueue; 43 | import java.util.concurrent.PriorityBlockingQueue; 44 | import java.io.OutputStream; 45 | import javax.swing.event.EventListenerList; 46 | 47 | /** 48 | * Thread created to send message to the remote peer. Hold a queue for outgoing 49 | * messages 50 | */ 51 | public class MessageSender extends Thread { 52 | private OutputStream os = null; 53 | private LinkedBlockingQueue outgoingMessage = null; 54 | private long lmst = 0; 55 | private boolean run = true; 56 | private final EventListenerList listeners = new EventListenerList(); 57 | 58 | 59 | public MessageSender(String id, OutputStream os) { 60 | //this.setName("MS_"+id); 61 | this.os = os; 62 | this.outgoingMessage = new LinkedBlockingQueue(); 63 | } 64 | 65 | public void addOutgoingListener(OutgoingListener listener) { 66 | listeners.add(OutgoingListener.class, listener); 67 | } 68 | 69 | public void removeOutgoingListener(OutgoingListener listener) { 70 | listeners.remove(OutgoingListener.class, listener); 71 | } 72 | 73 | public OutgoingListener[] getOutgoingListeners() { 74 | return listeners.getListeners(OutgoingListener.class); 75 | } 76 | 77 | /** 78 | * Called when the connection to the peer has been closed. Advertise the 79 | * DownloadTask that there is no more connection to the remote peer. 80 | */ 81 | protected void fireConnectionClosed() { 82 | for (OutgoingListener listener : getOutgoingListeners()) { 83 | listener.connectionClosed(); 84 | } 85 | } 86 | 87 | /** 88 | * Called when a keep-alive message has been sent. This happens about every 89 | * 2 minutes if there has not been any other messages sent to avoid the 90 | * connection to be closed by the remote peer 91 | */ 92 | protected void fireKeepAliveSent() { 93 | for (OutgoingListener listener : getOutgoingListeners()) { 94 | listener.keepAliveSent(); 95 | } 96 | } 97 | 98 | /** 99 | * Puts the message in parameter in the queue, waiting to be sent 100 | * @param m Message 101 | */ 102 | public synchronized void addMessageToQueue(Message m){ 103 | this.outgoingMessage.add(m); 104 | this.lmst = System.currentTimeMillis(); 105 | //this.notify(); 106 | } 107 | 108 | /** 109 | * Sends messages from the queue. While the queue is not empty, polls message 110 | * from it and sends it to the remote peer. If the queue is empty for more than 111 | * 2 minutes, a keep-alive message is sent and the DownloadTask is advertised 112 | */ 113 | public void run() { 114 | Message out = null; 115 | byte[] keep = new Message_PP(PeerProtocol.KEEP_ALIVE).generate(); 116 | try { 117 | while (this.run) { 118 | if(this.outgoingMessage != null && this.os != null) 119 | out = outgoingMessage.poll(120000, TimeUnit.MILLISECONDS); 120 | if(out != null){ 121 | os.write(out.generate()); 122 | this.lmst = System.currentTimeMillis(); 123 | out = null; 124 | }else if(this.run){ 125 | os.write(keep); 126 | this.fireKeepAliveSent(); 127 | } 128 | } 129 | } catch (InterruptedException ie) { 130 | } catch(IOException ioe){ 131 | this.fireConnectionClosed(); 132 | } catch(Exception e){ 133 | this.fireConnectionClosed(); 134 | } 135 | 136 | if(this.outgoingMessage != null) 137 | this.outgoingMessage.clear(); 138 | this.outgoingMessage = null; 139 | try{ 140 | this.os.close(); 141 | this.os = null; 142 | this.notify(); 143 | }catch(Exception e){} 144 | 145 | } 146 | 147 | /** 148 | * Sets the 'run' variable to false, causing the thread to stop on its next 149 | * loop. 150 | */ 151 | public void stopThread(){ 152 | this.run = false; 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /Message_HS.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | /** 41 | * 42 | * Represent a Handshake message according to Bittorrent Protocol. It has the form: 43 | * 44 | * 45 | * - # pstrlen: string length of , as a single raw byte - 46 | * - # pstr: string identifier of the protocol - 47 | * - # reserved: eight (8) reserved bytes - 48 | * - # info_hash: 20-byte SHA1 hash of the info key in the metainfo file - 49 | * - # peer_id: 20-byte string used as a unique ID for the client - 50 | * 51 | * @author Baptiste Dubuis 52 | * @version 0.1 53 | */ 54 | public class Message_HS extends Message { 55 | 56 | private byte[] length = new byte[1]; 57 | private byte[] protocol = new byte[19]; 58 | private byte[] reserved = new byte[8]; 59 | private byte[] fileID = new byte[20]; 60 | private byte[] peerID = new byte[20]; 61 | 62 | /** 63 | * Creates an empty HS message 64 | */ 65 | public Message_HS(){ 66 | super(-1, 0); 67 | } 68 | 69 | /** 70 | * Creates a HS message with the given infoHash and peerID and default values 71 | * @param infoHash byte[] 72 | * @param peerID byte[] 73 | */ 74 | public Message_HS(byte[] infoHash, byte[] peerID){ 75 | this(new byte[]{19}, "BitTorrent protocol".getBytes(), 76 | new byte[]{0,0,0,0,0,0,0,0}, infoHash, peerID); 77 | } 78 | 79 | /** 80 | * Create a HS message with all given parameters 81 | * @param length byte[] 82 | * @param protocol byte[] 83 | * @param reserved byte[] 84 | * @param fileID byte[] 85 | * @param peerID byte[] 86 | */ 87 | public Message_HS(byte[] length, byte[] protocol, byte[] reserved, byte[] fileID, byte[] peerID){ 88 | super(-1, 0); 89 | this.length = length; 90 | this.protocol = protocol; 91 | this.reserved = reserved; 92 | this.fileID = fileID; 93 | this.peerID = peerID; 94 | } 95 | /** 96 | * Return the length of the protocol string as a byte 97 | * @return byte 98 | */ 99 | public byte getLength(){ 100 | return length[0]; 101 | } 102 | /** 103 | * Return the protocol string as a byte array 104 | * @return byte[] 105 | */ 106 | public byte[] getProtocol(){ 107 | return this.protocol; 108 | } 109 | /** 110 | * Return the reserved bytes as a byte array 111 | * @return byte[] 112 | */ 113 | public byte[] getReserved(){ 114 | return this.reserved; 115 | } 116 | /** 117 | * Return the infoHash as a byte array 118 | * @return byte[] 119 | */ 120 | public byte[] getFileID(){ 121 | return this.fileID; 122 | } 123 | /** 124 | * Return the peerID as a byte array 125 | * @return byte[] 126 | */ 127 | public byte[] getPeerID(){ 128 | return this.peerID; 129 | } 130 | 131 | /** 132 | * Set the values of the fields according to the parameters 133 | * @param length byte[] 134 | * @param protocol byte[] 135 | * @param reserved byte[] 136 | * @param fileID byte[] 137 | * @param peerID byte[] 138 | */ 139 | public void setData(byte[] length, byte[] protocol, byte[] reserved, 140 | byte[] fileID, byte[] peerID){ 141 | this.length = length; 142 | this.protocol = protocol; 143 | this.reserved = reserved; 144 | this.fileID = fileID; 145 | this.peerID = peerID; 146 | } 147 | /** 148 | * Generate the byte array representing the whole message that can then be transmitted 149 | * @return byte[] 150 | */ 151 | public byte[] generate(){ 152 | return Utils.concat(this.length, Utils.concat(this.protocol, Utils.concat(this.reserved, Utils.concat(this.fileID, this.peerID)))); 153 | } 154 | /** 155 | * Display the message in a readable format 156 | * @return String 157 | */ 158 | public String toString(){ 159 | String toString = ""; 160 | toString += this.length[0]+"+"; 161 | toString += new String(this.protocol)+"+"; 162 | toString += Utils.byteArrayToByteString(this.reserved)+"+"; 163 | toString += Utils.byteArrayToByteString(this.fileID)+"+"; 164 | toString += Utils.byteArrayToByteString(this.peerID); 165 | 166 | return toString; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Message_PP.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | /** 41 | * 42 | * Represent a Peer Protocol message according to Bittorrent protocol specifications. 43 | * This message format depends on its identity, so refer to Bittorrent specifications for further information 44 | * 45 | * @author Baptiste Dubuis 46 | * @version 0.1 47 | */ 48 | public class Message_PP extends Message { 49 | private byte[] length = new byte[4]; 50 | private byte[] id = new byte[1]; 51 | private byte[] payload; 52 | 53 | public Message_PP(){ 54 | super(); 55 | } 56 | 57 | public Message_PP(int type, int p) { 58 | super(type, p); 59 | this.setData(type); 60 | } 61 | 62 | public Message_PP(int type){ 63 | this(type, 0); 64 | } 65 | 66 | public Message_PP(int type, byte[] payload, int p) { 67 | super(type, p); 68 | this.setData(type, payload); 69 | } 70 | 71 | public Message_PP(int type, byte[] payload){ 72 | this(type, payload, 0); 73 | } 74 | 75 | 76 | public byte[] getLength() { 77 | return this.length; 78 | } 79 | 80 | public byte[] getID() { 81 | return this.id; 82 | } 83 | 84 | public byte[] getPayload() { 85 | return this.payload; 86 | } 87 | 88 | public void setLength(byte[] length) { 89 | this.length = length; 90 | } 91 | 92 | public void setID(int id) { 93 | this.id[0] = (byte) id; 94 | } 95 | 96 | public void setPayload(byte[] payload) { 97 | this.payload = payload; 98 | } 99 | 100 | public void setData(int type) { 101 | this.type = type; 102 | switch (type) { 103 | case 0: 104 | this.length = new byte[] {0, 0, 0, 0}; 105 | break; 106 | case 1: 107 | this.length = new byte[] {0, 0, 0, 1}; 108 | this.id[0] = 0; 109 | break; 110 | case 2: 111 | this.length = new byte[] {0, 0, 0, 1}; 112 | this.id[0] = 1; 113 | break; 114 | case 3: 115 | this.length = new byte[] {0, 0, 0, 1}; 116 | this.id[0] = 2; 117 | break; 118 | case 4: 119 | this.length = new byte[] {0, 0, 0, 1}; 120 | this.id[0] = 3; 121 | break; 122 | } 123 | } 124 | 125 | public void setData(int type, byte[] payload) { 126 | this.type = type; 127 | switch (type) { 128 | case 5: 129 | this.length = new byte[] {0, 0, 0, 5}; 130 | this.id[0] = 4; 131 | this.payload = payload; 132 | break; 133 | case 6: 134 | this.length = Utils.intToByteArray(1 + payload.length); 135 | this.id[0] = 5; 136 | this.payload = payload; 137 | break; 138 | case 7: 139 | this.length = new byte[] {0, 0, 0, 13}; 140 | this.id[0] = 6; 141 | this.payload = payload; 142 | break; 143 | case 8: 144 | this.length = Utils.intToByteArray(1 + payload.length); 145 | this.id[0] = 7; 146 | this.payload = payload; 147 | break; 148 | case 9: 149 | this.length = new byte[] {0, 0, 0, 13}; 150 | this.id[0] = 8; 151 | this.payload = payload; 152 | break; 153 | case 10: 154 | this.length = new byte[] {0, 0, 0, 3}; 155 | this.id[0] = 9; 156 | this.payload = payload; 157 | break; 158 | } 159 | } 160 | 161 | public void setData(byte[] length, byte id, byte[] payload) { 162 | this.length = length; 163 | this.id[0] = id; 164 | this.payload = payload; 165 | } 166 | 167 | public byte[] generate() { 168 | if (this.type > 4) 169 | return Utils.concat(Utils.concat(this.length, this.id), 170 | this.payload); 171 | else if (this.type > 0) 172 | return Utils.concat(this.length, this.id); 173 | else 174 | return this.length; 175 | } 176 | 177 | public String toString() { 178 | String toString = ""; 179 | 180 | int length = Utils.byteArrayToInt(this.length); 181 | toString += ""; 182 | if (length > 0) { 183 | toString += ""; 184 | if (length > 1) { 185 | switch(this.id[0]+1){ 186 | case PeerProtocol.HAVE: 187 | toString += ""; 189 | break; 190 | case PeerProtocol.BITFIELD: 191 | toString += ""; 192 | break; 193 | case PeerProtocol.REQUEST: 194 | toString += ""; 195 | toString += ""; 196 | toString += ""; 197 | break; 198 | case PeerProtocol.PIECE: 199 | toString += ""; 200 | toString += ""; 201 | toString += ""; 202 | break; 203 | case PeerProtocol.CANCEL: 204 | toString += ""; 205 | toString += ""; 206 | toString += ""; 207 | break; 208 | case PeerProtocol.PORT: 209 | break; 210 | } 211 | // + ">"; 212 | } 213 | } 214 | return toString; 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /OutgoingListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.EventListener; 41 | 42 | public interface OutgoingListener extends EventListener{ 43 | /** 44 | * Fired when the connection to the remote peer has been closed 45 | */ 46 | public void connectionClosed(); 47 | 48 | /** 49 | * Fired when a keep-alive message has been sent 50 | */ 51 | public void keepAliveSent(); 52 | } 53 | -------------------------------------------------------------------------------- /Peer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.*; 41 | 42 | /** 43 | * Class representing a bittorrent peer 44 | * 45 | */ 46 | public class Peer { 47 | private String id; 48 | private String ip; 49 | private int port; 50 | private boolean interested = false; 51 | private boolean choked = true; 52 | private boolean interesting = false; 53 | private boolean choking = true; 54 | private BitSet hasPiece; 55 | private int downloaded = 0; 56 | private float dlrate = 0; 57 | private long lastDL = 0; 58 | private float ulrate = 0; 59 | private long lastUL = 0; 60 | private int uploaded = 0; 61 | private boolean connected = false; 62 | 63 | public Peer() { 64 | this.hasPiece = new BitSet(); 65 | } 66 | 67 | public Peer(String id, String ip, int port){ 68 | this.lastDL = System.currentTimeMillis(); 69 | this.lastUL = System.currentTimeMillis(); 70 | this.id = id; 71 | this.ip = ip; 72 | this.port = port; 73 | this.hasPiece = new BitSet(); 74 | } 75 | 76 | public void resetDL(){ 77 | this.dlrate = 0; 78 | this.lastDL = System.currentTimeMillis(); 79 | } 80 | 81 | public void resetUL(){ 82 | this.ulrate = 0; 83 | this.lastUL = System.currentTimeMillis(); 84 | } 85 | 86 | /** 87 | * Returns the number of bytes downloaded since the last reset 88 | * @param reset true if the download rate should be reset 89 | * @return float 90 | */ 91 | public float getDLRate(boolean reset){ 92 | if(reset){ 93 | float tmp = this.dlrate; 94 | this.dlrate = 0; 95 | return tmp; 96 | }else 97 | return this.dlrate; 98 | 99 | } 100 | 101 | /** 102 | * Returns the number of bytes uploaded since the last reset. 103 | * @param reset true if the download rate should be reset 104 | * @return float 105 | */ 106 | public float getULRate(boolean reset){ 107 | if(reset){ 108 | float tmp = this.ulrate; 109 | this.ulrate = 0; 110 | return tmp; 111 | }else 112 | return this.ulrate; 113 | } 114 | 115 | /** 116 | * Returns the total number of bytes downloaded from this peer 117 | * @return int 118 | */ 119 | public int getDL(){ 120 | return this.downloaded; 121 | } 122 | 123 | /** 124 | * Returns the total number of bytes uploaded to this peer 125 | * @return int 126 | */ 127 | public int getUL(){ 128 | return this.uploaded; 129 | } 130 | 131 | /** 132 | * Updates the downloaded values 133 | * @param dl int 134 | */ 135 | public void setDLRate(int dl){ 136 | this.dlrate += dl; 137 | this.downloaded += dl; 138 | } 139 | 140 | /** 141 | * Updates the uploaded values 142 | * @param ul int 143 | */ 144 | public void setULRate(int ul){ 145 | this.ulrate += ul; 146 | this.uploaded += ul; 147 | } 148 | 149 | /** 150 | * Returns the id of this peer 151 | * @return String 152 | */ 153 | public String getID(){ 154 | return this.id; 155 | } 156 | 157 | /** 158 | * Returns the IP address of this peer 159 | * @return String 160 | */ 161 | public String getIP(){ 162 | return this.ip; 163 | } 164 | 165 | /** 166 | * Returns the listening port of this peer 167 | * @return int 168 | */ 169 | public int getPort(){ 170 | return this.port; 171 | } 172 | 173 | /** 174 | * Returns the pieces availability of this peer 175 | * @return BitSet 176 | */ 177 | public BitSet getHasPiece(){ 178 | return this.hasPiece; 179 | } 180 | 181 | /** 182 | * Sets the id of this peer 183 | * @param id String 184 | */ 185 | public void setID(String id){ 186 | this.id = id; 187 | } 188 | 189 | /** 190 | * Sets the IP address of this peer 191 | * @param ip String 192 | */ 193 | public void setIP(String ip){ 194 | this.ip = ip; 195 | } 196 | 197 | /** 198 | * Sets the listening port of this peer 199 | * @param port int 200 | */ 201 | public void setPort(int port){ 202 | this.port = port; 203 | } 204 | /** 205 | * Returns if this peer is interested or not 206 | * @return boolean 207 | */ 208 | public boolean isInterested(){ 209 | return this.interested; 210 | } 211 | 212 | /** 213 | * Returns if this peer is choked or not 214 | * @return boolean 215 | */ 216 | public boolean isChoked(){ 217 | return this.choked; 218 | } 219 | 220 | /** 221 | * Returns if this peer is interesting or not 222 | * @return boolean 223 | */ 224 | public boolean isInteresting(){ 225 | return this.interesting; 226 | } 227 | 228 | /** 229 | * Returns if this peer is choking or not 230 | * @return boolean 231 | */ 232 | public boolean isChoking(){ 233 | return this.choking; 234 | } 235 | 236 | /** 237 | * Sets if this peer is intereseted or not 238 | * @param i boolean 239 | */ 240 | public void setInterested(boolean i){ 241 | this.interested = i; 242 | } 243 | 244 | /** 245 | * Sets if this peer is choked or not 246 | * @param c boolean 247 | */ 248 | public void setChoked(boolean c){ 249 | this.choked = c; 250 | } 251 | 252 | /** 253 | * Sets if this peer is interesting or not 254 | * @param i boolean 255 | */ 256 | public void setInteresting(boolean i){ 257 | this.interesting = i; 258 | } 259 | 260 | /** 261 | * Sets if this peer is choking or not 262 | * @param c boolean 263 | */ 264 | public void setChoking(boolean c){ 265 | this.choking = c; 266 | } 267 | 268 | /** 269 | * Updates this peer availability according to the received bitfield 270 | * @param bitfield byte[] 271 | */ 272 | public void setHasPiece(byte[] bitfield){ 273 | boolean[] b = Utils.byteArray2BitArray(bitfield); 274 | for(int i = 0; i < b.length; i++) 275 | this.hasPiece.set(i,b[i]); 276 | } 277 | 278 | /** 279 | * Updates the availability of the piece in parameter 280 | * @param piece int 281 | * @param has boolean 282 | */ 283 | public void setHasPiece(int piece, boolean has){ 284 | this.hasPiece.set(piece, has); 285 | } 286 | 287 | public boolean isConnected(){ 288 | return this.connected; 289 | } 290 | 291 | public void setConnected(boolean connectionStatus){ 292 | this.connected = connectionStatus; 293 | } 294 | 295 | /** 296 | * Compares if this peer is equal to the peer in parameter 297 | * @param p Peer 298 | * @return boolean 299 | */ 300 | public boolean equals(Peer p){ 301 | if(this.id == p.getID() && this.ip == p.getIP() && this.port == p.getPort()) 302 | return true; 303 | return false; 304 | } 305 | 306 | /** 307 | * Returns this peer characteristics in the form : 308 | * @return String 309 | */ 310 | public String toString(){ 311 | return (this.ip+":" + this.port); 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /PeerProtocol.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.lang.ArrayIndexOutOfBoundsException; 41 | import java.io.InputStream; 42 | import java.io.IOException; 43 | 44 | /** 45 | * Constants used in Peer Protocol. 46 | * 47 | * @author Baptiste Dubuis 48 | * @version 0.1 49 | */ 50 | public class PeerProtocol { 51 | public static final int HANDSHAKE = -1; 52 | public static final int KEEP_ALIVE = 0; 53 | public static final int CHOKE = 1; 54 | public static final int UNCHOKE = 2; 55 | public static final int INTERESTED = 3; 56 | public static final int NOT_INTERESTED = 4; 57 | public static final int HAVE = 5; 58 | public static final int BITFIELD = 6; 59 | public static final int REQUEST = 7; 60 | public static final int PIECE = 8; 61 | public static final int CANCEL = 9; 62 | public static final int PORT = 10; 63 | public static final String[] TYPE = {"Keep_Alive", "Choke", "Unchoke", 64 | "Interested", "Not_Interested", "Have", 65 | "Bitfield", "Request", "Piece", 66 | "Cancel", "Port"}; 67 | 68 | public static final int BLOCK_SIZE = 16384; 69 | public static final byte[] BLOCK_SIZE_BYTES = Utils.intToByteArray(16384); 70 | /* 71 | public static Message_HS readHS(InputStream is) { 72 | try { 73 | byte[] length = new byte[1]; 74 | is.read(length); 75 | byte[] protocol = new byte[19]; 76 | is.read(protocol); 77 | byte[] reserved = new byte[8]; 78 | is.read(reserved); 79 | byte[] fileID = new byte[20]; 80 | is.read(fileID); 81 | byte[] peerID = new byte[20]; 82 | is.read(peerID); 83 | 84 | return new Message_HS(fileID, peerID); 85 | 86 | } catch (IOException ioe) { 87 | 88 | } 89 | return null; 90 | } 91 | 92 | public static Message_PP readMessage(InputStream is) { 93 | byte[] length = new byte[4]; 94 | int id; 95 | byte[] payload = new byte[0]; 96 | try { 97 | is.read(length); 98 | int l = Utils.byteArrayToInt(length); 99 | if (l == 0) 100 | return new Message_PP(KEEP_ALIVE); 101 | 102 | long timeout = System.currentTimeMillis(); 103 | id = is.read(); 104 | if (l == 1) 105 | return new Message_PP(id + 1); 106 | l = l - 1; 107 | for (int i = 0; i < l; ) { 108 | int available = is.available(); 109 | if (available < l - i) { 110 | byte[] temp = new byte[available]; 111 | is.read(temp); 112 | payload = Utils.concat(payload, temp); 113 | i += available; 114 | } else { 115 | byte[] temp = new byte[l - i]; 116 | is.read(temp); 117 | payload = Utils.concat(payload, temp); 118 | break; 119 | } 120 | } 121 | return new Message_PP(id + 1, payload); 122 | } catch (IOException ioe) { 123 | System.err.println("Problem when reading message from stream..."); 124 | ioe.printStackTrace(); 125 | } 126 | return null; 127 | } 128 | */ 129 | } 130 | -------------------------------------------------------------------------------- /PeerUpdateListener.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.LinkedHashMap; 41 | import java.util.EventListener; 42 | 43 | public interface PeerUpdateListener extends EventListener{ 44 | public void updatePeerList(LinkedHashMap list); 45 | public void updateFailed(int error, String message); 46 | } 47 | -------------------------------------------------------------------------------- /PeerUpdater.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.*; 41 | import javax.swing.event.EventListenerList; 42 | import java.net.UnknownHostException; 43 | import java.io.InputStream; 44 | import java.io.IOException; 45 | import java.io.BufferedInputStream; 46 | import java.net.MalformedURLException; 47 | import java.net.URL; 48 | import java.net.URLConnection; 49 | 50 | /** 51 | * Class providing methods to enable communication between the client and a tracker. 52 | * Provide method to decode and parse tracker response. 53 | * 54 | * @author Baptiste Dubuis 55 | * @version 0.1 56 | */ 57 | public class PeerUpdater extends Thread { 58 | private LinkedHashMap peerList; 59 | private byte[] id; 60 | private TorrentFile torrent; 61 | 62 | 63 | private long downloaded = 0; 64 | private long uploaded = 0; 65 | private long left = 0; 66 | private String event = "&event=started"; 67 | private int listeningPort = 6881; 68 | 69 | private int interval = 150; 70 | private int minInterval = 0; 71 | private boolean first = true; 72 | private boolean end = false; 73 | 74 | 75 | private final EventListenerList listeners = new EventListenerList(); 76 | 77 | public PeerUpdater(byte[] id, TorrentFile torrent) { 78 | peerList = new LinkedHashMap(); 79 | this.id = id; 80 | this.torrent = torrent; 81 | this.left = torrent.total_length; 82 | this.setDaemon(true); 83 | //this.start(); 84 | } 85 | 86 | public void setListeningPort(int port){ 87 | this.listeningPort = port; 88 | } 89 | 90 | /** 91 | * Returns the last interval for updates received from the tracker 92 | * @return int 93 | */ 94 | public int getInterval() { 95 | return this.interval; 96 | } 97 | 98 | /** 99 | * Returns the last minimal interval for updates received from the tracker 100 | * @return int 101 | */ 102 | 103 | public int getMinInterval() { 104 | return this.minInterval; 105 | } 106 | 107 | /** 108 | * Returns the number of bytes that have been downloaded so far 109 | * @return int 110 | */ 111 | 112 | public long getDownloaded() { 113 | return this.downloaded; 114 | } 115 | 116 | /** 117 | * Returns the number of bytes that have been uploaded so far 118 | * @return int 119 | */ 120 | 121 | public long getUploaded() { 122 | return this.uploaded; 123 | } 124 | 125 | /** 126 | * Returns the number of bytes still to download to complete task 127 | * @return int 128 | */ 129 | 130 | public long getLeft() { 131 | return this.left; 132 | } 133 | 134 | /** 135 | * Returns the current event of the client 136 | * @return int 137 | */ 138 | 139 | public String getEvent() { 140 | return this.event; 141 | } 142 | 143 | /** 144 | * Sets the interval between tracker update 145 | * @param interval int 146 | */ 147 | public void setInterval(int interval) { 148 | this.interval = interval; 149 | } 150 | 151 | /** 152 | * Sets the mininterval between tracker update 153 | * @param minInt int 154 | */ 155 | public void setMinInterval(int minInt) { 156 | this.minInterval = minInt; 157 | } 158 | 159 | /** 160 | * Sets the # of bytes downloaded so far 161 | * @param dl long 162 | */ 163 | 164 | public void setDownloaded(long dl) { 165 | this.downloaded = dl; 166 | } 167 | 168 | /** 169 | * Sets the # of bytes uploaded so far 170 | * @param ul long 171 | */ 172 | public void setUploaded(long ul) { 173 | this.uploaded = ul; 174 | } 175 | 176 | /** 177 | * Sets the # of bytes still to download 178 | * @param left long 179 | */ 180 | public void setLeft(long left) { 181 | this.left = left; 182 | } 183 | 184 | /** 185 | * Sets the current state of the client 186 | * @param event String 187 | */ 188 | public void setEvent(String event) { 189 | this.event = event; 190 | } 191 | 192 | /** 193 | * Returns the list of peers in its current state 194 | * @return LinkedHashMap 195 | */ 196 | public LinkedHashMap getList() { 197 | return this.peerList; 198 | } 199 | 200 | /** 201 | * Update the parameters for future tracker communication 202 | * @param dl int 203 | * @param ul int 204 | * @param event String 205 | */ 206 | public synchronized void updateParameters(int dl, int ul, String event) { 207 | synchronized (this) { 208 | this.downloaded += dl; 209 | this.uploaded += ul; 210 | this.left -= dl; 211 | this.event = event; 212 | } 213 | } 214 | 215 | /** 216 | * Thread method that regularly contact the tracker and process its response 217 | */ 218 | public void run() { 219 | int tryNB = 0; 220 | byte[] b = new byte[0]; 221 | while (!this.end) { 222 | tryNB++; 223 | 224 | this.peerList = this.processResponse(this.contactTracker(id, 225 | torrent, this.downloaded, 226 | this.uploaded, 227 | this.left, this.event)); 228 | if (peerList != null) { 229 | if (first) { 230 | this.event = ""; 231 | first = false; 232 | } 233 | tryNB = 0; 234 | this.fireUpdatePeerList(this.peerList); 235 | try { 236 | synchronized (b) { 237 | b.wait(interval * 1000); 238 | } 239 | } catch (InterruptedException ie) {} 240 | } else { 241 | try { 242 | synchronized (b) { 243 | b.wait(2000); 244 | } 245 | } catch (InterruptedException ie) {} 246 | } 247 | } 248 | } 249 | 250 | /** 251 | * Process the map representing the tracker response, which should contain 252 | * either an error message or the peers list and other information such as 253 | * the interval before next update, aso 254 | * @param m The tracker response as a Map 255 | * @return LinkedHashMap A HashMap containing the peers and their ID as keys 256 | */ 257 | public synchronized LinkedHashMap processResponse(Map m) { 258 | LinkedHashMap l = null; 259 | if (m != null) { 260 | if (m.containsKey("failure reason")) { 261 | this.fireUpdateFailed(0, 262 | "The tracker returns the following error message:" + 263 | "\t'" + 264 | new String((byte[]) m.get( 265 | "failure reason")) + 266 | "'"); 267 | return null; 268 | } else { 269 | if (((Long) m.get("interval")).intValue() < this.interval) 270 | this.interval = ((Long) m.get("interval")).intValue(); 271 | else 272 | this.interval *= 2; 273 | 274 | Object peers = m.get("peers"); 275 | ArrayList peerList = new ArrayList(); 276 | l = new LinkedHashMap(); 277 | if (peers instanceof List) { 278 | peerList.addAll((List) peers); 279 | if (peerList != null && peerList.size() > 0) { 280 | for (int i = 0; i < peerList.size(); i++) { 281 | String peerID = new String((byte[]) ((Map) ( 282 | peerList. 283 | get(i))). 284 | get( 285 | "peer_id")); 286 | String ipAddress = new String((byte[]) ((Map) ( 287 | peerList. 288 | get( 289 | i))). 290 | get("ip")); 291 | int port = ((Long) ((Map) (peerList.get(i))).get( 292 | "port")).intValue(); 293 | Peer p = new Peer(peerID, ipAddress, port); 294 | l.put(p.toString(), p); 295 | } 296 | } 297 | } else if (peers instanceof byte[]) { 298 | byte[] p = ((byte[]) peers); 299 | for (int i = 0; i < p.length; i += 6) { 300 | Peer peer = new Peer(); 301 | peer.setIP(Utils.byteToUnsignedInt(p[i]) + "." + 302 | Utils.byteToUnsignedInt(p[i + 1]) + "." + 303 | Utils.byteToUnsignedInt(p[i + 2]) + "." + 304 | Utils.byteToUnsignedInt(p[i + 3])); 305 | peer.setPort(Utils.byteArrayToInt(Utils.subArray(p, 306 | i + 4, 2))); 307 | l.put(peer.toString(), peer); 308 | } 309 | } 310 | } 311 | return l; 312 | } else 313 | return null; 314 | } 315 | 316 | /** 317 | * Contact the tracker according to the HTTP/HTTPS tracker protocol and using 318 | * the information in the TorrentFile. 319 | * @param id byte[] 320 | * @param t TorrentFile 321 | * @param dl long 322 | * @param ul long 323 | * @param left long 324 | * @param event String 325 | * @return A Map containing the decoded tracker response 326 | */ 327 | public synchronized Map contactTracker(byte[] id, 328 | TorrentFile t, long dl, long ul, 329 | long left, String event) { 330 | try { 331 | URL source = new URL(t.announceURL + "?info_hash=" + 332 | t.info_hash_as_url + "&peer_id=" + 333 | Utils.byteArrayToURLString(id) + "&port="+ 334 | this.listeningPort + 335 | "&downloaded=" + dl + "&uploaded=" + ul + 336 | "&left=" + 337 | left + "&numwant=100&compact=1" + event); 338 | // System.out.println("Contact Tracker. URL source = " + source); //DAVID 339 | URLConnection uc = source.openConnection(); 340 | InputStream is = uc.getInputStream(); 341 | 342 | BufferedInputStream bis = new BufferedInputStream(is); 343 | 344 | // Decode the tracker bencoded response 345 | Map m = BDecoder.decode(bis); 346 | // System.out.println(m); 347 | bis.close(); 348 | is.close(); 349 | 350 | return m; 351 | } catch (MalformedURLException murle) { 352 | this.fireUpdateFailed(2, 353 | "Tracker URL is not valid... Check if your data is correct and try again"); 354 | } catch (UnknownHostException uhe) { 355 | this.fireUpdateFailed(3, "Tracker not available... Retrying..."); 356 | } catch (IOException ioe) { 357 | this.fireUpdateFailed(4, "Tracker unreachable... Retrying"); 358 | } catch (Exception e) { 359 | this.fireUpdateFailed(5, "Internal error"); 360 | } 361 | return null; 362 | } 363 | 364 | /** 365 | * Stops the update process. This methods sends one last message to 366 | * the tracker saying this client stops sharing the file and it also exits 367 | * the run method 368 | */ 369 | public void end() { 370 | this.event = "&event=stopped"; 371 | this.end = true; 372 | this.contactTracker(this.id, this.torrent, this.downloaded, 373 | this.uploaded, this.left, "&event=stopped"); 374 | } 375 | 376 | /** 377 | * Adds a PeerUpdateListener to the list of listeners, enabling communication 378 | * with this object 379 | * @param listener PeerUpdateListener 380 | */ 381 | public void addPeerUpdateListener(PeerUpdateListener listener) { 382 | listeners.add(PeerUpdateListener.class, listener); 383 | } 384 | 385 | /** 386 | * Removes a PeerUpdateListener from the list of listeners 387 | * @param listener PeerUpdateListener 388 | */ 389 | 390 | public void removePeerUpdateListener(PeerUpdateListener listener) { 391 | listeners.remove(PeerUpdateListener.class, listener); 392 | } 393 | 394 | /** 395 | * Returns the list of object that are currently listening to this PeerUpdater 396 | * @return PeerUpdateListener[] 397 | */ 398 | public PeerUpdateListener[] getPeerUpdateListeners() { 399 | return listeners.getListeners(PeerUpdateListener.class); 400 | } 401 | 402 | /** 403 | * Sends a message to all listeners with a HashMap containg the list of all 404 | * peers present in the last tracker response 405 | * @param l LinkedHashMap 406 | */ 407 | protected void fireUpdatePeerList(LinkedHashMap l) { 408 | for (PeerUpdateListener listener : getPeerUpdateListeners()) { 409 | listener.updatePeerList(l); 410 | } 411 | } 412 | 413 | /** 414 | * Sends a message to all listeners with an error code and a String representing 415 | * the reason why the last try to contact tracker failed 416 | * @param error int 417 | * @param message String 418 | */ 419 | 420 | protected void fireUpdateFailed(int error, String message) { 421 | for (PeerUpdateListener listener : getPeerUpdateListeners()) { 422 | listener.updateFailed(error, message); 423 | } 424 | } 425 | 426 | } 427 | -------------------------------------------------------------------------------- /Piece.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.*; 41 | 42 | /** 43 | * Class representing a piece according to bittorrent definition. 44 | * The piece is a part of data of the target file(s) 45 | * 46 | * @author Baptiste Dubuis 47 | * @version 0.1 48 | */ 49 | public class Piece { 50 | 51 | private TreeMap filesAndoffset; 52 | /** 53 | * Index of the piece within the file(s) 54 | */ 55 | private int index; 56 | /** 57 | * Length of the piece. It should be constant, except for the last piece of the file(s) 58 | */ 59 | private int length; 60 | /** 61 | * Map containing the piece data 62 | */ 63 | private TreeMap pieceBlock; 64 | /** 65 | * SHA1 hash of the piece contained in the torrent file. At the end of the download 66 | * this value must correspond to the SHA1 hash of the pieceBlock map concatenated 67 | */ 68 | byte[] sha1; 69 | 70 | public Piece(int index, int length, int blockSize, byte[] sha1){ 71 | this(index, length, blockSize, sha1, null); 72 | } 73 | 74 | /** 75 | * Constructor of a Piece 76 | * @param index Index of the piece 77 | * @param length Length of the piece 78 | * @param blockSize Size of a block of data 79 | * @param sha1 SHA1 hash that must be verified at the end of download 80 | * @param m HashTable containing the file(s) this piece belongs to and the index in these 81 | */ 82 | public Piece(int index, int length, int blockSize, byte[] sha1, TreeMap m) { 83 | this.index = index; 84 | this.length = length; 85 | this.pieceBlock = new TreeMap(); 86 | this.sha1 = sha1; 87 | if(m != null) 88 | this.filesAndoffset = m; 89 | else 90 | this.filesAndoffset = new TreeMap(); 91 | } 92 | 93 | public void clearData(){ 94 | this.pieceBlock.clear(); 95 | } 96 | 97 | public void setFileAndOffset(int file, int offset){ 98 | this.filesAndoffset.put(file, offset); 99 | } 100 | 101 | public TreeMap getFileAndOffset(){ 102 | return this.filesAndoffset; 103 | } 104 | 105 | /** 106 | * Return the index of the piece 107 | * @return int 108 | */ 109 | public synchronized int getIndex(){ 110 | return this.index; 111 | } 112 | 113 | /** 114 | * Returns the length of the piece 115 | * @return int 116 | */ 117 | public synchronized int getLength(){ 118 | return this.length; 119 | } 120 | 121 | /** 122 | * Set a block of data at the corresponding offset 123 | * @param offset Offset of the data within the current piece 124 | * @param data Data to be set at the given offset 125 | */ 126 | public synchronized void setBlock(int offset, byte[] data){ 127 | this.pieceBlock.put(offset, data); 128 | } 129 | 130 | /** 131 | * Returns the concatenated value of the pieceBlock map. This represent the piece data 132 | * @return byte[] 133 | */ 134 | public synchronized byte[] data(){ 135 | byte[] data = new byte[0]; 136 | for(Iterator it = this.pieceBlock.keySet().iterator(); it.hasNext();) 137 | data = Utils.concat(data, this.pieceBlock.get(it.next())); 138 | return data; 139 | } 140 | 141 | /** 142 | * Verify if the downloaded data corresponds to the original data contained in the torrent 143 | * by comparing it to the SHA1 hash in the torrent 144 | * @return boolean 145 | */ 146 | public synchronized boolean verify(){ 147 | return Utils.byteArrayToByteString(Utils.hash(this.data())).matches(Utils.byteArrayToByteString(this.sha1)); 148 | } 149 | 150 | /** 151 | * Print some information about the Piece 152 | * @return String 153 | */ 154 | public synchronized String toString(){ 155 | String s = ""; 156 | s += "Piece " + this.index + "[" + this.length + "Bytes], part of file"; 157 | if(this.filesAndoffset.size() > 1) 158 | s += "s"; 159 | for(Iterator it = this.filesAndoffset.keySet().iterator(); it.hasNext();){ 160 | int key = ((Integer)(it.next())).intValue(); 161 | s += " " + key + " [offset = " + this.filesAndoffset.get(key)+"]"; 162 | if(it.hasNext()) 163 | s += " and"; 164 | } 165 | return s; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /TorrentFile.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.ArrayList; 41 | import java.util.Date; 42 | 43 | /** 44 | * Representation of a torrent file 45 | * 46 | * @author Baptiste Dubuis 47 | * @version 0.1 48 | */ 49 | public class TorrentFile { 50 | 51 | public String announceURL; 52 | public String comment; 53 | public String createdBy; 54 | public long creationDate; 55 | public String encoding; 56 | public String saveAs; 57 | public int pieceLength; 58 | 59 | /* In case of multiple files torrent, saveAs is the name of a directory 60 | * and name contains the path of the file to be saved in this directory 61 | */ 62 | public ArrayList name; 63 | public ArrayList length; 64 | 65 | public byte[] info_hash_as_binary; 66 | public String info_hash_as_hex; 67 | public String info_hash_as_url; 68 | public long total_length; 69 | 70 | public ArrayList piece_hash_values_as_binary; 71 | public ArrayList piece_hash_values_as_hex; 72 | public ArrayList piece_hash_values_as_url; 73 | 74 | /** 75 | * Create the TorrentFile object and initiate its instance variables 76 | */ 77 | public TorrentFile() { 78 | super(); 79 | announceURL = new String(); 80 | comment = new String(); 81 | createdBy = new String(); 82 | encoding = new String(); 83 | saveAs = new String(); 84 | creationDate = -1; 85 | total_length = -1; 86 | pieceLength = -1; 87 | 88 | name = new ArrayList(); 89 | length = new ArrayList(); 90 | 91 | piece_hash_values_as_binary = new ArrayList(); 92 | piece_hash_values_as_url = new ArrayList(); 93 | piece_hash_values_as_hex = new ArrayList(); 94 | info_hash_as_binary = new byte[20]; 95 | info_hash_as_url = new String(); 96 | info_hash_as_hex = new String(); 97 | } 98 | 99 | /** 100 | * Print the torrent information in a readable manner. 101 | * @param detailed Choose if we want a detailed output or not. Detailed 102 | * output prints the comment, the files list and the pieces hashes while the 103 | * standard output simply prints tracker url, creator, creation date and 104 | * info hash 105 | */ 106 | public void printData(boolean detailed) { 107 | System.out.println("Tracker URL: " + this.announceURL); 108 | System.out.println("Torrent created by : " + this.createdBy); 109 | System.out.println("Torrent creation date : " + new Date(this.creationDate)); 110 | System.out.println("Info hash :\n"); 111 | System.out.println("\t\t" + new String(this.info_hash_as_binary)); 112 | System.out.println("\t\t" + this.info_hash_as_hex); 113 | System.out.println("\t\t" + this.info_hash_as_url); 114 | if(detailed){ 115 | System.out.println("Comment :" + this.comment); 116 | System.out.println("\nFiles List :\n"); 117 | for (int i = 0; i < this.length.size(); i++) 118 | System.out.println("\t- " + this.name.get(i) + " ( " + 119 | this.length.get(i) + " Bytes )"); 120 | System.out.println("\n"); 121 | System.out.println("Pieces hashes (piece length = " + 122 | this.pieceLength + ") :\n"); 123 | for (int i = 0; i < this.piece_hash_values_as_binary.size(); i++) { 124 | System.out.println((i + 1) + ":\t\t" + 125 | this.piece_hash_values_as_binary.get(i)); 126 | System.out.println("\t\t" + this.piece_hash_values_as_hex.get(i)); 127 | System.out.println("\t\t" + this.piece_hash_values_as_url.get(i)); 128 | 129 | } 130 | } 131 | 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /TorrentProcessor.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.io.*; 41 | import java.util.*; 42 | import java.nio.ByteBuffer; 43 | import java.net.URL; 44 | import java.net.MalformedURLException; 45 | 46 | /** 47 | * 48 | * Class enabling to process a torrent file 49 | * @author Baptiste Dubuis 50 | * @version 0.1 51 | */ 52 | public class TorrentProcessor { 53 | 54 | private TorrentFile torrent; 55 | 56 | int startLevel; 57 | 58 | 59 | public TorrentProcessor(TorrentFile torrent){ 60 | this.torrent = torrent; 61 | } 62 | 63 | public TorrentProcessor(){ 64 | this.torrent = new TorrentFile(); 65 | } 66 | 67 | /** 68 | * Given the path of a torrent, parse the file and represent it as a Map 69 | * @param filename String 70 | * @return Map 71 | */ 72 | public Map parseTorrent(String filename){ 73 | return this.parseTorrent(new File(filename)); 74 | } 75 | 76 | /** 77 | * Given a File (supposed to be a torrent), parse it and represent it as a Map 78 | * @param file File 79 | * @return Map 80 | */ 81 | public Map parseTorrent(File file){ 82 | try{ 83 | return BDecoder.decode(IOManager.readBytesFromFile(file)); 84 | } catch(IOException ioe){} 85 | return null; 86 | } 87 | 88 | /** 89 | * Given a Map, retrieve all useful information and represent it as a TorrentFile object 90 | * @param m Map 91 | * @return TorrentFile 92 | */ 93 | public TorrentFile getTorrentFile(Map m){ 94 | if(m == null) 95 | return null; 96 | if(m.containsKey("announce")) // mandatory key 97 | this.torrent.announceURL = new String((byte[]) m.get("announce")); 98 | else 99 | return null; 100 | if(m.containsKey("comment")) // optional key 101 | this.torrent.comment = new String((byte[]) m.get("comment")); 102 | if(m.containsKey("created by")) // optional key 103 | this.torrent.createdBy = new String((byte[]) m.get("created by")); 104 | if(m.containsKey("creation date")) // optional key 105 | this.torrent.creationDate = (Long) m.get("creation date"); 106 | if(m.containsKey("encoding")) // optional key 107 | this.torrent.encoding = new String((byte[]) m.get("encoding")); 108 | 109 | //Store the info field data 110 | if(m.containsKey("info")){ 111 | Map info = (Map) m.get("info"); 112 | try{ 113 | 114 | this.torrent.info_hash_as_binary = Utils.hash(BEncoder.encode(info)); 115 | this.torrent.info_hash_as_hex = Utils.byteArrayToByteString( 116 | this.torrent.info_hash_as_binary); 117 | this.torrent.info_hash_as_url = Utils.byteArrayToURLString( 118 | this.torrent.info_hash_as_binary); 119 | }catch(IOException ioe){return null;} 120 | if (info.containsKey("name")) 121 | this.torrent.saveAs = new String((byte[]) info.get("name")); 122 | if (info.containsKey("piece length")) 123 | this.torrent.pieceLength = ((Long) info.get("piece length")).intValue(); 124 | else 125 | return null; 126 | 127 | if (info.containsKey("pieces")) { 128 | byte[] piecesHash2 = (byte[]) info.get("pieces"); 129 | if (piecesHash2.length % 20 != 0) 130 | return null; 131 | 132 | for (int i = 0; i < piecesHash2.length / 20; i++) { 133 | byte[] temp = Utils.subArray(piecesHash2, i * 20, 20); 134 | this.torrent.piece_hash_values_as_binary.add(temp); 135 | this.torrent.piece_hash_values_as_hex.add(Utils. 136 | byteArrayToByteString( 137 | temp)); 138 | this.torrent.piece_hash_values_as_url.add(Utils. 139 | byteArrayToURLString( 140 | temp)); 141 | } 142 | } else 143 | return null; 144 | 145 | if (info.containsKey("files")) { 146 | List multFiles = (List) info.get("files"); 147 | this.torrent.total_length = 0; 148 | for (int i = 0; i < multFiles.size(); i++) { 149 | this.torrent.length.add(((Long) ((Map) multFiles.get(i)). 150 | get("length")).intValue()); 151 | this.torrent.total_length += ((Long) ((Map) multFiles.get(i)). 152 | get("length")).intValue(); 153 | 154 | List path = (List) ((Map) multFiles.get(i)).get( 155 | "path"); 156 | String filePath = ""; 157 | for (int j = 0; j < path.size(); j++) { 158 | filePath += new String((byte[]) path.get(j)); 159 | } 160 | this.torrent.name.add(filePath); 161 | } 162 | } else { 163 | this.torrent.length.add(((Long) info.get("length")).intValue()); 164 | this.torrent.total_length = ((Long) info.get("length")).intValue(); 165 | this.torrent.name.add(new String((byte[]) info.get("name"))); 166 | } 167 | }else 168 | return null; 169 | return this.torrent; 170 | } 171 | 172 | /** 173 | * Sets the TorrentFile object of the Publisher equals to the given one 174 | * @param torr TorrentFile 175 | */ 176 | public void setTorrent(TorrentFile torr) { 177 | this.torrent = torr; 178 | } 179 | 180 | /** 181 | * Updates the TorrentFile object according to the given parameters 182 | * @param url The announce url 183 | * @param pLength The length of the pieces of the torrent 184 | * @param comment The comments for the torrent 185 | * @param encoding The encoding of the torrent 186 | * @param filename The path of the file to be added to the torrent 187 | */ 188 | public void setTorrentData(String url, int pLength, String comment, 189 | String encoding, String filename) { 190 | this.torrent.announceURL = url; 191 | this.torrent.pieceLength = pLength * 1024; 192 | this.torrent.createdBy = Constants.CLIENT; 193 | this.torrent.comment = comment; 194 | this.torrent.creationDate = System.currentTimeMillis(); 195 | this.torrent.encoding = encoding; 196 | this.addFile(filename); 197 | } 198 | 199 | /** 200 | * Updates the TorrentFile object according to the given parameters 201 | * @param url The announce url 202 | * @param pLength The length of the pieces of the torrent 203 | * @param comment The comments for the torrent 204 | * @param encoding The encoding of the torrent 205 | * @param name The name of the directory to save the files in 206 | * @param filenames The path of the file to be added to the torrent 207 | * @throws java.lang.Exception 208 | */ 209 | public void setTorrentData(String url, int pLength, String comment, 210 | String encoding, String name, List filenames) throws Exception { 211 | this.torrent.announceURL = url; 212 | this.torrent.pieceLength = pLength * 1024; 213 | this.torrent.comment = comment; 214 | this.torrent.createdBy = Constants.CLIENT; 215 | this.torrent.creationDate = System.currentTimeMillis(); 216 | this.torrent.encoding = encoding; 217 | this.torrent.saveAs = name; 218 | this.addFiles(filenames); 219 | } 220 | 221 | /** 222 | * Sets the announce url of the torrent 223 | * @param url String 224 | */ 225 | public void setAnnounceURL(String url) { 226 | this.torrent.announceURL = url; 227 | } 228 | 229 | /** 230 | * Sets the pieceLength 231 | * @param length int 232 | */ 233 | public void setPieceLength(int length) { 234 | this.torrent.pieceLength = length * 1024; 235 | } 236 | 237 | /** 238 | * Sets the directory the files have to be saved in (in case of multiple files torrent) 239 | * @param name String 240 | */ 241 | public void setName(String name) { 242 | this.torrent.saveAs = name; 243 | } 244 | 245 | /** 246 | * Sets the comment about this torrent 247 | * @param comment String 248 | */ 249 | public void setComment(String comment) { 250 | this.torrent.comment = comment; 251 | } 252 | 253 | /** 254 | * Sets the creator of the torrent. This should be the client name and version 255 | * @param creator String 256 | */ 257 | public void setCreator(String creator) { 258 | this.torrent.createdBy = creator; 259 | } 260 | 261 | /** 262 | * Sets the time the torrent was created 263 | * @param date long 264 | */ 265 | public void setCreationDate(long date) { 266 | this.torrent.creationDate = date; 267 | } 268 | 269 | /** 270 | * Sets the encoding of the torrent 271 | * @param encoding String 272 | */ 273 | public void setEncoding(String encoding) { 274 | this.torrent.encoding = encoding; 275 | } 276 | 277 | /** 278 | * Add the files in the list to the torrent 279 | * @param l A list containing the File or String object representing the files to be added 280 | * @return int The number of files that have been added 281 | * @throws Exception 282 | */ 283 | public int addFiles(List l) throws Exception { 284 | return this.addFiles(l.toArray()); 285 | } 286 | 287 | /** 288 | * Add the files in the list to the torrent 289 | * @param file The file to be added 290 | * @return int The number of file that have been added 291 | * @throws Exception 292 | */ 293 | public int addFile(File file) { 294 | return this.addFiles(new File[] {file}); 295 | } 296 | 297 | /** 298 | * Add the files in the list to the torrent 299 | * @param filename The path of the file to be added 300 | * @return int The number of file that have been added 301 | * @throws Exception 302 | */ 303 | public int addFile(String filename) { 304 | return this.addFiles(new String[] {filename}); 305 | } 306 | /** 307 | * Add the files in the list to the torrent 308 | * @param filenames An array containing the files to be added 309 | * @return int The number of files that have been added 310 | * @throws Exception 311 | */ 312 | public int addFiles(Object[] filenames) { 313 | int nbFileAdded = 0; 314 | 315 | if (this.torrent.total_length == -1) 316 | this.torrent.total_length = 0; 317 | 318 | File f = null; 319 | for (int i = 0; i < filenames.length; i++) { 320 | if (filenames[i] instanceof String) 321 | f = new File((String) filenames[i]); 322 | else if (filenames[i] instanceof File) 323 | f = (File) filenames[i]; 324 | if (f != null) 325 | if (f.exists()) { 326 | if(f.isDirectory()) 327 | { 328 | DirUtils du = new DirUtils(); 329 | 330 | List l = du.recurseDir(f.getAbsolutePath()); 331 | 332 | for(int j = 1; j < l.size(); j++) 333 | { 334 | String pth = null; 335 | 336 | pth = (String) l.get(j); 337 | 338 | File recursiveListFile = new File(pth); 339 | 340 | this.torrent.total_length += recursiveListFile.length(); 341 | this.torrent.name.add(pth); 342 | this.torrent.length.add(new Long(recursiveListFile.length()).intValue()); 343 | nbFileAdded++; 344 | } 345 | } 346 | else if(f.isFile()) 347 | { 348 | this.torrent.total_length += f.length(); 349 | this.torrent.name.add(f.getPath()); 350 | this.torrent.length.add(new Long(f.length()).intValue()); 351 | nbFileAdded++; 352 | } 353 | } 354 | } 355 | 356 | startLevel = f.getParent().split("/").length; 357 | 358 | return nbFileAdded; 359 | } 360 | 361 | /** 362 | * Generate the SHA-1 hashes for the file in the torrent in parameter 363 | * @param torr TorrentFile 364 | */ 365 | public void generatePieceHashes(TorrentFile torr) { 366 | ByteBuffer bb = ByteBuffer.allocate(torr.pieceLength); 367 | int index = 0; 368 | long total = 0; 369 | torr.piece_hash_values_as_binary.clear(); 370 | for (int i = 0; i < torr.name.size(); i++) { 371 | total += (Integer) torr.length.get(i); 372 | File f = new File((String) torr.name.get(i)); 373 | if (f.exists()) { 374 | try { 375 | FileInputStream fis = new FileInputStream(f); 376 | int read = 0; 377 | byte[] data = new byte[torr.pieceLength]; 378 | while ((read = fis.read(data, 0, bb.remaining())) != -1) { 379 | bb.put(data, 0, read); 380 | if (bb.remaining() == 0) { 381 | torr.piece_hash_values_as_binary.add(Utils.hash(bb. 382 | array())); 383 | bb.clear(); 384 | } 385 | } 386 | } catch (FileNotFoundException fnfe) {} catch (IOException ioe) {} 387 | } 388 | } 389 | if (bb.remaining() != bb.capacity()) 390 | torr.piece_hash_values_as_binary.add(Utils.hash(Utils.subArray( 391 | bb.array(), 0, bb.capacity() - bb.remaining()))); 392 | } 393 | /** 394 | * Generate the SHA-1 hashes for the files in the current object TorrentFile 395 | */ 396 | public void generatePieceHashes() { 397 | this.generatePieceHashes(this.torrent); 398 | } 399 | 400 | /** 401 | * Generate the bytes of the bencoded TorrentFile data 402 | * @param torr TorrentFile 403 | * @return byte[] 404 | */ 405 | public byte[] generateTorrent(TorrentFile torr) { 406 | SortedMap map = new TreeMap(); 407 | map.put("announce", torr.announceURL); 408 | if(torr.comment.length() > 0) 409 | map.put("comment", torr.comment); 410 | if(torr.creationDate >= 0) 411 | map.put("creation date", torr.creationDate); 412 | if(torr.createdBy.length() > 0) 413 | map.put("created by", torr.createdBy); 414 | SortedMap info = new TreeMap(); 415 | 416 | if (torr.name.size() == 1) { 417 | info.put("length", (Integer) torr.length.get(0)); 418 | info.put("name", new File((String) torr.name.get(0)).getName()); 419 | } else { 420 | if (!torr.saveAs.matches("")) 421 | info.put("name", torr.saveAs); 422 | else 423 | info.put("name", "noDirSpec"); 424 | 425 | ArrayList files = new ArrayList(); 426 | 427 | for (int i = 0; i < torr.name.size(); i++) { 428 | SortedMap file = new TreeMap(); 429 | String[] path = ((String) torr.name.get(i)).split("/"); 430 | File f = new File((String)(torr.name.get(i))); 431 | 432 | ArrayList pathLst = new ArrayList(); 433 | 434 | String tmp = "", pth = null; 435 | pth = (String) torr.name.get(i); 436 | long fileLength = new File(pth).length(); 437 | 438 | torr.length.set(i, (int) fileLength); 439 | file.put("length", torr.length.get(i)); 440 | 441 | String[] pthSplit = pth.split("/"); 442 | 443 | for(int c = startLevel; c < pthSplit.length; c++) 444 | { 445 | tmp += pthSplit[c]; 446 | 447 | pathLst.add(pthSplit[c]); 448 | } 449 | 450 | file.put("path", new ArrayList(pathLst)); 451 | files.add(new TreeMap(file)); 452 | } 453 | 454 | info.put("files", files); 455 | } 456 | info.put("piece length", torr.pieceLength); 457 | byte[] pieces = new byte[0]; 458 | for (int i = 0; i < torr.piece_hash_values_as_binary.size(); i++) 459 | pieces = Utils.concat(pieces, 460 | (byte[]) torr.piece_hash_values_as_binary. 461 | get(i)); 462 | info.put("pieces", pieces); 463 | map.put("info", info); 464 | 465 | try { 466 | byte[] data = BEncoder.encode(map); 467 | return data; 468 | } catch (Exception e) { 469 | e.printStackTrace(); 470 | } 471 | return null; 472 | } 473 | 474 | public class DirUtils 475 | { 476 | public List recurseDir(String dir) 477 | { 478 | String result, _result[]; 479 | 480 | result = recurseInDirFrom(dir); 481 | _result = result.split("\\|"); 482 | return Arrays.asList(_result); 483 | } 484 | 485 | private String recurseInDirFrom(String dirItem) 486 | { 487 | File file; 488 | String list[], result; 489 | 490 | result = dirItem; 491 | 492 | file = new File(dirItem); 493 | if(file.isDirectory()) 494 | { 495 | list = file.list(); 496 | for(int i = 0; i < list.length; i++) 497 | { 498 | result = result + "|" 499 | + recurseInDirFrom(dirItem + File.separatorChar + list[i]); 500 | } 501 | } 502 | return result; 503 | } 504 | } 505 | 506 | /** 507 | * Generate the bytes for the current object TorrentFile 508 | * @return byte[] 509 | */ 510 | public byte[] generateTorrent() { 511 | return this.generateTorrent(this.torrent); 512 | } 513 | 514 | /** 515 | * Returns the local TorrentFile in its current state 516 | * @return TorrentFile 517 | */ 518 | public TorrentFile getTorrent(){ 519 | return this.torrent; 520 | } 521 | 522 | } 523 | -------------------------------------------------------------------------------- /ULRateComparator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.util.*; 41 | 42 | /** 43 | * Compares 2 peers upload rate 44 | */ 45 | public class ULRateComparator implements Comparator { 46 | /** 47 | * Compares its two arguments for order. 48 | * 49 | * @param a the first object to be compared. 50 | * @param b the second object to be compared. 51 | * @return a negative integer, zero, or a positive integer as the first 52 | * argument is less than, equal to, or greater than the second. 53 | */ 54 | public int compare(Object a, Object b) { 55 | if (a instanceof Peer && b instanceof Peer) 56 | if (((Peer) a).getULRate(false) > ((Peer) b).getULRate(false)) 57 | return -1; 58 | else if (((Peer) a).getULRate(false) < ((Peer) b).getULRate(false)) 59 | return 1; 60 | return 0; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Utils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Java Bittorrent API as its name indicates is a JAVA API that implements the Bittorrent Protocol 3 | * This project contains two packages: 4 | * 1. jBittorrentAPI is the "client" part, i.e. it implements all classes needed to publish 5 | * files, share them and download them. 6 | * This package also contains example classes on how a developer could create new applications. 7 | * 2. trackerBT is the "tracker" part, i.e. it implements a all classes needed to run 8 | * a Bittorrent tracker that coordinates peers exchanges. * 9 | * 10 | * Copyright (C) 2007 Baptiste Dubuis, Artificial Intelligence Laboratory, EPFL 11 | * 12 | * This file is part of jbittorrentapi-v1.0.zip 13 | * 14 | * Java Bittorrent API is free software and a free user study set-up; 15 | * you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation; either version 2 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * Java Bittorrent API is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with Java Bittorrent API; if not, write to the Free Software 27 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 | * 29 | * @version 1.0 30 | * @author Baptiste Dubuis 31 | * To contact the author: 32 | * email: baptiste.dubuis@gmail.com 33 | * 34 | * More information about Java Bittorrent API: 35 | * http://sourceforge.net/projects/bitext/ 36 | */ 37 | 38 | package jBittorrentAPI; 39 | 40 | import java.security.NoSuchAlgorithmException; 41 | import java.security.MessageDigest; 42 | import java.util.*; 43 | import java.lang.*; 44 | import java.io.*; 45 | import java.nio.*; 46 | 47 | /** 48 | * A set of utility methods used by the program 49 | * 50 | * @author Baptiste Dubuis 51 | * @version 0.1 52 | */ 53 | public class Utils { 54 | 55 | /** 56 | * Convenience method to convert a byte to a hex string. 57 | * 58 | * @param data the byte to convert 59 | * @return String the converted byte 60 | */ 61 | public static String byteToHex(byte data) { 62 | StringBuffer buf = new StringBuffer(); 63 | buf.append(toHexChar((data >>> 4) & 0x0F)); 64 | buf.append(toHexChar(data & 0x0F)); 65 | return buf.toString(); 66 | } 67 | 68 | /** 69 | * Convenience method to convert a byte array to a hex string. 70 | * 71 | * @param data the byte[] to convert 72 | * @return String the converted byte[] 73 | */ 74 | public static String bytesToHex(byte[] data) { 75 | StringBuffer buf = new StringBuffer(); 76 | for (int i = 0; i < data.length; i++) { 77 | buf.append(byteToHex(data[i])); 78 | } 79 | return buf.toString(); 80 | } 81 | 82 | /** 83 | * Convenience method to convert an int to a hex char. 84 | * 85 | * @param i the int to convert 86 | * @return char the converted char 87 | */ 88 | public static char toHexChar(int i) { 89 | if ((0 <= i) && (i <= 9)) 90 | return (char) ('0' + i); 91 | else 92 | return (char) ('a' + (i - 10)); 93 | } 94 | 95 | /** 96 | * Convert a byte array to a URL encoded string 97 | * @param in byte[] 98 | * @return String 99 | */ 100 | public static String byteArrayToURLString(byte in[]) { 101 | byte ch = 0x00; 102 | int i = 0; 103 | if (in == null || in.length <= 0) 104 | return null; 105 | 106 | String pseudo[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 107 | "A", "B", "C", "D", "E", "F"}; 108 | StringBuffer out = new StringBuffer(in.length * 2); 109 | 110 | while (i < in.length) { 111 | // First check to see if we need ASCII or HEX 112 | if ((in[i] >= '0' && in[i] <= '9') 113 | || (in[i] >= 'a' && in[i] <= 'z') 114 | || (in[i] >= 'A' && in[i] <= 'Z') || in[i] == '$' 115 | || in[i] == '-' || in[i] == '_' || in[i] == '.' 116 | || in[i] == '!') { 117 | out.append((char) in[i]); 118 | i++; 119 | } else { 120 | out.append('%'); 121 | ch = (byte) (in[i] & 0xF0); // Strip off high nibble 122 | ch = (byte) (ch >>> 4); // shift the bits down 123 | ch = (byte) (ch & 0x0F); // must do this is high order bit is 124 | // on! 125 | out.append(pseudo[(int) ch]); // convert the nibble to a 126 | // String Character 127 | ch = (byte) (in[i] & 0x0F); // Strip off low nibble 128 | out.append(pseudo[(int) ch]); // convert the nibble to a 129 | // String Character 130 | i++; 131 | } 132 | } 133 | 134 | String rslt = new String(out); 135 | 136 | return rslt; 137 | 138 | } 139 | 140 | /** 141 | * 142 | * Convert a byte[] array to readable string format. This makes the "hex" 143 | * readable! 144 | * 145 | * @author Jeff Boyle 146 | * 147 | * @return result String buffer in String format 148 | * 149 | * @param in 150 | * byte[] buffer to convert to string format 151 | * 152 | */ 153 | // Taken from http://www.devx.com/tips/Tip/13540 154 | public static String byteArrayToByteString(byte in[]) { 155 | byte ch = 0x00; 156 | int i = 0; 157 | if (in == null || in.length <= 0) 158 | return null; 159 | 160 | String pseudo[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 161 | "A", "B", "C", "D", "E", "F"}; 162 | StringBuffer out = new StringBuffer(in.length * 2); 163 | 164 | while (i < in.length) { 165 | ch = (byte) (in[i] & 0xF0); // Strip off high nibble 166 | ch = (byte) (ch >>> 4); // shift the bits down 167 | ch = (byte) (ch & 0x0F); // must do this is high order bit is on! 168 | out.append(pseudo[(int) ch]); // convert the nibble to a String 169 | // Character 170 | ch = (byte) (in[i] & 0x0F); // Strip off low nibble 171 | out.append(pseudo[(int) ch]); // convert the nibble to a String 172 | // Character 173 | i++; 174 | } 175 | 176 | String rslt = new String(out); 177 | 178 | return rslt; 179 | } 180 | 181 | /** 182 | * Convert an integer value to its byte array representation 183 | * @param value int 184 | * @return byte[] 185 | */ 186 | public static byte[] intToByteArray(int value) { 187 | byte[] b = new byte[4]; 188 | for (int i = 0; i < 4; i++) { 189 | int offset = (b.length - 1 - i) * 8; 190 | b[i] = (byte) ((value >>> offset) & 0xFF); 191 | } 192 | return b; 193 | } 194 | 195 | /** 196 | * Convert a byte array integer (4 bytes) to its int value 197 | * @param b byte[] 198 | * @return int 199 | */ 200 | public static int byteArrayToInt(byte[] b) { 201 | if(b.length == 4) 202 | return b[0] << 24 | (b[1] & 0xff) << 16 | (b[2] & 0xff) << 8 | 203 | (b[3] & 0xff); 204 | else if(b.length == 2) 205 | return 0x00 << 24 | 0x00 << 16 | (b[0] & 0xff) << 8 | (b[1] & 0xff); 206 | 207 | return 0; 208 | } 209 | 210 | public static int byteToUnsignedInt(byte b){ 211 | return 0x00 << 24 | b & 0xff; 212 | } 213 | 214 | public static byte[] intToByteArray4(int i) { 215 | return new byte[] {(byte) (i >> 24), (byte) (i >> 16), (byte) (i >> 8), 216 | (byte) i}; 217 | } 218 | 219 | /** 220 | * Compute the SHA-1 hash of the bytes in the given buffer 221 | * @param hashThis ByteBuffer 222 | * @return byte[] 223 | */ 224 | public static byte[] hash(ByteBuffer hashThis){ 225 | try{ 226 | byte[] hash = new byte[20]; 227 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 228 | md.update(hashThis); 229 | return md.digest(); 230 | }catch(NoSuchAlgorithmException nsae){} 231 | return null; 232 | } 233 | 234 | /** 235 | * Compute the SHA-1 hash of the given byte array 236 | * @param hashThis byte[] 237 | * @return byte[] 238 | */ 239 | public static byte[] hash(byte[] hashThis) { 240 | try { 241 | byte[] hash = new byte[20]; 242 | MessageDigest md = MessageDigest.getInstance("SHA-1"); 243 | 244 | hash = md.digest(hashThis); 245 | return hash; 246 | } catch (NoSuchAlgorithmException nsae) { 247 | System.err.println("SHA-1 algorithm is not available..."); 248 | System.exit(2); 249 | } 250 | return null; 251 | } 252 | 253 | /** 254 | * Generate the client id, which is a fixed string of length 8 concatenated with 12 random bytes 255 | * @return byte[] 256 | */ 257 | public static byte[] generateID() { 258 | byte[] id = new byte[12]; 259 | 260 | Random r = new Random(System.currentTimeMillis()); 261 | r.nextBytes(id); 262 | return Utils.concat("-BE0001-".getBytes(),id); 263 | } 264 | 265 | /** 266 | * Concatenate the 2 byte arrays 267 | * @param a byte[] 268 | * @param b byte[] 269 | * @return byte[] 270 | */ 271 | public static byte[] concat2(byte[] a, byte[] b) { 272 | ByteBuffer bb = ByteBuffer.allocate(a.length + b.length); 273 | bb.put(a); 274 | bb.put(b); 275 | return bb.array(); 276 | } 277 | /** 278 | * Concatenate the 2 byte arrays 279 | * @param b1 byte[] 280 | * @param b2 byte[] 281 | * @return byte[] 282 | */ 283 | public static byte[] concat(byte[] b1, byte[] b2) { 284 | byte[] b3 = new byte[b1.length + b2.length]; 285 | System.arraycopy(b1, 0, b3, 0, b1.length); 286 | System.arraycopy(b2, 0, b3, b1.length, b2.length); 287 | return b3; 288 | } 289 | 290 | /** 291 | * Concatenate the byte array and the byte 292 | * @param b1 byte[] 293 | * @param b2 byte 294 | * @return byte[] 295 | */ 296 | public static byte[] concat(byte[] b1, byte b2) { 297 | byte[] b3 = new byte[b1.length + 1]; 298 | byte[] temp = new byte[] {b2}; 299 | System.arraycopy(b1, 0, b3, 0, b1.length); 300 | System.arraycopy(temp, 0, b3, b1.length, 1); 301 | return b3; 302 | } 303 | 304 | /** 305 | * Convert a byte array representing an unsigned integer (4bytes) to its long value 306 | * @param b byte[] 307 | * @return long 308 | */ 309 | public static final long unsignedIntToLong(byte[] b) { 310 | long l = 0; 311 | l |= b[0] & 0xFF; 312 | l <<= 8; 313 | l |= b[1] & 0xFF; 314 | l <<= 8; 315 | l |= b[2] & 0xFF; 316 | l <<= 8; 317 | l |= b[3] & 0xFF; 318 | return l; 319 | } 320 | 321 | /** 322 | * Convert a byte array to a boolean array. Bit 0 is represented with false, Bit 1 is represented with 1 323 | * @param bytes byte[] 324 | * @return boolean[] 325 | */ 326 | public static boolean[] byteArray2BitArray(byte[] bytes) { 327 | boolean[] bits = new boolean[bytes.length*8]; 328 | for (int i = 0; i < bytes.length * 8; i++) { 329 | if ((bytes[i / 8] & (1 << (7 -(i % 8)))) > 0) 330 | bits[i] = true; 331 | } 332 | return bits; 333 | } 334 | 335 | /** 336 | * Return a subarray of the byte array in parameter. 337 | * @param b The original array 338 | * @param offset Begin index of the subarray 339 | * @param length Length of the subarray 340 | * @return byte[] 341 | */ 342 | public static byte[] subArray(byte[] b, int offset, int length){ 343 | byte[] sub = new byte[length]; 344 | for(int i = offset; i < offset + length; i++) 345 | sub[i-offset] = b[i]; 346 | return sub; 347 | } 348 | /** 349 | * Compare 2 byte arrays byte to byte 350 | * @param a byte[] 351 | * @param b byte[] 352 | * @return boolean 353 | */ 354 | public static boolean bytesCompare(byte[] a, byte[] b){ 355 | if(a.length != b.length) 356 | return false; 357 | for(int i = 0; i < a.length; i++) 358 | if(a[i] != b[i]) 359 | return false; 360 | return true; 361 | } 362 | 363 | /** 364 | * Copy the input byte array to the output byte array 365 | * @param in byte[] 366 | * @param out byte[] 367 | */ 368 | public static void copy(byte[] in, byte[] out){ 369 | for(int i = 0; i < out.length && i < in.length; i++) 370 | out[i] = in[i]; 371 | } 372 | 373 | public static byte[] toByteArray(BitSet bits) { 374 | byte[] bytes = new byte[bits.length() / 8 + 1]; 375 | for (int i = 0; i < bits.length(); i++) { 376 | if (bits.get(i)) { 377 | bytes[i / 8] |= 1 << (7 - i % 8); 378 | } 379 | } 380 | return bytes; 381 | } 382 | 383 | } 384 | --------------------------------------------------------------------------------