Source code: org/jext/JextLoader.java
1 /*
2 * 01/20/2003 - 23:56:01
3 *
4 * JextLoader.java - Loads Jext instances in a single JVM
5 * Copyright (C) 2000 Romain Guy
6 * romain.guy@jext.org
7 * www.jext.org
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 */
23
24 package org.jext;
25
26 import java.io.*;
27 import java.net.*;
28 import java.util.*;
29
30 import javax.swing.JOptionPane;
31
32 /**
33 * This class creates a new socket connection which listens to client requests. Whenever
34 * a client logs onto the socket, we check its IP address.<br>
35 * Security implementation:<p>
36 * <ul>
37 * <li>If this address isn't 127.0.0.1 (aka localhost), the connection is rejected.</li>
38 * <li>The socket also needs to get the good message which must contain a give authorization key.
39 * If the given key or message is wrong, the connection is rejected.</li>
40 * <li>If the server rejects a connection, it also closes itself to avoid Denial Of Service
41 * attacks or brutal ones (trying for instance random keys).</li>
42 * </ul>
43 * @author Romain Guy
44 * @version 1.1.1
45 */
46
47 final class JextLoader implements Runnable
48 {
49 private int port;
50 private File auth;
51 private String key;
52 private Thread tServer;
53 private ServerSocket server;
54
55 JextLoader()
56 {
57 auth = new File(Jext.SETTINGS_DIRECTORY + ".auth-key");
58 // creates the authorization key
59 try
60 {
61 BufferedWriter writer = new BufferedWriter(new FileWriter(auth));
62 // 16 383 = unreserved range of ports
63 port = Math.abs(new Random().nextInt()) % (16383);
64 String portStr = Integer.toString(port);
65 key = Integer.toString(Math.abs(new Random().nextInt()) % (int) Math.pow(2, 30));
66 writer.write(portStr, 0, portStr.length());
67 writer.newLine();
68 writer.write(key, 0, key.length());
69 writer.flush();
70 writer.close();
71
72 // creates the server
73 server = new ServerSocket(Jext.JEXT_SERVER_PORT + port);
74
75 } catch (IOException ioe) {
76 ioe.printStackTrace();
77 }
78
79 // server is necessarily threaded
80 tServer = new Thread(this);
81 tServer.start();
82 }
83
84 /**
85 * Stops the server by inerrupting the thread, killing it and then
86 * closing the server itself. Finally, it erases the authorization
87 * key.
88 */
89
90 public void stop()
91 {
92 tServer.interrupt();
93 tServer = null;
94
95 try
96 {
97 if (server != null)
98 server.close();
99 auth.delete();
100 } catch (IOException ioe) { }
101 }
102
103 /**
104 * Waits for a connexion request and handle it. The client should provide a special line
105 * containing a message, the arguments for the loading and the authorization key. This
106 * key is used to avoid security holes in your system.
107 */
108
109 public void run()
110 {
111 while (tServer != null)
112 {
113 try
114 {
115 Socket client = server.accept();
116 if (client == null)
117 continue;
118
119 if (!"127.0.0.1".equals(client.getLocalAddress().getHostAddress()))
120 {
121 client.close();
122 Jext.stopServer();
123 intrusion();
124 return;
125 }
126
127 BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream()));
128 String givenKey = reader.readLine();
129 reader.close();
130
131 if (givenKey != null)//when backgrounding connects to check existance of server but sends
132 //nothing.
133 if (givenKey.startsWith("load_jext:") && givenKey.endsWith(":" + key))
134 {
135 Vector args = new Vector(1);
136 StringTokenizer st = new StringTokenizer(givenKey.substring(10,
137 givenKey.length() - (key.length() + 1)), "?");
138 while (st.hasMoreTokens())
139 args.addElement(st.nextToken());
140
141 if (args.size() > 0)
142 {
143 String arguments[] = new String[args.size()];
144 args.copyInto(arguments);
145 args = null;
146
147 if (Jext.getBooleanProperty("jextLoader.newWindow"))
148 {
149 Jext.newWindow(arguments);
150 } else if (!Jext.isRunningBg()) {
151 ArrayList instances = Jext.getInstances();
152 synchronized(instances) {
153 if (instances.size() != 0) {//can be 0 when backgrounding.??? No more!
154 JextFrame parent = (JextFrame) instances.get(0);
155 for (int i = 0; i < arguments.length; i++)
156 parent.open(arguments[i]);
157 //parent.setVisible(true);//this code is not good when running background server,
158 //since Jext keeps builtTextArea set(and doesn't open a new one until it isn't unset).
159 //And so setVisible is not needed.
160 } else {
161 Jext.newWindow(arguments);
162 System.err.println("DEBUG - instances.size() == 0 in JextLoader.java!");
163 }
164 }
165
166 } else //when Jext.isRunningBg()
167 Jext.newWindow(arguments);
168 } else
169 Jext.newWindow();
170
171 client.close();
172 } else if (givenKey.equals("kill:" + key)) {
173 if (Jext.isRunningBg())// && Jext.getWindowsCount() <= 1 )
174 {
175 ArrayList instances = Jext.getInstances();
176 synchronized (instances)
177 {
178 //normally at least one window is always open, even if hidden, but in some moments
179 //this isn't true(when the user exits jext and it has not still started a new window).
180 //If one window is open, we must check it is not shown.
181 JextFrame lastInstance = null;
182 if (instances.size() == 0 || instances.size() == 1 &&
183 ! ( lastInstance = (JextFrame)instances.get(0) ) .isVisible())
184 {
185 if (instances.size() != 0)
186 {
187 Jext.closeToQuit(lastInstance, true);
188 //since the window has not been shown this could be useless, but maybe not, especially to
189 //dispatch JextEvent's.
190 }
191 //I've commented out the above code since it causes bugs with the ProjectManagement,
192 //that is NullPointerEx. I'm trying if this doesn't happen without cleanMemory.
193 Jext.finalCleanupAndExit();//check well this! TODO
194 }
195 }
196 }
197 } else {
198 client.close();
199 Jext.stopServer();
200 intrusion();
201 return;
202 }
203 } catch (IOException ioe) { }
204 }
205 }
206
207 // warn the user that someone is attempting to break into his system
208
209 private void intrusion()
210 {
211 JOptionPane.showMessageDialog(null,
212 "An intrusion is attempted against your system !\nJext will close its opened " + "sockets to preserve system integrity.\nYou should warn the network administrator.",
213 "Intrusion attempt...", JOptionPane.WARNING_MESSAGE);
214 }
215
216 /***************************************************************************
217 Patch
218 -> Memory management improvements : it may help the garbage collector.
219 -> Author : Julien Ponge (julien@izforge.com)
220 -> Date : 23, May 2001
221 ***************************************************************************/
222 protected void finalize() throws Throwable
223 {
224 super.finalize();
225
226 auth = null;
227 key = null;
228 tServer = null;
229 server = null;
230 }
231 // End of patch
232 }
233
234 // End of JextLoader.java