1
2
3
4
5 package spellcast.server;
6
7 import java.io.ByteArrayOutputStream;
8 import java.io.IOException;
9 import java.io.InterruptedIOException;
10 import java.io.ObjectOutputStream;
11 import java.net.DatagramPacket;
12 import java.net.DatagramSocket;
13 import java.net.InetAddress;
14
15 import org.apache.log4j.Logger;
16 import spellcast.net.NetConstants;
17 import spellcast.net.ServerStatus;
18
19 /***
20 * The ServerStatusRequestHandler listens for ServerStatusRequest messages and
21 * handles them. The class creates the datagram socket that is used
22 * to receive the broadcast messages for ServerStatusRequests and creates
23 * the ServerStatusResponse message. A new thread is started to handle the
24 * message processing for ServerStatusRequestHandler when <code>start</code> is called.
25 * Call <code>stop</code> to stop the thread.
26 *
27 * @author Barrie Treloar
28 */
29 public class ServerStatusRequestHandler implements NetConstants, Runnable {
30 /***
31 * The socket timeout is set to 10 seconds.
32 */
33 private static final int SOCKET_TIMEOUT = 10 * 1000;
34
35 /***
36 * The datagram packet size is 1024 bytes. Any packet exceeding this length
37 * will be truncated.
38 */
39 private static final int PACKET_SIZE = 1024;
40
41 private static final Logger logger = Logger.getLogger("server.status");
42 private static final Logger logger_net = Logger.getLogger("server.status.net");
43
44 private Thread serverStatusThread;
45 private DatagramSocket serverStatusSocket;
46 private boolean isRunning;
47
48 public ServerStatusRequestHandler() {
49 }
50
51 /***
52 * Send back the ServerStatusResponse.
53 */
54 private void sendResponse(DatagramPacket message) {
55 try {
56 ServerStatus ss = Server.getServer().getServerStatus();
57
58 ByteArrayOutputStream baos = new ByteArrayOutputStream();
59 ObjectOutputStream oos = new ObjectOutputStream(baos);
60 oos.writeObject(ss);
61
62 byte[] bytes = baos.toByteArray();
63 logger_net.debug("ServerStatusResponse.size = " + bytes.length);
64 logger_net.debug(
65 "Sending to "
66 + message.getAddress().getHostAddress()
67 + ":"
68 + message.getPort());
69 DatagramPacket response =
70 new DatagramPacket(
71 bytes,
72 bytes.length,
73 message.getAddress(),
74 message.getPort());
75 serverStatusSocket.send(response);
76 }
77 catch (Exception ex) {
78 logger.error("Sending of server status response failed.", ex);
79 }
80 }
81
82 /***
83 * This thread will start running when <code>start</code> is called and
84 * continue running until the <code>stop</code> method is called.
85 * This method loops while checking for a ServerStatusRequest message to be
86 * received. When it is received it queries the current game for its status
87 * returns the status in a ServerStatusResponse message.
88 */
89 public void run() {
90 DatagramPacket message = new DatagramPacket(new byte[PACKET_SIZE], PACKET_SIZE);
91
92 while (isRunning) {
93 try {
94 serverStatusSocket.receive(message);
95 sendResponse(message);
96 }
97 catch (InterruptedIOException ix) {
98
99 }
100 catch (IOException ex) {
101 logger.error("Failed on serverStatusSocket.receive.", ex);
102 }
103 }
104 }
105
106 /***
107 * Allocate resources, create and start the thread.
108 * Resources are deallocated in <code>cleanup</code>.
109 *
110 * @throws ServerException thrown if the server status socket could not be allocated.
111 */
112 public void start() throws ServerException {
113 try {
114 serverStatusSocket =
115 new DatagramSocket(
116 SPELLCAST_NET_SERVERLIST_PORT,
117 InetAddress.getByName("0.0.0.0"));
118 serverStatusSocket.setSoTimeout(SOCKET_TIMEOUT);
119 logger_net.debug(
120 "Status Socket = "
121 + serverStatusSocket.getLocalAddress().getHostAddress()
122 + ":"
123 + serverStatusSocket.getLocalPort());
124
125 isRunning = true;
126 serverStatusThread = new Thread(this, "serverStatusThread");
127 serverStatusThread.start();
128 }
129 catch (Exception e) {
130 throw new ServerException(e);
131 }
132 }
133
134 /***
135 * Sets the isRunning flag to false which lets <code>run</code> exit the
136 * infite loop. This method will wait until the thread dies before
137 * calling <code>cleanup</code> where resources are deallocated.
138 */
139 public void stop() {
140 isRunning = false;
141 try {
142 serverStatusThread.join();
143 }
144 catch (InterruptedException e) {
145 logger.error("Unexpectedly Interrupted.", e);
146 }
147 cleanup();
148 }
149
150 /***
151 * Dellocate resources allocated in <code>start</code>
152 */
153 private void cleanup() {
154 if (serverStatusSocket != null) {
155 serverStatusSocket.close();
156 serverStatusSocket = null;
157 }
158 serverStatusThread = null;
159 }
160 }