1 package be
.nikiroo
.utils
.serial
.server
;
3 import java
.io
.IOException
;
4 import java
.lang
.reflect
.Array
;
5 import java
.net
.Socket
;
6 import java
.net
.UnknownHostException
;
8 import be
.nikiroo
.utils
.StringUtils
;
9 import be
.nikiroo
.utils
.TraceHandler
;
10 import be
.nikiroo
.utils
.Version
;
11 import be
.nikiroo
.utils
.serial
.Importer
;
14 * This class implements a simple server that can bridge two other
17 * It can, of course, inspect the data that goes through it (by default, it
18 * prints traces of the data).
20 * Note: this {@link ServerBridge} has to be discarded after use (cannot be
25 public class ServerBridge
extends Server
{
26 private final String forwardToHost
;
27 private final int forwardToPort
;
28 private final String forwardToKey
;
31 * Create a new server that will start listening on the network when
32 * {@link ServerBridge#start()} is called.
35 * the port to listen on, or 0 to assign any unallocated port
36 * found (which can later on be queried via
37 * {@link ServerBridge#getPort()}
39 * an optional key to encrypt all the communications (if NULL,
40 * everything will be sent in clear text)
41 * @param forwardToHost
42 * the host server to forward the calls to
43 * @param forwardToPort
44 * the host port to forward the calls to
46 * an optional key to encrypt all the communications (if NULL,
47 * everything will be sent in clear text)
50 * in case of I/O error
51 * @throws UnknownHostException
52 * if the IP address of the host could not be determined
53 * @throws IllegalArgumentException
54 * if the port parameter is outside the specified range of valid
55 * port values, which is between 0 and 65535, inclusive
57 public ServerBridge(int port
, String key
, String forwardToHost
,
58 int forwardToPort
, String forwardToKey
) throws IOException
{
60 this.forwardToHost
= forwardToHost
;
61 this.forwardToPort
= forwardToPort
;
62 this.forwardToKey
= forwardToKey
;
66 * Create a new server that will start listening on the network when
67 * {@link ServerBridge#start()} is called.
70 * the server name (only used for debug info and traces)
72 * the port to listen on
74 * an optional key to encrypt all the communications (if NULL,
75 * everything will be sent in clear text)
76 * @param forwardToHost
77 * the host server to forward the calls to
78 * @param forwardToPort
79 * the host port to forward the calls to
81 * an optional key to encrypt all the communications (if NULL,
82 * everything will be sent in clear text) use an SSL connection
83 * for the forward server or not
86 * in case of I/O error
87 * @throws UnknownHostException
88 * if the IP address of the host could not be determined
89 * @throws IllegalArgumentException
90 * if the port parameter is outside the specified range of valid
91 * port values, which is between 0 and 65535, inclusive
93 public ServerBridge(String name
, int port
, String key
,
94 String forwardToHost
, int forwardToPort
, String forwardToKey
)
96 super(name
, port
, key
);
97 this.forwardToHost
= forwardToHost
;
98 this.forwardToPort
= forwardToPort
;
99 this.forwardToKey
= forwardToKey
;
103 * The traces handler for this {@link Server}.
105 * The trace levels are handled as follow:
107 * <li>1: it will only print basic IN/OUT messages with length</li>
108 * <li>2: it will try to interpret it as an object (SLOW) and print the
109 * object class if possible</li>
110 * <li>3: it will try to print the {@link Object#toString()} value, or the
111 * data if it is not an object</li>
112 * <li>4: it will also print the unzipped serialised value if it is an
117 * the new traces handler
120 public void setTraceHandler(TraceHandler tracer
) {
121 super.setTraceHandler(tracer
);
125 protected ConnectActionServer
createConnectActionServer(Socket s
) {
126 return new ConnectActionServerString(s
, key
) {
128 public void action(final Version clientVersion
) throws Exception
{
129 onClientContact(clientVersion
);
130 final ConnectActionServerString bridge
= this;
133 new ConnectActionClientString(forwardToHost
, forwardToPort
,
134 forwardToKey
, clientVersion
) {
136 public void action(final Version serverVersion
)
138 onServerContact(serverVersion
);
140 for (String fromClient
= bridge
.rec(); fromClient
!= null; fromClient
= bridge
142 onRec(clientVersion
, fromClient
);
143 String fromServer
= send(fromClient
);
144 onSend(serverVersion
, fromServer
);
145 bridge
.send(fromServer
);
148 getTraceHandler().trace("=== DONE", 1);
149 getTraceHandler().trace("", 1);
153 protected void onError(Exception e
) {
154 ServerBridge
.this.onError(e
);
157 } catch (Exception e
) {
158 ServerBridge
.this.onError(e
);
165 * This is the method that is called each time a client contact us.
167 * @param clientVersion
170 protected void onClientContact(Version clientVersion
) {
171 getTraceHandler().trace(">>> CLIENT " + clientVersion
);
175 * This is the method that is called each time a client contact us.
177 * @param serverVersion
180 protected void onServerContact(Version serverVersion
) {
181 getTraceHandler().trace("<<< SERVER " + serverVersion
);
182 getTraceHandler().trace("");
186 * This is the method that is called each time a client contact us.
188 * @param clientVersion
191 * the data sent by the client
193 protected void onRec(Version clientVersion
, String data
) {
194 trace(">>> CLIENT (" + clientVersion
+ ")", data
);
198 * This is the method that is called each time the forwarded server contact
201 * @param serverVersion
204 * the data sent by the client
206 protected void onSend(Version serverVersion
, String data
) {
207 trace("<<< SERVER (" + serverVersion
+ ")", data
);
212 getTraceHandler().trace(
213 getName() + ": will forward to " + forwardToHost
+ ":"
214 + forwardToPort
+ " ("
215 + (forwardToKey
!= null ?
"encrypted" : "plain text")
221 * Trace the data with the given prefix.
224 * the prefix (client, server, version...)
228 private void trace(String prefix
, String data
) {
229 int size
= data
== null ?
0 : data
.length();
230 String ssize
= StringUtils
.formatNumber(size
) + "bytes";
232 getTraceHandler().trace(prefix
+ ": " + ssize
, 1);
234 if (getTraceHandler().getTraceLevel() >= 2) {
236 while (data
.startsWith("ZIP:") || data
.startsWith("B64:")) {
237 if (data
.startsWith("ZIP:")) {
238 data
= StringUtils
.unbase64s(data
.substring(4), true);
239 } else if (data
.startsWith("B64:")) {
240 data
= StringUtils
.unbase64s(data
.substring(4), false);
244 Object obj
= new Importer().read(data
).getValue();
246 getTraceHandler().trace("NULL", 2);
247 getTraceHandler().trace("NULL", 3);
248 getTraceHandler().trace("NULL", 4);
250 if (obj
.getClass().isArray()) {
251 getTraceHandler().trace(
252 "(" + obj
.getClass() + ") with "
253 + Array
.getLength(obj
) + "element(s)",
256 getTraceHandler().trace("(" + obj
.getClass() + ")", 2);
258 getTraceHandler().trace("" + obj
.toString(), 3);
259 getTraceHandler().trace(data
, 4);
261 } catch (NoSuchMethodException e
) {
262 getTraceHandler().trace("(not an object)", 2);
263 getTraceHandler().trace(data
, 3);
264 getTraceHandler().trace("", 4);
265 } catch (NoSuchFieldException e
) {
266 getTraceHandler().trace(
267 "(incompatible: " + e
.getMessage() + ")", 2);
268 getTraceHandler().trace(data
, 3);
269 getTraceHandler().trace("", 4);
270 } catch (ClassNotFoundException e
) {
271 getTraceHandler().trace(
272 "(unknown object: " + e
.getMessage() + ")", 2);
273 getTraceHandler().trace(data
, 3);
274 getTraceHandler().trace("", 4);
275 } catch (Exception e
) {
276 getTraceHandler().trace(
277 "(decode error: " + e
.getMessage() + ")", 2);
278 getTraceHandler().trace(data
, 3);
279 getTraceHandler().trace("", 4);
282 getTraceHandler().trace("", 2);