diff --git a/.classpath b/.classpath deleted file mode 100644 index 52f234a..0000000 --- a/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/.project b/.project deleted file mode 100644 index 858ec5e..0000000 --- a/.project +++ /dev/null @@ -1,28 +0,0 @@ - - - p2pfilesharing - - - - - - org.eclipse.jdt.core.javabuilder - - - - - - org.eclipse.jdt.core.javanature - - - - 1759349142872 - - 30 - - org.eclipse.core.resources.regexFilterMatcher - node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ - - - - diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 99f26c0..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 6f94d6a..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,11 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=23 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=23 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled -org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning -org.eclipse.jdt.core.compiler.release=enabled -org.eclipse.jdt.core.compiler.source=23 diff --git a/bin/Main/Main.class b/bin/Main/Main.class deleted file mode 100644 index 92ad32b..0000000 Binary files a/bin/Main/Main.class and /dev/null differ diff --git a/bin/discovery/CentralRegistry.class b/bin/discovery/CentralRegistry.class deleted file mode 100644 index 3ab951f..0000000 Binary files a/bin/discovery/CentralRegistry.class and /dev/null differ diff --git a/bin/discovery/FileData.class b/bin/discovery/FileData.class deleted file mode 100644 index 61e25a1..0000000 Binary files a/bin/discovery/FileData.class and /dev/null differ diff --git a/bin/discovery/Handshake.class b/bin/discovery/Handshake.class deleted file mode 100644 index ec2271e..0000000 Binary files a/bin/discovery/Handshake.class and /dev/null differ diff --git a/bin/discovery/Node.class b/bin/discovery/Node.class deleted file mode 100644 index 0900bd9..0000000 Binary files a/bin/discovery/Node.class and /dev/null differ diff --git a/bin/discovery/messages/CentralRegistryRequest.class b/bin/discovery/messages/CentralRegistryRequest.class deleted file mode 100644 index c0f0c46..0000000 Binary files a/bin/discovery/messages/CentralRegistryRequest.class and /dev/null differ diff --git a/bin/discovery/messages/CentralRegistryResponse.class b/bin/discovery/messages/CentralRegistryResponse.class deleted file mode 100644 index 3647f13..0000000 Binary files a/bin/discovery/messages/CentralRegistryResponse.class and /dev/null differ diff --git a/bin/discovery/messages/FileRequest.class b/bin/discovery/messages/FileRequest.class deleted file mode 100644 index 8c9e1b4..0000000 Binary files a/bin/discovery/messages/FileRequest.class and /dev/null differ diff --git a/bin/discovery/messages/FileResponse.class b/bin/discovery/messages/FileResponse.class deleted file mode 100644 index 67275d8..0000000 Binary files a/bin/discovery/messages/FileResponse.class and /dev/null differ diff --git a/bin/discovery/messages/TransferRequest.class b/bin/discovery/messages/TransferRequest.class deleted file mode 100644 index 222d55d..0000000 Binary files a/bin/discovery/messages/TransferRequest.class and /dev/null differ diff --git a/bin/discovery/messages/TransferResponse.class b/bin/discovery/messages/TransferResponse.class deleted file mode 100644 index 8166786..0000000 Binary files a/bin/discovery/messages/TransferResponse.class and /dev/null differ diff --git a/bin/module-info.class b/bin/module-info.class deleted file mode 100644 index 79cac06..0000000 Binary files a/bin/module-info.class and /dev/null differ diff --git a/bin/p2p/ConnectionHandlerParallel.class b/bin/p2p/ConnectionHandlerParallel.class deleted file mode 100644 index 244fa0a..0000000 Binary files a/bin/p2p/ConnectionHandlerParallel.class and /dev/null differ diff --git a/bin/p2p/ConnectionHandlerSequential.class b/bin/p2p/ConnectionHandlerSequential.class deleted file mode 100644 index 0a30214..0000000 Binary files a/bin/p2p/ConnectionHandlerSequential.class and /dev/null differ diff --git a/bin/p2p/FileTransfer.class b/bin/p2p/FileTransfer.class deleted file mode 100644 index fe896c9..0000000 Binary files a/bin/p2p/FileTransfer.class and /dev/null differ diff --git a/bin/p2p/ObjectTransfer.class b/bin/p2p/ObjectTransfer.class deleted file mode 100644 index 84ba96a..0000000 Binary files a/bin/p2p/ObjectTransfer.class and /dev/null differ diff --git a/bin/utils/FileTransfer.class b/bin/utils/FileTransfer.class deleted file mode 100644 index a1ce32e..0000000 Binary files a/bin/utils/FileTransfer.class and /dev/null differ diff --git a/config.properties b/config.properties index 2ee1808..e5a37f1 100644 --- a/config.properties +++ b/config.properties @@ -1,2 +1,12 @@ test.dir=./src/test downloads.dir=./src/downloads + +#Defaults +beacon.port=12344 +broadcast.group=255.255.255.255 +broadcast.port=12345 +broadcast.chunk_bytes=1024 +broadcast.max_rounds=3 +broadcast.nack_port=50011 +broadcast.nack_delay_ms=200 +broadcast.wait_nacks_ms=250 diff --git a/src/Main/Main.java b/src/Main/Main.java index 0c5e865..6b120f5 100644 --- a/src/Main/Main.java +++ b/src/Main/Main.java @@ -113,7 +113,7 @@ public static void main(String[] args) throws IOException { Scanner scanner = new Scanner(System.in); - System.out.print("Enter command (upload or download ): "); + System.out.print("Enter command (upload | download | broadcastfile | broadcastrecieve ): "); while (true) { @@ -149,14 +149,11 @@ public static void main(String[] args) throws IOException { break; case "broadcastfile": - FileData f = new FileData(argument); - - System.out.println("The File Hash of the File to be broadcasted is " + f.getFileHash()); - System.out.println("Type broadcast to enter broadcasting period"); - - userInput = scanner.nextLine().trim(); - BroadCastTransfer.BroadcastFile(f , Handshake.getClient() , argument); - break; + + FileData f = new FileData(argument); + System.out.println("The File Hash of the File to be broadcasted is " + f.getFileHash()); + BroadCastTransfer.BroadcastFile(f , Handshake.getClient() , argument); + break; case "broadcastrecieve": BroadCastTransfer.RecieveFile(argument); diff --git a/src/p2p/BroadCastTransfer.java b/src/p2p/BroadCastTransfer.java index 16a9ebe..a104860 100644 --- a/src/p2p/BroadCastTransfer.java +++ b/src/p2p/BroadCastTransfer.java @@ -11,6 +11,16 @@ import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.Random; +import java.nio.charset.StandardCharsets; + import discovery.FileData; import discovery.Node; @@ -20,11 +30,49 @@ public class BroadCastTransfer { - public static int broadcastListeningPort = 12345; - private static int BUFFER_SIZE = 1024; - public static int broadCastCountDefault = 1; //anybody that misses the beacon would miss the file transfer + public static int broadcastListeningPort = Config.getBroadcastPort(); + private static int BUFFER_SIZE = 1024; + public static int broadCastCountDefault = 3; //anybody that misses the beacon would miss the file transfer public static int congestionControlSleepTime = 30; public static int congestionControlSleepPacketCount = 400; + + static final byte FLAG_DATA = 0x01; + static final byte FLAG_EOB = 0x02; // End Of Broadcast (marker after first pass) + + // Make a packet with header and data + static ByteBuffer makePkt(int sessionId, int seq, int total, byte flag, byte[] data) + { + int body = (data == null ? 0 : data.length); + ByteBuffer bb = ByteBuffer.allocate(1 + 4 + 4 + 4 + body); + bb.put(flag); // 1 + bb.putInt(sessionId); // 4 + bb.putInt(seq); // 4 + bb.putInt(total); // 4 + if (body > 0) bb.put(data); + bb.flip(); + return bb; + } + + // Parse a received packet + static class Parsed + { + byte flag; int sid; int seq; int total; byte[] data; + } + static Parsed parsePkt(byte[] buf, int len) + { + ByteBuffer bb = ByteBuffer.wrap(buf, 0, len); + Parsed p = new Parsed(); + p.flag = bb.get(); + p.sid = bb.getInt(); + p.seq = bb.getInt(); + p.total = bb.getInt(); + int remain = bb.remaining(); + p.data = new byte[remain]; + bb.get(p.data); + return p; + } + + public static void BroadcastFile(FileData f, Node client , String filePath) { try { @@ -42,62 +90,155 @@ public static void BroadcastFile(FileData f, Node client , String filePath) { socket.setBroadcast(true); // Enable broadcasting // Define the broadcast address - InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255"); + InetAddress broadcastAddress = InetAddress.getByName(Config.getBroadcastGroup()); + + //NACK Listener + int nackPort = Config.getBroadcastNackPort(); + int waitNacksMs = Config.getBroadcastWaitNacksMs(); + int maxRounds = Config.getBroadcastMaxRounds(); + + DatagramSocket nackSocket = new DatagramSocket(nackPort); + nackSocket.setSoTimeout(waitNacksMs); // Open the file to read File file = new File(filePath); FileInputStream fileInputStream = new FileInputStream(file); - byte[] buffer = new byte[BUFFER_SIZE]; + + byte[] buf = new byte[BUFFER_SIZE]; + List slices = new ArrayList<>(); int bytesRead; + while ((bytesRead = fileInputStream.read(buf)) != -1) { + byte[] chunk = new byte[bytesRead]; + System.arraycopy(buf, 0, chunk, 0, bytesRead); + slices.add(chunk); + } + fileInputStream.close(); + + int totalPackets = slices.size(); // Total number of packets to send + int sessionId = (int)(System.nanoTime() & 0x7fffffff); // Random session ID // Send the file in chunks - int sequenceNumber = 0; + //int sequenceNumber = 0; long totalSize = f.getFileSize(); long sentSize = 0; - while ((bytesRead = fileInputStream.read(buffer)) != -1) { + + for (int sequenceNumber =0; sequenceNumber < totalPackets; sequenceNumber++) + { + byte[] chunk = slices.get(sequenceNumber); // Create a packet with the chunk and sequence number ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); dataOutputStream.writeInt(sequenceNumber); // Add sequence number - dataOutputStream.write(buffer, 0, bytesRead); // Add the chunk + dataOutputStream.write(chunk); // Add the chunk byte[] packetData = byteArrayOutputStream.toByteArray(); + ByteBuffer pkt = makePkt(sessionId, sequenceNumber, totalPackets, FLAG_DATA, packetData); // Create packet with header + // Send the packet - DatagramPacket packet = new DatagramPacket(packetData, packetData.length, broadcastAddress, BroadCastTransfer.broadcastListeningPort); + DatagramPacket packet = new DatagramPacket(pkt.array(), pkt.remaining(), broadcastAddress, BroadCastTransfer.broadcastListeningPort); socket.send(packet); - sentSize += bytesRead; - sequenceNumber++; + sentSize += chunk.length; UserExperience.printProgressBar(sentSize, totalSize); - if(sequenceNumber%BroadCastTransfer.congestionControlSleepPacketCount == 0) { + if(sequenceNumber%BroadCastTransfer.congestionControlSleepPacketCount == 0 && sequenceNumber != 0) { // Congestion control Thread.sleep(BroadCastTransfer.congestionControlSleepTime); } } // Send an end-of-file packet - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); - dataOutputStream.writeInt(-1); // Special sequence number to indicate EOF - byte[] eofPacketData = byteArrayOutputStream.toByteArray(); - DatagramPacket eofPacket = new DatagramPacket(eofPacketData, eofPacketData.length, broadcastAddress, BroadCastTransfer.broadcastListeningPort); - socket.send(eofPacket); + { + ByteBuffer eob = makePkt(sessionId, -1, totalPackets, FLAG_EOB, null); // EOB packet + DatagramPacket eofPacket = new DatagramPacket(eob.array(), eob.remaining(), broadcastAddress, BroadCastTransfer.broadcastListeningPort); + socket.send(eofPacket);// Send EOB packet + } + + System.out.println("File broadcast complete (pass 1). Listening for NACKs..."); + + // Listen for NACKs and resend missing packets + + for (int round = 0; round < maxRounds; round++) + { + long deadline = System.currentTimeMillis() + waitNacksMs; + Set toRetransmit = new TreeSet<>(); + while (System.currentTimeMillis() < deadline) + { + try + { + byte[] nbuf = new byte[2048]; + DatagramPacket ndp = new DatagramPacket(nbuf, nbuf.length); + nackSocket.receive(ndp); + + String msg = new String(ndp.getData(), 0, ndp.getLength(), StandardCharsets.UTF_8); + // Expected: "NACK;;" + if (!msg.startsWith("NACK;")) continue; + String[] parts = msg.split(";", 3); + if (parts.length < 2) continue; + int sid = Integer.parseInt(parts[1].trim()); + if (sid != sessionId) continue; + + if (parts.length == 3 && !parts[2].isEmpty()) { + String[] seqs = parts[2].split(","); + for (String s : seqs) { + s = s.trim(); + if (!s.isEmpty()) toRetransmit.add(Integer.parseInt(s)); + } + } + } catch (IOException e) { + // timeout or transient; break the inner wait loop + break; + } + } + + if (toRetransmit.isEmpty()) { + System.out.println("No NACKs in round " + (round + 1) + ". Done."); + break; + } + + System.out.println("Round " + (round + 1) + " retransmitting: " + toRetransmit); + + // Re-broadcast missing chunks + for (int seq : toRetransmit) { + if (seq < 0 || seq >= totalPackets) continue; + byte[] chunk = slices.get(seq); - System.out.println("File broadcast complete."); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeInt(seq); + dos.write(chunk); + byte[] legacyPayload = baos.toByteArray(); + + ByteBuffer pkt = makePkt(sessionId, seq, totalPackets, FLAG_DATA, legacyPayload); + DatagramPacket dp = new DatagramPacket(pkt.array(), pkt.remaining(), broadcastAddress, BroadCastTransfer.broadcastListeningPort); + socket.send(dp); + } + + // Re-send EOB to trigger final hole checks at receivers + ByteBuffer eob = makePkt(sessionId, -1, totalPackets, FLAG_EOB, null); + socket.send(new DatagramPacket(eob.array(), eob.remaining(), broadcastAddress, BroadCastTransfer.broadcastListeningPort)); + } + + System.out.println("Broadcast (with repairs) complete."); // Clean up - fileInputStream.close(); socket.close(); - } catch (IOException | InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - - } + nackSocket.close(); + + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + } + + public static void RecieveFile(String fileHash) { BroadcastBeacon beacon = (BroadcastBeacon)ObjectTransfer.recieveObjectBroadcast(); - + if (beacon == null) // + { + System.err.println("Failed to receive beacon (null). Is the sender running and on the same LAN?"); + return; + } + long totalSize = beacon.file.getFileSize(); if(beacon.file.getFileHash().equals(fileHash)) { @@ -107,43 +248,86 @@ public static void RecieveFile(String fileHash) { // Open the file to write String outputFilePath = new java.io.File(Config.getDownloadsDir(), beacon.file.getFileName()).getPath(); - FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath); - byte[] buffer = new byte[BUFFER_SIZE]; + //FileOutputStream fileOutputStream = new FileOutputStream(outputFilePath); + byte[] bigBuf = new byte[65535]; // Max UDP packet size long recvSize = 0; + + // Buffer chunks by sequence number (so out-of-order doesn’t corrupt the file) + Map bufferBySeq = new HashMap<>(); + int expectedTotal = -1; + int sessionId = -1; + + // For NACKs + int nackPort = Config.getBroadcastNackPort(); + int nackDelayMs = Config.getBroadcastNackDelayMs(); + Random jitter = new Random(); // Receive packets and write to file while (true) { - DatagramPacket packet = new DatagramPacket(buffer, buffer.length); + DatagramPacket packet = new DatagramPacket(bigBuf, bigBuf.length); socket.receive(packet); + // Parse reliability header + Parsed p = parsePkt(packet.getData(), packet.getLength()); + if (sessionId == -1) sessionId = p.sid; + // Extract sequence number and data - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packet.getData()); - DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream); - int sequenceNumber = dataInputStream.readInt(); - - if (sequenceNumber == -1) { - // End-of-file packet received - System.out.println("End of file received."); - break; - } - - // Write the chunk to the file - int bytesRead = packet.getLength() - 4; // Subtract 4 bytes for the sequence number - byte[] chunk = new byte[bytesRead]; - dataInputStream.readFully(chunk); - fileOutputStream.write(chunk); - recvSize += bytesRead; - - UserExperience.printProgressBar(recvSize, totalSize); - - } - - // Clean up - fileOutputStream.close(); - socket.close(); - } catch (Exception e) { - e.printStackTrace(); - } - - } - } + if (p.flag == FLAG_DATA) { + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(p.data); // FIXED: p.data + DataInputStream dataInputStream = new DataInputStream(byteArrayInputStream); + int sequenceNumber = dataInputStream.readInt(); + int payloadLen = p.data.length - 4; + byte[] chunk = new byte[payloadLen]; + dataInputStream.readFully(chunk); + + if (!bufferBySeq.containsKey(sequenceNumber)) { + bufferBySeq.put(sequenceNumber, chunk); + recvSize += chunk.length; + UserExperience.printProgressBar(recvSize, totalSize); + } + + if (expectedTotal < 0) expectedTotal = p.total; + + } else if (p.flag == FLAG_EOB) { + if (expectedTotal < 0) expectedTotal = p.total; + + List missing = new ArrayList<>(); + for (int i = 0; i < expectedTotal; i++) { + if (!bufferBySeq.containsKey(i)) missing.add(i); + } + + if (missing.isEmpty()) { + try (FileOutputStream fos = new FileOutputStream(outputFilePath)) { + for (int i = 0; i < expectedTotal; i++) { + fos.write(bufferBySeq.get(i)); + } + } + System.out.println("End of file received (complete)."); + socket.close(); + return; + } else { + int delay = jitter.nextInt(Math.max(1, nackDelayMs)); + try { Thread.sleep(delay); } catch (InterruptedException ignored) {} + + missing.removeIf(bufferBySeq::containsKey); + + if (!missing.isEmpty()) { + String body = String.join(",", missing.stream().map(String::valueOf).toArray(String[]::new)); + String msg = "NACK;" + sessionId + ";" + body; + byte[] m = msg.getBytes(StandardCharsets.UTF_8); + DatagramPacket ndp = new DatagramPacket(m, m.length, InetAddress.getByName(Config.getBroadcastGroup()), nackPort); + DatagramSocket ns = new DatagramSocket(); + ns.setBroadcast(true); + ns.send(ndp); + ns.close(); + } + } + } + } + + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } diff --git a/src/p2p/ObjectTransfer.java b/src/p2p/ObjectTransfer.java index 7269ef4..c2f57ff 100644 --- a/src/p2p/ObjectTransfer.java +++ b/src/p2p/ObjectTransfer.java @@ -6,8 +6,16 @@ import java.net.InetAddress; import java.net.Socket; +import utils.Config; + public class ObjectTransfer { - public static int broadCastListeningPort = 12345; + + public static int broadCastListeningPort = Config.getBeaconPort(); + private static final String BROADCAST_GROUP = Config.getBroadcastGroup(); + + private static final int MAX_UDP_PAYLOAD = 65507; + private static final int RECV_BUFFER = 65535; + public static void sendObject(Socket socket, Object object) throws IOException { // Create an ObjectOutputStream to send the object ObjectOutputStream outputStream = new ObjectOutputStream(socket.getOutputStream()); @@ -26,7 +34,7 @@ public static Object receiveObject(Socket socket) throws IOException, ClassNotFo } public static void sendObjectBroadcast(Object obj) { - try { + try { // Serialize the object ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); @@ -36,27 +44,31 @@ public static void sendObjectBroadcast(Object obj) { objectOutputStream.close(); byteArrayOutputStream.close(); + // + if (serializedObject.length > MAX_UDP_PAYLOAD) { + System.err.println("[ObjectTransfer] Serialized object too large for a single UDP packet (" + + serializedObject.length + " > " + MAX_UDP_PAYLOAD + ")."); + return; + } + // Create a UDP socket - DatagramSocket socket = new DatagramSocket(); + try(DatagramSocket socket = new DatagramSocket()){ socket.setBroadcast(true); // Enable broadcasting // Define the broadcast address and port - InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255"); - + InetAddress broadcastAddress = InetAddress.getByName(BROADCAST_GROUP.trim()); // Create a DatagramPacket with the serialized object DatagramPacket packet = new DatagramPacket(serializedObject, serializedObject.length, broadcastAddress, ObjectTransfer.broadCastListeningPort); // Send the packet socket.send(packet); + } System.out.println("Object broadcasted successfully!"); - - // Close the socket - socket.close(); - } catch (Exception e) { - e.printStackTrace(); + }catch (Exception e){ + e.printStackTrace(); + } } - } public static Object recieveObjectBroadcast() { try { @@ -64,7 +76,7 @@ public static Object recieveObjectBroadcast() { DatagramSocket socket = new DatagramSocket(ObjectTransfer.broadCastListeningPort); // Listen on the same port // Buffer to store incoming data - byte[] buffer = new byte[1024]; + byte[] buffer = new byte[RECV_BUFFER]; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); // Receive the packet @@ -73,7 +85,7 @@ public static Object recieveObjectBroadcast() { System.out.println("Object received!"); // Deserialize the object - ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packet.getData()); + ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(packet.getData(), 0, packet.getLength()); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); Object receivedObject = objectInputStream.readObject(); objectInputStream.close(); diff --git a/src/utils/Config.java b/src/utils/Config.java index 6b1608d..fcad39c 100644 --- a/src/utils/Config.java +++ b/src/utils/Config.java @@ -24,6 +24,41 @@ public final class Config { private Config() {} + // Getters for broadcast properties + public static String getBroadcastGroup() + { + return PROPERTIES.getProperty("broadcast.group","255.255.255.255").trim(); + } + public static int getBroadcastPort() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.port","50010")); + } + public static int getBroadcastChunkBytes() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.chunk_bytes","4096")); + } + public static int getBroadcastMaxRounds() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.max_rounds","3")); + } + public static int getBroadcastNackPort() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.nack_port","50011")); + } + public static int getBroadcastNackDelayMs() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.nack_delay_ms","200")); + } + public static int getBroadcastWaitNacksMs() + { + return Integer.parseInt(PROPERTIES.getProperty("broadcast.wait_nacks_ms","250")); + } + public static int getBeaconPort() + { + return Integer.parseInt(PROPERTIES.getProperty("beacon.port", "12344")); + } + + // Getters for directory paths public static String getTestDir() { String dir = PROPERTIES.getProperty("test.dir", DEFAULT_TEST_DIR); ensureDirectory(dir);