-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPeerTopology.java
More file actions
198 lines (168 loc) · 7.5 KB
/
Copy pathPeerTopology.java
File metadata and controls
198 lines (168 loc) · 7.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
import java.util.*;
import java.net.*;
import java.io.*;
public class PeerTopology {
// N = 16
// port ranges from 52320 to 52339
// Using a universal port 52322 among the peers
private int port;
// The UDP Socket for the protocol
private DatagramSocket udpSocket;
// A buffered list of packets listing available hosts to be processed
private ArrayList<DatagramPacket> peerPacketBuffer;
// A string of available hosts
private ArrayList<String> availablePeers = new ArrayList<String>();
// A string of available hosts with port numbers
private ArrayList<String> availablePeerPorts = new ArrayList<String>();
public PeerTopology(int port) {
this.port = port;
this.peerPacketBuffer = new ArrayList<DatagramPacket>();
this.availablePeers = new ArrayList<String>();
this.availablePeerPorts = new ArrayList<String>();
// Leave the UDP peer discovery channel available in the background
new Thread(new Runnable() {
public void run() {
socketInit();
}
}).start();
// Send out the UDP discovery packet to the broadcast address
broadcast();
}
/**
* The function that initializes the UDP socket
*/
public void socketInit() {
try {
// Creating the UDP socket
udpSocket = new DatagramSocket(port);
udpSocket.setBroadcast(true);
// Set up the socket readily available for peer discovery
// If the request buffer has packets, the program parses the packets
System.out.println("UDP Socket Initialized, waiting for UDP response from other peers...");
while (receivedPacket());
}
catch (SocketException e) {
System.out.println("Error accessing socket on port " + port);
}
catch (IOException e) {
System.out.println("Error receiving incoming message from socket on port " + port);
}
}
/**
* The function that broadcasts the discovery message
*/
public void broadcast() {
try {
// Wait 0.5 sec to initialize the server
Thread.sleep(500);
// Define the broadcast IP address
InetAddress broadcastIP = InetAddress.getByName("255.255.255.255");
// Compose the peer discovery message and create the packet
byte[] peerDiscoveryReq = "Discovery Msg".getBytes();
DatagramPacket peerDiscoveryPacket = new DatagramPacket(peerDiscoveryReq, peerDiscoveryReq.length, broadcastIP, port);
// Send out the peer discovery packet to the broadcast IP address
System.out.println("Broadcasting UDP discovery message...");
udpSocket.send(peerDiscoveryPacket);
}
catch (UnknownHostException e) {
System.out.println("Error: failed to broadcast to destination 255.255.255.255");
}
catch (IOException e) {
System.out.println("Error receiving incoming message from socket on port " + port);
}
catch (InterruptedException e) {
System.out.println("Error: Failed to initialize thread");
}
catch (NullPointerException e) {
System.out.println("Error: Check if the socket is already in use");
}
}
/**
* The function that receives the incoming packet from the socket
* @return true when the packet properly received and queued in the appropriate buffer
* @throws IOException when the socket cannot properly receive the packet data
* @throws SocketException when the socket cannot be accessed
*/
public boolean receivedPacket() throws IOException, SocketException {
// Create the packet for the incoming message and receive the packet
byte[] rxData = new byte[2048];
DatagramPacket incomingPacket = new DatagramPacket(rxData, rxData.length);
udpSocket.receive(incomingPacket);
// Parse the packet if it is a request for ACK, or queue the ACK into the buffer
if (new String(incomingPacket.getData()).charAt(0) == 'D')
parseRequestPacket(incomingPacket);
else
peerPacketBuffer.add(incomingPacket);
// returns true if the above process is successful
return true;
}
/**
* Parse the packets in the request buffer by sending out an acknowledgment
* @param packet the packet received from the socket with the discovery message
*/
public void parseRequestPacket(DatagramPacket packet) {
sendAck(packet.getAddress(), packet.getPort());
}
/**
* Parse the packets in the peer buffer by translating the addresses and ports into array lists of String
*/
public void parseAllPeerPackets() {
for (DatagramPacket packet : peerPacketBuffer) {
// The IP address of the sender who sent the ACK
availablePeers.add(packet.getAddress().toString().substring(1));
// The port number is included in the data portion of the ACK
availablePeerPorts.add(new String(packet.getData()));
}
}
/**
* The method that sends an acknowledgment back to the sender
* @param ipAddr the IP address of the sender in the format of InetAddress
* @param udpPort the port number used by the sender in the format of int
*/
public void sendAck(InetAddress ipAddr, int udpPort) {
try {
// Update the current list of available ports from the TCP socket controller
//ParseFile.updateAvailablePorts();
// For each available port on the local machine, the protocol sends out an acknowledgment back to the remote peer
for (TcpSocket tcpPort : TcpSocketController.availableTcpSockets) {
// The data sent contains the available port number
byte[] peerData = Integer.toString(tcpPort.getLocalPort()).getBytes();
DatagramPacket availablePeerPacket = new DatagramPacket(peerData, peerData.length, ipAddr, udpPort);
udpSocket.send(availablePeerPacket);
}
}
catch (UnknownHostException e) {
System.out.println("Error: failed to send packet to destination " + ipAddr.toString().substring(1));
}
catch (IOException e) {
System.out.println("Error receiving incoming message from socket on port " + port);
}
catch (NullPointerException e) {
System.out.println("Error: Check if the socket is already in use");
}
}
/**
* The method that returns an array list of formatted IP addresses and ports of available peers
* @return an array list of string that contains the information of available peers
*/
public ArrayList<String> getPeer() {
parseAllPeerPackets();
ArrayList<String> availablePeersFormatted = new ArrayList<String>();
for (int i = 0; i < peerPacketBuffer.size(); i++) {
String ipAddrPortFormatted = "";
// Remove the packet sent back to oneself by the broadcast
// The string format is as follows: "<IP address>:<port>"
if (!availablePeers.get(i).equals(NetworkUtil.getOwnExternalIp())) {
ipAddrPortFormatted += availablePeers.get(i) + ":" + availablePeerPorts.get(i);
availablePeersFormatted.add(ipAddrPortFormatted);
}
}
return availablePeersFormatted;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
}