Now then, final report?
[packetlaptime.git] / UDPNode.java
blobaa5a0304e90f28cabdeb52cce9b3cf7358224c0d
1 /*
2 * @(#)UDPNode.java
3 * Time-stamp: "2007-11-06 18:12:55 anton"
4 */
6 import java.io.FileWriter;
7 import java.io.BufferedWriter;
8 import java.io.IOException;
10 import java.net.InetAddress;
11 import java.net.DatagramSocket;
12 import java.net.DatagramPacket;
13 import java.net.SocketException;
15 /**
16 * UDPNode – a node in a UDP packet ring.
18 * @author "Anton Johansson" <anton.johansson@gmail.com>
19 * @author "Victor Zamanian" <victor.zamanian@gmail.com>
21 public class UDPNode extends Node {
23 // This node's socket
24 private DatagramSocket mySocket = null;
26 /**
27 * Creates a new UDPNode instance with all necessary information.
29 * @param localPort the local port to listen to
30 * @param nextHost the host to connect to
31 * @param nextPort the port that <code>nextHost</code> listens to
32 * @param logger determines if this node should log lap-times
34 public UDPNode(int localPort,
35 InetAddress nextHost,
36 int nextPort,
37 boolean logger) {
39 // initiate fields
40 super(localPort, nextHost, nextPort, logger);
41 // open a DatagramSocket
42 try {
43 this.mySocket = new DatagramSocket(localPort);
45 catch (SocketException e) {
46 System.out.println(e);
47 System.exit(1);
50 // if this node is a logging node
51 if (isLogger) {
52 logFileName = "lap-times-udp.log";
53 try {
54 file = new FileWriter(logFileName);
55 out = new BufferedWriter(file);
57 catch (IOException e) {
58 System.out.println(e);
61 } // end constructor
63 /**
64 * Runs the main logic of the UDPNode
66 public void runUDPNode() {
68 // keeps track of whether or not the
69 // main while-loop should be running
70 boolean runMainWhileLoop = true;
72 // start phase 1 by sending out a find-master query
73 sendPacket(constructPacket(FINDMASTER, new Integer(ID).toString()));
75 // initate fields used to store information from arrived packets
76 byte[] receivedData = new byte[DATAGRAMSIZE];
77 DatagramPacket receivePacket =
78 new DatagramPacket(receivedData, DATAGRAMSIZE);
80 // start receiving packets ('main while-loop')
81 while (runMainWhileLoop) {
82 // Waiting for data to arrive
83 receivePacket(receivePacket);
85 // acquire the message's message type
86 int messageType = receivedData[0];
88 // keeping track of which phase we're in
89 int phase = FINDMASTER;
90 switch (messageType) {
91 // if messageType == 1
92 case FINDMASTER:
94 // acquire the message's length
95 int messageLength = receivedData[1];
97 // acquire the message...
98 String message =
99 new String(receivedData).substring(2, messageLength + 2);
101 // the largest ID that this packet has seen so far, i.e. the
102 // ID of the node with the largest ID so far in the ring.
103 int receivedID = Integer.parseInt(message);
105 // if we left phase 1 but messages
106 // are still circling the ring:
107 if (phase != FINDMASTER) {
108 // don't do anything.
109 break;
111 // if this node will surely not be the master node
112 if (receivedID > ID) {
113 // set a new receiver for the received packet
114 receivePacket.setPort(nextPort);
115 receivePacket.setAddress(nextHost);
116 sendPacket(receivePacket);
118 // if this node has a larger ID than the one of the sending node
119 else if (receivedID < ID) {
120 // Send own ID again since it could have been lost
121 sendPacket(constructPacket(FINDMASTER, new Integer(ID).toString()));
123 // if this node should be the master node
124 else if (receivedID == ID) {
125 phase = RUNMODE;
126 isMasterNode = true;
128 // if this node is a logging node,
129 if (isLogger) {
130 // set the starting time -- the time
131 // when phase two was initiated
132 startTime = System.nanoTime();
134 // increase the number of sent packets.
135 sentPackets++;
137 // send first packet in phase two
138 sendPacket(constructPacket(RUNMODE, new Integer(ID).toString()));
140 break;
141 // if messageType == 2
142 case RUNMODE:
143 // make sure everybody knows we're in the second phase
144 phase = RUNMODE;
146 // if this node is a logger and the start time hasn't been set
147 if (isLogger && startTime == 0) {
148 // set the start time
149 startTime = System.nanoTime();
151 // if this node is a logger:
152 if (isLogger) {
153 // write to file
154 writeToLog(new String(receivedData).substring(2, receivedData[1] + 2));
156 // if this is the master node and
157 // we've sent as many packets as we were to (and the
158 // number of packets to send is not zero (infinitely many)):
159 if (isMasterNode && sentPackets == PACKETSTOSEND) {
160 // send the terminating packet to the next node
161 // (and, indirectly so, to all other nodes)
162 sendPacket(constructPacket(TERMINATE, "3"));
163 break;
166 // if we've not send as many packets as we are to:
167 // re-route packet (set its port and address) and send it
168 receivePacket.setPort(nextPort);
169 receivePacket.setAddress(nextHost);
170 sendPacket(receivePacket);
171 sentPackets++;
172 break;
173 // if messageType == 3 (stop sending packets and ultimately quit
174 case TERMINATE:
175 runMainWhileLoop = false;
176 // if this node is a logger, log one final time before
177 // stopping the whole shebang and close the file
178 if (isLogger) {
179 writeToLog(new String(receivedData).substring(2, receivedData[1] + 2));
180 System.out.println("Closing file...");
181 closeLogFile();
182 System.out.println("Finished.");
184 // send terminating packet (end the whole shebang)
185 sendPacket(constructPacket(TERMINATE, "3"));
186 mySocket.close();
187 break;
188 } // end switch
189 } // end main while-loop
190 } // end runUDPNode
193 * Sends a DatagramPacket through this UDPNode's DatagramSocket.
195 * @return boolean <code>true</code> if sending was successful,
196 * else <code>false</code>.
198 public boolean sendPacket(DatagramPacket sendPacket) {
199 try {
200 mySocket.send(sendPacket);
202 catch (IOException e) {
203 System.out.println(e);
204 return false;
206 return true;
210 * Receives a DatagramPacket from this UDPNode's DatagramSocket.
212 * @return boolean <code>true</code> if receiving was successful,
213 * else <code>false</code>.
215 public boolean receivePacket(DatagramPacket receivePacket) {
216 try {
217 mySocket.receive(receivePacket);
219 catch (IOException e) {
220 System.out.println(e);
221 return false;
223 return true;
227 * For starting the UDPNode from a commandline
229 * @param args should contain local-port next-host next-port [L]
230 * where the L is optional and specifies if the node
231 * should log lap-times
232 * @exception IOException if an error occurs
234 public static void main(String[] args) throws IOException {
235 // args should contain local-port next-host next-port
236 UDPNode node = null;
237 boolean logger = false;
238 if (args.length == 4 && args[3].charAt(0) == 'L') {
239 logger = true;
241 try {
242 node = new UDPNode(Integer.parseInt(args[0]),
243 InetAddress.getByName(args[1]),
244 Integer.parseInt(args[2]),
245 logger);
247 catch (Exception e) {
248 System.out.println("You most likely provided parameters " +
249 "incorrectly to the program." + '\n' +
250 "Usage: java UDPNode local-port " +
251 "next-host next-port [L]");
252 System.exit(1);
254 try {
255 node.runUDPNode();
257 catch (Exception e) {
258 System.out.println("Something went wrong... Try making sure " +
259 "that the ports you are trying to use " +
260 "are not occupied by any other program.");