Source code: marauroa/net/NetworkServerManager.java
1 /* $Id: NetworkServerManager.java,v 1.9 2003/12/09 23:40:16 arianne_rpg Exp $ */
2 /***************************************************************************
3 * (C) Copyright 2003 - Marauroa *
4 ***************************************************************************
5 ***************************************************************************
6 * *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
11 * *
12 ***************************************************************************/
13 package marauroa.net;
14
15 import java.net.*;
16 import java.util.*;
17 import java.io.*;
18 import java.math.*;
19
20 import marauroa.marauroad;
21
22 /** The NetworkServerManager is the active entity of the marauroa.net package,
23 * it is in charge of sending and recieving the packages from the network. */
24 public class NetworkServerManager
25 {
26 /** The server socket from where we recieve the packets. */
27 private DatagramSocket socket;
28 /** While keepRunning is true, we keep recieving messages */
29 private boolean keepRunning;
30 /** isFinished is true when the thread has really exited. */
31 private boolean isfinished;
32
33 /** A List of Message objects: List<Message> */
34 private List messages;
35
36 private MessageFactory msgFactory;
37 private NetworkServerManagerRead readManager;
38 private NetworkServerManagerWrite writeManager;
39
40 /** Constructor that opens the socket on the marauroa_PORT and start the thread
41 to recieve new messages from the network. */
42 public NetworkServerManager() throws SocketException
43 {
44 marauroad.trace("NetworkServerManager",">");
45 try
46 {
47 /* Create the socket and set a timeout of 1 second */
48 socket=new DatagramSocket(NetConst.marauroa_PORT);
49 socket.setSoTimeout(1000);
50
51 msgFactory=MessageFactory.getFactory();
52
53 keepRunning=true;
54 isfinished=false;
55
56 /* Because we access the list from several places we create a synchronized list. */
57 messages=Collections.synchronizedList(new LinkedList());
58
59 readManager=new NetworkServerManagerRead();
60 readManager.start();
61
62 writeManager=new NetworkServerManagerWrite();
63 }
64 finally
65 {
66 marauroad.trace("NetworkServerManager","<");
67 }
68 }
69
70 /** This method notify the thread to finish it execution */
71 public void finish()
72 {
73 marauroad.trace("NetworkServerManager::finish",">");
74 keepRunning=false;
75
76 while(isfinished==false)
77 {
78 try
79 {
80 Thread.sleep(1000);
81 }
82 catch(java.lang.InterruptedException e)
83 {
84 }
85 }
86
87 socket.close();
88 marauroad.trace("NetworkServerManager::finish","<");
89 }
90
91 private synchronized void newMessageArrived()
92 {
93 notify();
94 }
95
96 /** This method returns a Message from the list or block for timeout milliseconds
97 * until a message is available or null if timeout happens.
98 * @param timeout timeout time in milliseconds
99 * @return a Message or null if timeout happens */
100 public synchronized Message getMessage(int timeout)
101 {
102 marauroad.trace("NetworkServerManager::getMessage",">");
103 try
104 {
105 if(messages.size()==0)
106 {
107 try
108 {
109 wait(timeout);
110 }
111 catch(InterruptedException e)
112 {
113 }
114 }
115
116 if(messages.size()==0)
117 {
118 marauroad.trace("NetworkServerManager::getMessage","D","Message not available.");
119 return null;
120 }
121 else
122 {
123 marauroad.trace("NetworkServerManager::getMessage","D","Message returned.");
124 return (Message)messages.remove(0);
125 }
126 }
127 finally
128 {
129 marauroad.trace("NetworkServerManager::getMessage","<");
130 }
131 }
132
133 /** This method blocks until a message is available
134 * @return a Message*/
135 public synchronized Message getMessage()
136 {
137 marauroad.trace("NetworkServerManager::getMessage",">");
138 try
139 {
140 while(messages.size()==0)
141 {
142 try
143 {
144 wait();
145 }
146 catch(InterruptedException e)
147 {
148 }
149 }
150
151 return (Message)messages.remove(0);
152 }
153 finally
154 {
155 marauroad.trace("NetworkServerManager::getMessage","<");
156 }
157 }
158
159 /** This method add a message to be delivered to the client the message is pointed to.
160 * @param msg the message to ve delivered. */
161 public synchronized void addMessage(Message msg)
162 {
163 marauroad.trace("NetworkServerManager::addMessage",">");
164 writeManager.write(msg);
165 marauroad.trace("NetworkServerManager::addMessage","<");
166 }
167
168 /** The active thread in charge of recieving messages from the network. */
169 class NetworkServerManagerRead extends Thread
170 {
171 public NetworkServerManagerRead()
172 {
173 super("NetworkServerManagerRead");
174 }
175
176 /** Method that execute the reading. It runs as a active thread forever. */
177 public void run()
178 {
179 marauroad.trace("NetworkServerManagerRead::run",">");
180 while(keepRunning)
181 {
182 byte[] buffer=new byte[NetConst.UDP_PACKET_SIZE];
183 DatagramPacket packet=new DatagramPacket(buffer,buffer.length);
184
185 try
186 {
187 socket.receive(packet);
188 marauroad.trace("NetworkServerManagerRead::run","D","Received UDP Packet");
189
190 Message msg=msgFactory.getMessage(packet.getData(),(InetSocketAddress)packet.getSocketAddress());
191 marauroad.trace("NetworkServerManagerRead::run","D","Received message: "+msg.toString());
192
193 messages.add(msg);
194 newMessageArrived();
195 }
196 catch(java.net.SocketTimeoutException e)
197 {
198 /* We need the thread to check from time to time if user has requested
199 * an exit */
200 }
201 catch(IOException e)
202 {
203 /* Report the exception */
204 marauroad.trace("NetworkServerManagerRead::run","X",e.getMessage());
205 }
206 }
207
208 isfinished=true;
209 marauroad.trace("NetworkServerManagerRead::run","<");
210 }
211 }
212
213 /** A wrapper class for sending messages to clients */
214 class NetworkServerManagerWrite
215 {
216 private int last_signature;
217 private String name;
218
219 public NetworkServerManagerWrite()
220 {
221 last_signature=0;
222 name="NetworkServerManagerWrite";
223 }
224
225 /** Method that execute the writting */
226 public void write(Message msg)
227 {
228 marauroad.trace("NetworkServerManagerWrite::write",">");
229 try
230 {
231 /* TODO: Looks like hardcoded, write it in a better way */
232 if(keepRunning)
233 {
234 ByteArrayOutputStream out=new ByteArrayOutputStream();
235 OutputSerializer s=new OutputSerializer(out);
236
237 s.write(msg);
238
239 byte[] buffer=out.toByteArray();
240 marauroad.trace("NetworkServerManagerWrite::write","D","Message size in bytes: "+buffer.length);
241
242 int total=buffer.length/(NetConst.UDP_PACKET_SIZE-3)+1;
243 ++last_signature;
244 int remaining=buffer.length;
245
246 for(int i=0;i<total;++i)
247 {
248 int size=0;
249 if((NetConst.UDP_PACKET_SIZE-3)>remaining)
250 {
251 size=remaining;
252 }
253 else
254 {
255 size=NetConst.UDP_PACKET_SIZE-3;
256 }
257
258 remaining-=size;
259
260 marauroad.trace("NetworkServerManagerWrite::write","D","Packet size: "+size);
261 marauroad.trace("NetworkServerManagerWrite::write","D","Bytes remaining: "+remaining);
262
263 byte[] data=new byte[size+3];
264 data[0]=(byte)total;
265 data[1]=(byte)i;
266 data[2]=(byte)last_signature;
267 System.arraycopy(buffer,(NetConst.UDP_PACKET_SIZE-3)*i,data,3,size);
268
269 DatagramPacket pkt=new DatagramPacket(data,data.length,msg.getAddress());
270 socket.send(pkt);
271 marauroad.trace("NetworkServerManagerWrite::write","D","Sent packet "+(i+1)+" of "+total);
272 }
273
274 marauroad.trace("NetworkServerManagerWrite::write","D","Sent message: "+msg.toString());
275 }
276 }
277 catch(IOException e)
278 {
279 /* Report the exception */
280 marauroad.trace("NetworkServerManagerWrite::write","X",e.getMessage());
281 }
282 finally
283 {
284 marauroad.trace("NetworkServerManagerWrite::write","<");
285 }
286 }
287 }
288 }