View Javadoc

1   /*
2    *   Firemox is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18   */
19  package net.sf.firemox.network;
20  
21  import java.net.ServerSocket;
22  import java.net.SocketException;
23  import java.net.SocketTimeoutException;
24  
25  import javax.swing.JOptionPane;
26  
27  import net.sf.firemox.action.PayMana;
28  import net.sf.firemox.action.WaitActivatedChoice;
29  import net.sf.firemox.clickable.target.player.Opponent;
30  import net.sf.firemox.clickable.target.player.You;
31  import net.sf.firemox.deckbuilder.Deck;
32  import net.sf.firemox.deckbuilder.MdbLoader;
33  import net.sf.firemox.stack.StackManager;
34  import net.sf.firemox.token.IdConst;
35  import net.sf.firemox.tools.Configuration;
36  import net.sf.firemox.tools.Log;
37  import net.sf.firemox.tools.MToolKit;
38  import net.sf.firemox.ui.MagicUIComponents;
39  import net.sf.firemox.ui.component.LoaderConsole;
40  import net.sf.firemox.ui.component.TableTop;
41  import net.sf.firemox.ui.i18n.LanguageManager;
42  
43  import org.apache.commons.io.IOUtils;
44  
45  /***
46   * a multi-client server
47   * 
48   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
49   * @since 0.2c
50   */
51  public class Server extends NetworkActor implements IdMessages {
52  
53  	/***
54  	 * create a new server for a specified port, play name, nickName and password
55  	 * required (null if none)
56  	 * 
57  	 * @param deck
58  	 *          the deck of this server
59  	 * @param passwd
60  	 *          is the password needed to connect to this play
61  	 */
62  	public Server(Deck deck, char[] passwd) {
63  		super(deck, passwd);
64  		LoaderConsole.beginTask(LanguageManager
65  				.getString("wiz_network.waitingforopponent"));
66  	}
67  
68  	/***
69  	 * If this thread was constructed using a separate <code>Runnable</code> run
70  	 * object, then that <code>Runnable</code> object's <code>run</code>
71  	 * method is called; otherwise, this method does nothing and returns.
72  	 * <p>
73  	 * Subclasses of <code>Thread</code> should override this method.
74  	 * 
75  	 * @see java.lang.Thread#start()
76  	 * @see java.lang.Thread#Thread(java.lang.ThreadGroup, java.lang.Runnable,
77  	 *      java.lang.String)
78  	 * @see java.lang.Runnable#run()
79  	 */
80  	@Override
81  	public void run() {
82  		// Creating connection socket
83  		try {
84  			serverSocket = new ServerSocket(port, 1);
85  			// enable timeout
86  			serverSocket.setSoTimeout(2000);
87  
88  			// accept any client
89  			clientSocket = null;
90  			LoaderConsole.beginTask(LanguageManager
91  					.getString("wiz_network.creatingconnection"), 2);
92  			while (clientSocket == null && !cancelling) {
93  				try {
94  					clientSocket = serverSocket.accept();
95  				} catch (SocketException timeout) {
96  					if (!"socket closed".equals(timeout.getMessage())) {
97  						throw timeout;
98  					}
99  				} catch (SocketTimeoutException timeout) {
100 					/*
101 					 * timeout of 'accept()' method, nothing to do, we look if we're still
102 					 * running
103 					 */
104 				}
105 			}
106 
107 			// stopping?
108 			if (cancelling) {
109 				Log.info(LanguageManager.getString("wiz_network.canceledcreation"));
110 				cancelConnexion();
111 				return;
112 			}
113 
114 			// A client is connecting...
115 			LoaderConsole.beginTask(LanguageManager
116 					.getString("wiz_network.incomming")
117 					+ " : " + clientSocket.getInetAddress().toString(), 5);
118 
119 			// free these two sockets later
120 			outBin = clientSocket.getOutputStream();
121 			inBin = clientSocket.getInputStream();
122 			// socketListener = new SocketListener(inBin);
123 
124 			if (passwd != null && passwd.length > 0) {
125 				// a password is needed to connect to this server
126 				MToolKit.writeString(outBin, STR_PASSWD);
127 				if (MToolKit.readString(inBin).equals(new String(passwd))) {
128 					MToolKit.writeString(outBin, STR_OK);
129 				} else {
130 					// wrong password, this client client will be disconnected
131 					MToolKit.writeString(outBin, STR_WRONGPASSWD);
132 					// close stream
133 					IOUtils.closeQuietly(inBin);
134 					IOUtils.closeQuietly(outBin);
135 					// free pointers
136 					outBin = null;
137 					inBin = null;
138 				}
139 			} else {
140 				MToolKit.writeString(outBin, STR_OK);
141 			}
142 
143 			// check version of client
144 			String clientVersion = MToolKit.readString(inBin);
145 			if (IdConst.VERSION.equals(clientVersion)) {
146 				MToolKit.writeString(outBin, STR_OK);
147 			} else {
148 				// two different versions
149 				MToolKit.writeString(outBin, STR_WRONGVERSION);
150 				LoaderConsole.beginTask(LanguageManager
151 						.getString("wiz_network.differentversionClientpb")
152 						+ " (" + clientVersion + ")", 10);
153 				IOUtils.closeQuietly(inBin);
154 				IOUtils.closeQuietly(outBin);
155 				// free pointers
156 				outBin = null;
157 				inBin = null;
158 			}
159 
160 			if (outBin != null) {
161 
162 				// enter in the main loop
163 				// Opponent is ...
164 				String clientName = MToolKit.readString(inBin);
165 				LoaderConsole.beginTask(LanguageManager
166 						.getString("wiz_network.opponentis")
167 						+ clientName, 10);
168 				// I am ...
169 				MToolKit.writeString(outBin, nickName);
170 
171 				// exchange shared string settings
172 				((You) StackManager.PLAYERS[0]).sendSettings(outBin);
173 				((Opponent) StackManager.PLAYERS[1]).readSettings(clientName, nickName,
174 						inBin);
175 
176 				// stopping?
177 				if (cancelling) {
178 					cancelConnexion();
179 					return;
180 				}
181 
182 				// set and send the random seed
183 				long seed = MToolKit.random.nextLong();
184 				MToolKit.random.setSeed(seed);
185 				MToolKit.writeString(outBin, Long.toString(seed));
186 				Log.info("Seed = " + seed);
187 
188 				// write mana use option
189 				PayMana.useMana = Configuration.getBoolean("useMana", true);
190 				MToolKit.writeString(outBin, PayMana.useMana ? "1" : "0");
191 
192 				// write opponent response option
193 				WaitActivatedChoice.opponentResponse = Configuration.getBoolean(
194 						"opponnentresponse", true);
195 				MToolKit.writeString(outBin, WaitActivatedChoice.opponentResponse ? "1"
196 						: "0");
197 
198 				// Who starts?
199 				final StartingOption startingOption = StartingOption.values()[Configuration
200 						.getInt("whoStarts", StartingOption.random.ordinal())];
201 				MToolKit.writeString(outBin, String.valueOf(Configuration.getInt(
202 						"whoStarts", 0)));
203 				final boolean serverStarts;
204 				switch (startingOption) {
205 				case random:
206 				default:
207 					serverStarts = MToolKit.random.nextBoolean();
208 					break;
209 				case server:
210 					serverStarts = true;
211 					break;
212 				case client:
213 					serverStarts = false;
214 				}
215 
216 				if (serverStarts) {
217 					// server begins
218 					LoaderConsole.beginTask(LanguageManager
219 							.getString("wiz_network.youwillstarts")
220 							+ " (mode=" + startingOption.getLocaleValue() + ")", 15);
221 					StackManager.idActivePlayer = 0;
222 					StackManager.idCurrentPlayer = 0;
223 				} else {
224 					// client begins
225 					LoaderConsole.beginTask(LanguageManager
226 							.getString("wiz_network.opponentwillstart")
227 							+ " (mode=" + startingOption.getLocaleValue() + ")", 15);
228 					StackManager.idActivePlayer = 1;
229 					StackManager.idCurrentPlayer = 1;
230 				}
231 
232 				// load rules from the MDB file
233 				dbStream = MdbLoader.loadMDB(MToolKit.mdbFile,
234 						StackManager.idActivePlayer);
235 				TableTop.getInstance().initTbs();
236 
237 				// receive and validate her/his deck
238 				LoaderConsole.beginTask(LanguageManager
239 						.getString("wiz_network.receivingdeck"), 25);
240 				readAndValidateOpponentDeck();
241 
242 				// stopping?
243 				if (cancelling) {
244 					cancelConnexion();
245 					return;
246 				}
247 
248 				// send our deck
249 				LoaderConsole.beginTask(LanguageManager
250 						.getString("wiz_network.sendingdeck"), 55);
251 				deck.send(outBin);
252 				StackManager.PLAYERS[0].zoneManager.giveCards(deck, dbStream);
253 
254 				// stopping?
255 				if (cancelling) {
256 					cancelConnexion();
257 					return;
258 				}
259 
260 				MToolKit.writeString(outBin, "%EOF%");
261 
262 				// free resources
263 				outBin.flush();
264 
265 				// stopping?
266 				if (cancelling) {
267 					cancelConnexion();
268 					return;
269 				}
270 
271 				initBigPipe();
272 				MagicUIComponents.magicForm.initGame();
273 			}
274 		} catch (Throwable e) {
275 			NetworkActor.cancelling = true;
276 			LoaderConsole.endTask();
277 			cancelConnexion();
278 			JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
279 					LanguageManager.getString("wiz_server.error") + " : "
280 							+ e.getMessage(), LanguageManager.getString("error"),
281 					JOptionPane.WARNING_MESSAGE);
282 			Log.error(e);
283 			return;
284 		}
285 	}
286 
287 	@Override
288 	public void closeConnexion() {
289 		super.closeConnexion();
290 		// close stream
291 		if (serverSocket != null) {
292 			try {
293 				serverSocket.close();
294 			} catch (Exception e) {
295 				// Nothing to do
296 			}
297 		}
298 	}
299 
300 	/***
301 	 * the server's socket of this connexion
302 	 */
303 	public ServerSocket serverSocket;
304 
305 }