1 | package dmg.cells.services ; |
2 | |
3 | import java.net.* ; |
4 | import java.io.* ; |
5 | import java.util.* ; |
6 | |
7 | import dmg.cells.nucleus.* ; |
8 | import dmg.util.*; |
9 | |
10 | import org.slf4j.Logger; |
11 | import org.slf4j.LoggerFactory; |
12 | |
13 | public class LocationManager extends CellAdapter { |
14 | |
15 | private final static Logger _log = |
16 | LoggerFactory.getLogger(LocationManager.class); |
17 | |
18 | /** |
19 | */ |
20 | private DatagramSocket _socket = null ; |
21 | private Server _server = null ; |
22 | private Client _client = null ; |
23 | private Args _args = null ; |
24 | private CellNucleus _nucleus = null ; |
25 | // Server Options : -strict[=yes|on|off|no] |
26 | // -perm=<helpFilename> |
27 | // -setupmode=write|rdonly|auto |
28 | // -setup=<setupFile> |
29 | // |
30 | // Client Options : -noboot |
31 | // |
32 | public class Server implements Runnable { |
33 | private class NodeInfo { |
34 | private String _domainName = null ; |
35 | private HashSet _list = new HashSet() ; |
36 | private String _default = null ; |
37 | private boolean _listen = false ; |
38 | private String _address = null ; |
39 | private boolean _defined = true ; |
40 | private int _port = 0 ; |
41 | private String _sec = null ; |
42 | |
43 | private NodeInfo( String domainName ){ |
44 | _domainName = domainName ; |
45 | } |
46 | private NodeInfo( String domainName , boolean defined ){ |
47 | _domainName = domainName ; |
48 | _defined = defined ; |
49 | } |
50 | private boolean isDefined(){ return _defined ; } |
51 | private String getDomainName(){ return _domainName ; } |
52 | private synchronized void setDefault( String defaultNode ){ |
53 | _default = defaultNode ; |
54 | } |
55 | private int getConnectionCount(){ return _list.size() ; } |
56 | private synchronized void add( String nodeName ){ |
57 | _list.add(nodeName); |
58 | } |
59 | private synchronized void remove( String nodeName ){ |
60 | _list.remove( nodeName ) ; |
61 | return; |
62 | } |
63 | private void setListenPort( int port ){ _port = port ; } |
64 | private void setSecurity( String sec ){ _sec = sec ; } |
65 | private void setListen( boolean listen ){ _listen = listen ; } |
66 | private void setAddress( String address ){ _listen=true; _address = address ; } |
67 | |
68 | private String getAddress(){ return _address ; } |
69 | private String getDefault(){ return _default ; } |
70 | private Iterator connections(){ return _list.iterator() ; } |
71 | private boolean mustListen(){ return _listen ; } |
72 | private String getSecurity(){ return _sec ; } |
73 | |
74 | public String toWhatToDoReply( boolean strict ){ |
75 | |
76 | StringBuffer sb = new StringBuffer() ; |
77 | sb.append(_domainName).append(" ") ; |
78 | if( _listen ){ |
79 | |
80 | sb.append( "\"l:" ); |
81 | if( _port > 0 )sb.append(_port) ; |
82 | sb.append(":"); |
83 | if( _sec != null )sb.append(_sec) ; |
84 | sb.append(":"); |
85 | sb.append('"'); |
86 | if( ( ! strict ) && ( _address != null ) )sb.append(" (").append(_address).append(")") ; |
87 | |
88 | }else{ |
89 | sb.append("nl"); |
90 | } |
91 | if( _default != null )sb.append( " d:" ).append( _default ) ; |
92 | Iterator i = connections() ; |
93 | while( i.hasNext() )sb.append(" c:").append(i.next().toString()) ; |
94 | return sb.toString() ; |
95 | } |
96 | public String toString(){ |
97 | return toWhatToDoReply(false); |
98 | } |
99 | |
100 | } |
101 | private final Map<String, NodeInfo> _nodeDb = new HashMap<String, NodeInfo>() ; |
102 | private int _port = 0 ; |
103 | private DatagramSocket _socket = null ; |
104 | private Thread _worker = null ; |
105 | private boolean _strict = true ; |
106 | private int _requestsReceived = 0 ; |
107 | private int _repliesSent = 0 ; |
108 | private int _totalExceptions = 0 ; |
109 | /** |
110 | * Server |
111 | * -strict=yes|no # 'yes' allows any client to register |
112 | * -setup=<setupFile> # full path of setupfile |
113 | * -setupmode=rdonly|rw|auto # write back the setup [def=rw] |
114 | * -perm=<filename> # store registry information |
115 | */ |
116 | private final static int SETUP_NONE = -2 ; |
117 | private final static int SETUP_ERROR = -1 ; |
118 | private final static int SETUP_AUTO = 0 ; |
119 | private final static int SETUP_WRITE = 1 ; |
120 | private final static int SETUP_RDONLY = 2 ; |
121 | private int _setupMode = SETUP_NONE ; |
122 | private String _setupFileName = null ; |
123 | private File _setupFile = null ; |
124 | private File _permFile = null ; |
125 | |
126 | private Server( int port , Args args ) throws Exception { |
127 | _port = port ; |
128 | addCommandListener(this); |
129 | |
130 | String strict = args.getOpt("strict") ; |
131 | if( strict == null ){ |
132 | _strict = true ; |
133 | }else{ |
134 | if( strict.equals("off") || strict.equals("no") ) |
135 | _strict = false ; |
136 | } |
137 | |
138 | prepareSetup( args.getOpt("setup") , args.getOpt("setupmode") ) ; |
139 | if( ( _setupMode == SETUP_WRITE ) || ( _setupMode == SETUP_RDONLY ) ) |
140 | execSetupFile( _setupFile ) ; |
141 | |
142 | preparePersistentMap( args.getOpt( "perm" ) ) ; |
143 | |
144 | try{ loadPersistentMap() ; }catch(Exception dd ){} |
145 | _socket = new DatagramSocket( _port ) ; |
146 | _worker = _nucleus.newThread(this,"Server") ; |
147 | _worker.start() ; |
148 | } |
149 | private void preparePersistentMap( String permFileName ) throws Exception { |
150 | if( ( permFileName == null ) || ( permFileName.length() < 1 ) )return ; |
151 | |
152 | File permFile = new File( permFileName ) ; |
153 | |
154 | if( permFile.exists() ){ |
155 | if( ! permFile.canWrite() ) |
156 | throw new |
157 | IllegalArgumentException( "Can't write to : "+permFileName ) ; |
158 | _permFile = permFile ; |
159 | // loadPersistentMap() ; |
160 | }else{ |
161 | if( ! permFile.createNewFile() ) |
162 | throw new |
163 | IllegalArgumentException( "Can't create : "+permFileName ) ; |
164 | _permFile = permFile ; |
165 | } |
166 | _log.info("Persistent map file set to : "+_permFile); |
167 | return; |
168 | } |
169 | private synchronized void loadPersistentMap() throws Exception { |
170 | if( _permFile == null )return ; |
171 | ObjectInputStream in = new ObjectInputStream( |
172 | new FileInputStream( _permFile ) ) ; |
173 | Map<String, String> hm = null ; |
174 | _log.info("Loading persistent map file"); |
175 | try{ |
176 | hm = (HashMap)in.readObject() ; |
177 | |
178 | _log.info("Persistent map : "+hm); |
179 | |
180 | for(Map.Entry<String, String> node_and_address: hm.entrySet()) { |
181 | |
182 | String node = node_and_address.getKey(); |
183 | String address = node_and_address.getValue(); |
184 | |
185 | NodeInfo info = getInfo( node , true ) ; |
186 | if( info == null )continue ; |
187 | info.setAddress( node ) ; |
188 | _log.info( "Updated : <"+node+"> -> "+address ) ; |
189 | } |
190 | |
191 | }catch(Exception ee){ |
192 | _log.warn("Problem reading persistent map "+ee.getMessage() ); |
193 | _permFile.delete() ; |
194 | }finally{ |
195 | try{ in.close() ; }catch(IOException ee){} |
196 | } |
197 | |
198 | } |
199 | private synchronized void savePersistentMap() throws Exception { |
200 | if( _permFile == null )return ; |
201 | |
202 | Map<String, String> hm = new HashMap<String, String>() ; |
203 | |
204 | for( NodeInfo info: _nodeDb.values() ){ |
205 | String address = info.getAddress() ; |
206 | if( ( address != null ) && info.mustListen() ) |
207 | hm.put( info.getDomainName() , info.getAddress() ) ; |
208 | } |
209 | ObjectOutputStream out = null; |
210 | |
211 | try{ |
212 | out = new ObjectOutputStream( new FileOutputStream( _permFile ) ) ; |
213 | out.writeObject( hm ) ; |
214 | }catch(Exception e){ |
215 | _log.warn("Problem writing persistent map "+e.getMessage() ); |
216 | _permFile.delete() ; |
217 | }finally{ |
218 | if(out != null) try{ out.close() ; }catch(Exception ee){} |
219 | } |
220 | return ; |
221 | } |
222 | private void prepareSetup( String setupFile , String setupMode ) throws Exception { |
223 | |
224 | if( ( _setupFileName = setupFile ) == null ){ |
225 | _setupMode = SETUP_NONE ; |
226 | return ; |
227 | } |
228 | String tmp = setupMode ; |
229 | |
230 | _setupMode = tmp == null ? SETUP_AUTO : |
231 | tmp.equals("rw") ? SETUP_WRITE : |
232 | tmp.equals("rdonly") ? SETUP_RDONLY : |
233 | tmp.equals("auto") ? SETUP_AUTO : |
234 | SETUP_ERROR ; |
235 | |
236 | if( _setupMode == SETUP_ERROR ) |
237 | throw new |
238 | IllegalArgumentException( |
239 | "Setup error, don't understand : "+_setupMode); |
240 | |
241 | _setupFile = new File( _setupFileName ) ; |
242 | |
243 | boolean fileExists = false , canWrite = false ; |
244 | try{ |
245 | fileExists = _setupFile.exists() ; |
246 | canWrite = _setupFile.canWrite() ; |
247 | }catch(Exception ee ){ |
248 | _log.warn("Can't check setup file <"+_setupFileName+"> : "+ee.getMessage(), ee) ; |
249 | throw ee ; |
250 | } |
251 | if( fileExists && ! _setupFile.isFile() ) |
252 | throw new |
253 | IllegalArgumentException("Not a file : "+_setupFileName ) ; |
254 | |
255 | if( _setupMode == SETUP_AUTO ){ |
256 | if( fileExists ){ |
257 | _setupMode = canWrite ? SETUP_WRITE : SETUP_RDONLY ; |
258 | return ; |
259 | } |
260 | if( ! _setupFile.createNewFile() ) |
261 | throw new |
262 | IllegalArgumentException( |
263 | "File doesn't exist and can't be created : "+_setupFileName ) ; |
264 | _setupMode = SETUP_WRITE ; |
265 | }else if( _setupMode == SETUP_WRITE ){ |
266 | // |
267 | // readwrite case |
268 | // |
269 | if( fileExists ){ |
270 | |
271 | if( canWrite )return ; |
272 | throw new |
273 | IllegalArgumentException( |
274 | "File not writeable : "+_setupFileName ) ; |
275 | } |
276 | if( ! _setupFile.createNewFile() ) |
277 | throw new |
278 | IllegalArgumentException( |
279 | "File doesn't exist and can't be created : "+_setupFileName ) ; |
280 | |
281 | }else if( _setupMode == SETUP_RDONLY ){ |
282 | if( ! fileExists ) |
283 | throw new |
284 | IllegalArgumentException( |
285 | "Setupfile not found : "+_setupFileName) ; |
286 | |
287 | if( ! _setupFile.canRead() ) |
288 | throw new |
289 | IllegalArgumentException( |
290 | "Setupfile not readable : "+_setupFileName) ; |
291 | }else if( _setupMode == SETUP_NONE ){ |
292 | _setupFileName = null ; |
293 | } |
294 | return ; |
295 | } |
296 | private void execSetupFile( File setupFile )throws Exception { |
297 | BufferedReader br = new BufferedReader( new FileReader( setupFile ) ) ; |
298 | String line = null ; |
299 | try{ |
300 | while( ( line = br.readLine() ) != null ){ |
301 | if( line.length() < 1 )continue ; |
302 | if( line.charAt(0) == '#' )continue ; |
303 | _log.info("Exec : "+line) ; |
304 | command( new Args(line) ) ; |
305 | } |
306 | }catch( EOFException eof ){ |
307 | }catch( Exception ef ){ |
308 | _log.warn("Ups : "+ef ) ; |
309 | }finally{ |
310 | try{ br.close() ; }catch(Exception ce ){} |
311 | } |
312 | return ; |
313 | } |
314 | public void getInfo( PrintWriter pw ){ |
315 | pw.println( " Version : $Id: LocationManager.java,v 1.15 2007-10-22 12:30:38 behrmann Exp $") ; |
316 | pw.println( " # of nodes : "+_nodeDb.size() ) ; |
317 | pw.println( "RequestsReceived : "+_requestsReceived ) ; |
318 | pw.println( " RepliesSent : "+_repliesSent) ; |
319 | pw.println( " Exceptions : "+_totalExceptions) ; |
320 | } |
321 | public String toString(){ |
322 | return "Server:Nodes="+_nodeDb.size()+";Reqs="+_requestsReceived; |
323 | } |
324 | public void run(){ |
325 | DatagramPacket packet = null ; |
326 | while (!Thread.currentThread().isInterrupted()){ |
327 | try{ |
328 | packet = new DatagramPacket(new byte[1024],1024) ; |
329 | _socket.receive(packet); |
330 | }catch(Exception ie){ |
331 | _log.warn("Exception in Server receive loop (exiting)", ie); |
332 | break ; |
333 | } |
334 | try{ |
335 | process( packet ) ; |
336 | _socket.send(packet); |
337 | }catch(Exception se ){ |
338 | _log.warn("Exception in send ", se); |
339 | } |
340 | } |
341 | _socket.close(); |
342 | } |
343 | public void process( DatagramPacket packet )throws Exception{ |
344 | byte [] data = packet.getData() ; |
345 | int datalen = packet.getLength() ; |
346 | InetAddress address = packet.getAddress() ; |
347 | if( datalen <= 0 ){ |
348 | _log.warn( "Empty Packet arrived from "+packet.getAddress() ) ; |
349 | return ; |
350 | } |
351 | String message = new String( data , 0 , datalen ) ; |
352 | _log.info( "server query : ["+address+"] "+"("+message.length()+") "+message) ; |
353 | |
354 | message = (String)command( new Args( message ) ) ; |
355 | |
356 | _log.info( "server reply : "+message ) ; |
357 | data = message.getBytes() ; |
358 | packet.setData(data) ; |
359 | packet.setLength(data.length); |
360 | return ; |
361 | } |
362 | private void createSetup( PrintWriter pw ){ |
363 | pw.println( "#") ; |
364 | pw.println( "# This setup was created by the LocationManager at "+( new Date().toString())); |
365 | pw.println( "#" ) ; |
366 | Iterator i = _nodeDb.values().iterator() ; |
367 | while( i.hasNext() ){ |
368 | NodeInfo info = (NodeInfo)i.next() ; |
369 | pw.println( "define "+info.getDomainName() ) ; |
370 | if( info.mustListen() )pw.println( "listen "+info.getDomainName() ) ; |
371 | String def = info.getDefault() ; |
372 | if( def != null )pw.println( "defaultroute "+info.getDomainName()+" "+def ) ; |
373 | Iterator j = info.connections() ; |
374 | while( j.hasNext() ) |
375 | pw.println( "connect "+info.getDomainName()+" "+j.next().toString() ) ; |
376 | |
377 | } |
378 | } |
379 | /** |
380 | * command interface |
381 | */ |
382 | private final String [] __mode2string = |
383 | { "none" , "error" , "auto" , "rw" , "rdonly" } ; |
384 | private String setupToString( int mode ){ |
385 | if( ( mode < -2 ) || ( mode > 2 ) )return "?("+mode+")" ; |
386 | return __mode2string[mode+2] ; |
387 | } |
388 | public String hh_ls_perm = " # list permanent file" ; |
389 | public String ac_ls_perm( Args args ) throws Exception { |
390 | if( _permFile == null ) |
391 | throw new |
392 | IllegalArgumentException("Permamanet file not defined" ) ; |
393 | |
394 | ObjectInputStream in = new ObjectInputStream( |
395 | new FileInputStream( _permFile ) ) ; |
396 | Map<String, String> hm = null ; |
397 | try{ |
398 | hm = (HashMap)in.readObject() ; |
399 | }finally{ |
400 | if( in != null) try{ in.close() ; }catch(Exception ee){} |
401 | } |
402 | |
403 | StringBuilder sb = new StringBuilder() ; |
404 | for(Map.Entry<String, String> node_and_address: hm.entrySet()) { |
405 | |
406 | String node = node_and_address.getKey() ; |
407 | String address = node_and_address.getValue() ; |
408 | |
409 | sb.append(node).append(" -> ").append(address).append("\n"); |
410 | } |
411 | return sb.toString() ; |
412 | |
413 | } |
414 | public String hh_setup_define = "<filename> [-mode=rw|rdonly|auto]" ; |
415 | public String ac_setup_define_$_1( Args args )throws Exception { |
416 | String filename = args.argv(0); |
417 | prepareSetup( filename , args.getOpt( "mode" ) ) ; |
418 | return "setupfile (mode="+setupToString(_setupMode)+") : "+filename ; |
419 | } |
420 | public String hh_setup_read = "" ; |
421 | public String ac_setup_read( Args args )throws Exception { |
422 | if( _setupFileName == null ) |
423 | throw new |
424 | IllegalArgumentException( "Setupfile not defined" ) ; |
425 | |
426 | try{ |
427 | execSetupFile( _setupFile ) ; |
428 | }catch(Exception ee){ |
429 | throw new |
430 | Exception( "Problem in setupFile : "+ee.getMessage()); |
431 | } |
432 | return "" ; |
433 | |
434 | } |
435 | public String hh_setup_write = "" ; |
436 | public String ac_setup_write( Args args )throws Exception { |
437 | if( _setupMode != SETUP_WRITE ) |
438 | throw new |
439 | IllegalArgumentException("Setupfile not in write mode" ) ; |
440 | |
441 | File tmpFile = new File( _setupFile.getParent() , "$-"+_setupFile.getName() ) ; |
442 | PrintWriter pw = new PrintWriter( new FileWriter( tmpFile ) ) ; |
443 | try{ |
444 | createSetup( pw ) ; |
445 | }catch(Exception ee ){ |
446 | throw ee ; |
447 | }finally{ |
448 | try{ pw.close() ; }catch(Exception eee){} |
449 | } |
450 | if( ! tmpFile.renameTo( _setupFile ) ) |
451 | throw new |
452 | IOException("Failed to replace setupFile" ) ; |
453 | |
454 | return "" ; |
455 | |
456 | } |
457 | private synchronized NodeInfo getInfo( String nodeName , boolean create ){ |
458 | NodeInfo info = (NodeInfo)_nodeDb.get(nodeName) ; |
459 | if( ( info != null ) || ! create )return info ; |
460 | _nodeDb.put( nodeName , info = new NodeInfo( nodeName ) ) ; |
461 | return info ; |
462 | } |
463 | public String hh_define = "<domainName>" ; |
464 | public String ac_define_$_1( Args args ){ |
465 | getInfo( args.argv(0) , true ) ; |
466 | return "" ; |
467 | } |
468 | public String hh_undefine = "<domainName>" ; |
469 | public String ac_undefine_$_1( Args args ){ |
470 | String nodeName = args.argv(0) ; |
471 | _nodeDb.remove( nodeName ) ; |
472 | Iterator i = _nodeDb.values().iterator() ; |
473 | while( i.hasNext() ) ((NodeInfo)i.next()).remove( nodeName ) ; |
474 | return "" ; |
475 | } |
476 | public String hh_nodefaultroute = "<sourceDomainName>" ; |
477 | public String ac_nodefaultroute_$_1( Args args ){ |
478 | NodeInfo info = getInfo( args.argv(0) , false ) ; |
479 | if( info == null )return ""; |
480 | info.setDefault( null ) ; |
481 | return "" ; |
482 | } |
483 | public String hh_defaultroute = "<sourceDomainName> <destinationDomainName>" ; |
484 | public String ac_defaultroute_$_2( Args args ){ |
485 | getInfo( args.argv(1) , true ) ; |
486 | getInfo( args.argv(0) , true ).setDefault( args.argv(1) ) ; |
487 | return "" ; |
488 | } |
489 | public String hh_connect = "<sourceDomainName> <destinationDomainName>" ; |
490 | public String ac_connect_$_2( Args args ){ |
491 | NodeInfo dest = getInfo( args.argv(1) , true ) ; |
492 | dest.setListen(true); |
493 | getInfo( args.argv(0) , true ).add( args.argv(1) ) ; |
494 | return "" ; |
495 | } |
496 | public String hh_disconnect = "<sourceDomainName> <destinationDomainName>" ; |
497 | public String ac_disconnect_$_2( Args args ){ |
498 | NodeInfo info = getInfo( args.argv(0) , false ) ; |
499 | if( info == null )return ""; |
500 | info.remove( args.argv(1) ) ; |
501 | return "" ; |
502 | |
503 | } |
504 | public String hh_listen = "<listenDomainName> [...] [-port=<portNumber>] [-security=<security>]" ; |
505 | public String ac_listen_$_1_99( Args args ){ |
506 | int port = 0 ; |
507 | String portString = args.getOpt("port") ; |
508 | if( portString != null )port = Integer.parseInt(portString); |
509 | String secString = args.getOpt("security"); |
510 | |
511 | for( int i = 0 ; i < args.argc() ; i++ ){ |
512 | NodeInfo info = getInfo( args.argv(i) , true ) ; |
513 | info.setListen(true) ; |
514 | if( port > 0 )info.setListenPort( port ) ; |
515 | if( ( secString != null ) && |
516 | ( secString.length() > 0 ) && |
517 | ! secString.equalsIgnoreCase("none") )info.setSecurity( secString ) ; |
518 | } |
519 | return "" ; |
520 | } |
521 | public String hh_unlisten = "<listenDomainName> [...]" ; |
522 | public String ac_unlisten_$_1_99( Args args ){ |
523 | for( int i = 0 ; i < args.argc() ; i++ ){ |
524 | NodeInfo info = getInfo( args.argv(i) , false ) ; |
525 | if( info == null )continue ; |
526 | info.setListen(false) ; |
527 | } |
528 | return "" ; |
529 | } |
530 | public String hh_ls_setup = "" ; |
531 | public String ac_ls_setup( Args args ){ |
532 | StringWriter sw = new StringWriter() ; |
533 | PrintWriter pw = new PrintWriter( sw ) ; |
534 | createSetup( pw ) ; |
535 | pw.flush() ; |
536 | sw.flush() ; |
537 | return sw.getBuffer().toString() ; |
538 | } |
539 | public String hh_ls_node = "[<domainName>]" ; |
540 | public String ac_ls_node_$_0_1( Args args ){ |
541 | if( args.argc() == 0 ){ |
542 | Iterator i = _nodeDb.values().iterator() ; |
543 | StringBuffer sb = new StringBuffer() ; |
544 | while( i.hasNext() )sb.append( i.next().toString() ).append("\n") ; |
545 | return sb.toString() ; |
546 | }else{ |
547 | NodeInfo info = getInfo(args.argv(0),false); |
548 | if( info == null ) |
549 | throw new |
550 | IllegalArgumentException( "Node not found : "+args.argv(0)); |
551 | return info.toString() ; |
552 | } |
553 | } |
554 | public String hh_set_address = "<domainname> <address>" ; |
555 | public String ac_set_address_$_2( Args args ){ |
556 | NodeInfo info = getInfo(args.argv(0),false) ; |
557 | if( info == null ) |
558 | throw new |
559 | IllegalArgumentException( "Domain not defined : "+args.argv(0)); |
560 | |
561 | if( ! info.mustListen() ) |
562 | throw new |
563 | IllegalArgumentException( "Domain won't listen : "+args.argv(0)); |
564 | |
565 | info.setAddress( args.argv(1) ) ; |
566 | try { savePersistentMap() ; }catch(Exception eee){} |
567 | return info.toString() ; |
568 | } |
569 | public String hh_unset_address = "<domainname>" ; |
570 | public String ac_unset_address_$_1( Args args ){ |
571 | NodeInfo info = getInfo(args.argv(0),false) ; |
572 | if( info == null ) |
573 | throw new |
574 | IllegalArgumentException( "Domain not defined : "+args.argv(0)); |
575 | |
576 | info.setAddress( null ) ; |
577 | try { savePersistentMap() ; }catch(Exception eee){} |
578 | return info.toString() ; |
579 | } |
580 | public String hh_clear_server = "" ; |
581 | public String ac_clear_server( Args args ){ |
582 | _nodeDb.clear() ; |
583 | return "" ; |
584 | } |
585 | public String hh_whatToDo = "<domainName>" ; |
586 | public String ac_whatToDo_$_1( Args args ){ |
587 | NodeInfo info = getInfo( args.argv(0) , false ) ; |
588 | if( info == null ){ |
589 | if( _strict || ( ( info = getInfo( "*" , false ) ) == null ) ) |
590 | throw new |
591 | IllegalArgumentException( "Domain not defined : "+args.argv(0) ); |
592 | |
593 | } |
594 | String tmp = null ; |
595 | String serial = ( tmp = args.getOpt("serial") ) != null ? |
596 | ( "-serial="+tmp ) : "" ; |
597 | return "do "+serial+" "+info.toWhatToDoReply(true) ; |
598 | } |
599 | public String hh_whereIs = "<domainName>" ; |
600 | public String ac_whereIs_$_1( Args args ){ |
601 | NodeInfo info = getInfo( args.argv(0) , false ) ; |
602 | if( info == null ) |
603 | throw new |
604 | IllegalArgumentException( "Domain not defined : "+args.argv(0) ); |
605 | String tmp = null ; |
606 | String serial = ( tmp = args.getOpt("serial") ) != null ? |
607 | ( "-serial="+tmp ) : "" ; |
608 | |
609 | StringBuffer sb = new StringBuffer() ; |
610 | sb.append("location ").append(serial).append(" ").append(info.getDomainName()) ; |
611 | String out = info.getAddress() ; |
612 | sb.append(" ").append( out == null ? "none" : out ) ; |
613 | out = info.getSecurity() ; |
614 | if( out != null )sb.append(" -security=\"").append(out).append("\""); ; |
615 | |
616 | return sb.toString() ; |
617 | } |
618 | public String hh_listeningOn = "<domainName> <address>" ; |
619 | public String ac_listeningOn_$_2( Args args ){ |
620 | String nodeName = args.argv(0); |
621 | NodeInfo info = getInfo( nodeName , false ) ; |
622 | if( info == null ){ |
623 | if( _strict ) |
624 | throw new |
625 | IllegalArgumentException( "Domain not defined : "+nodeName ); |
626 | |
627 | _nodeDb.put( nodeName , info = new NodeInfo( nodeName , false ) ) ; |
628 | } |
629 | info.setAddress( args.argv(1).equals("none") ? null : args.argv(1) ) ; |
630 | try { savePersistentMap() ; }catch(Exception eee){} |
631 | String tmp = null ; |
632 | String serial = ( tmp = args.getOpt("serial") ) != null ? |
633 | ( "-serial="+tmp ) : "" ; |
634 | return "listenOn "+serial+ |
635 | " "+info.getDomainName()+ |
636 | " "+( info.getAddress() == null ? "none" : info.getAddress() ) ; |
637 | } |
638 | |
639 | /** |
640 | * Shutdown the server. Notice that the method will not wait |
641 | * for the worker thread to shut down. |
642 | */ |
643 | public void shutdown() |
644 | { |
645 | _worker.interrupt(); |
646 | _socket.close(); |
647 | } |
648 | } |
649 | |
650 | private class LocationManagerHandler implements Runnable { |
651 | |
652 | private DatagramSocket _socket = null ; |
653 | private Map<Integer, StringBuffer> _map = new HashMap<Integer, StringBuffer>() ; |
654 | private int _serial = 0 ; |
655 | private InetAddress _address = null ; |
656 | private int _port = 0 ; |
657 | private Thread _thread = null ; |
658 | |
659 | private int _requestsSent = 0 ; |
660 | private int _repliesReceived = 0 ; |
661 | |
662 | private LocationManagerHandler( InetAddress address , int port ) throws Exception { |
663 | _port = port ; |
664 | _socket = new DatagramSocket( ) ; |
665 | _address = address ; |
666 | _thread = _nucleus.newThread( this , "LocationManagerHandler" ) ; |
667 | } |
668 | public void start(){ |
669 | _thread.start() ; |
670 | } |
671 | public int getRequestsSent(){ return _requestsSent ; } |
672 | public int getRepliesReceived(){ return _repliesReceived ; } |
673 | |
674 | public void run() |
675 | { |
676 | DatagramPacket packet = null; |
677 | while (!Thread.currentThread().isInterrupted()) { |
678 | try { |
679 | packet = new DatagramPacket(new byte[1024], 1024); |
680 | |
681 | _socket.receive(packet); |
682 | |
683 | byte [] data = packet.getData(); |
684 | int packLen = packet.getLength(); |
685 | |
686 | if ((data == null) || (packLen == 0)) { |
687 | _log.warn("Zero packet received"); |
688 | continue; |
689 | } |
690 | |
691 | Args a = new Args(new String(data, 0, packLen)); |
692 | String tmp = a.getOpt("serial"); |
693 | if (tmp == null) { |
694 | _log.warn("Packet didn't provide a serial number"); |
695 | continue; |
696 | } |
697 | |
698 | Integer s = Integer.valueOf(tmp); |
699 | StringBuffer b = _map.get(s); |
700 | if (b == null) { |
701 | _log.warn("Not waiting for " + s); |
702 | continue; |
703 | } |
704 | |
705 | _log.info("Reasonable reply arrived (" + s + ") : " + b); |
706 | |
707 | synchronized (b) { |
708 | b.append(a.toString()); |
709 | b.notifyAll(); |
710 | } |
711 | } catch (InterruptedIOException e) { |
712 | Thread.currentThread().interrupt(); |
713 | } catch (SocketException e) { |
714 | if (!Thread.currentThread().isInterrupted()) { |
715 | _log.warn("Receiver socket problem : " + e.getMessage()); |
716 | } |
717 | } catch (IOException e) { |
718 | _log.warn("Receiver IO problem : " + e.getMessage()); |
719 | } |
720 | } |
721 | _log.info("Receiver thread finished"); |
722 | } |
723 | |
724 | private String askServer( String message , long waitTime ) |
725 | throws IOException, InterruptedException |
726 | { |
727 | _requestsSent ++ ; |
728 | |
729 | int serial ; |
730 | synchronized( this ){ serial = (_serial++) ; } |
731 | |
732 | byte [] data = ( message+" -serial="+serial ).getBytes() ; |
733 | |
734 | StringBuffer b = new StringBuffer() ; |
735 | DatagramPacket packet = null ; |
736 | |
737 | Integer s = Integer.valueOf( serial ) ; |
738 | long rest = waitTime ; |
739 | long start = System.currentTimeMillis() ; |
740 | long now = 0 ; |
741 | |
742 | |
743 | _log.info( "Sending to "+_address+":"+_port+" : "+new String(data,0,data.length)); |
744 | |
745 | synchronized( b ){ |
746 | |
747 | packet = new DatagramPacket( data , data.length , _address , _port ) ; |
748 | _map.put( s , b ) ; |
749 | _socket.send( packet ) ; |
750 | while( rest > 0 ){ |
751 | b.wait( rest ) ; |
752 | if( b.length() > 0 ){ |
753 | _repliesReceived++ ; |
754 | _map.remove( s ) ; |
755 | return b.toString() ; |
756 | } |
757 | now = System.currentTimeMillis() ; |
758 | rest -= ( now - start ) ; |
759 | start = now ; |
760 | } |
761 | _map.remove(s); |
762 | } |
763 | throw new IOException( "Request timed out" ) ; |
764 | } |
765 | |
766 | /** |
767 | * Shutdown the client. Notice that the method will not wait |
768 | * for the worker thread to shut down. |
769 | */ |
770 | public void shutdown() |
771 | { |
772 | _thread.interrupt(); |
773 | _socket.close(); |
774 | } |
775 | |
776 | } |
777 | public class Client implements Runnable { |
778 | |
779 | private Thread _receiver = null; |
780 | private Thread _whatToDo = null; |
781 | private String _toDo = null ; |
782 | private String _registered = null ; |
783 | private int _state = 0 ; |
784 | private int _requestsReceived = 0 ; |
785 | private int _repliesSent = 0 ; |
786 | private int _totalExceptions = 0 ; |
787 | |
788 | private LocationManagerHandler _lmHandler = null ; |
789 | |
790 | private Client( InetAddress address , int port , Args args ) throws Exception { |
791 | |
792 | addCommandListener(this); |
793 | |
794 | _lmHandler = new LocationManagerHandler( address , port ) ; |
795 | _lmHandler.start() ; |
796 | |
797 | if( args.getOpt("noboot") == null ){ |
798 | _whatToDo = _nucleus.newThread(this,"WhatToDo"); |
799 | _whatToDo.start() ; |
800 | } |
801 | |
802 | } |
803 | public void getInfo( PrintWriter pw ){ |
804 | pw.println( " ToDo : "+(_state>-1?("Still Busy ("+_state+")"):_toDo)); |
805 | pw.println( " Registered : "+(_registered==null?"no":_registered) ) ; |
806 | pw.println( "RequestsReceived : "+_requestsReceived ) ; |
807 | pw.println( " RequestsSent : "+_lmHandler.getRequestsSent() ) ; |
808 | pw.println( " RepliesReceived : "+_lmHandler.getRepliesReceived() ) ; |
809 | pw.println( " RepliesSent : "+_repliesSent) ; |
810 | pw.println( " Exceptions : "+_totalExceptions) ; |
811 | } |
812 | public String toString(){ |
813 | return ""+(_state>-1?("Client<init>("+_state+")"):"ClientReady") ; |
814 | } |
815 | private class BackgroundServerRequest implements Runnable { |
816 | |
817 | private String _request = null ; |
818 | private CellMessage _message = null ; |
819 | |
820 | private BackgroundServerRequest( String request , CellMessage message ){ |
821 | _request = request ; |
822 | _message = message ; |
823 | } |
824 | public void run(){ |
825 | try{ |
826 | |
827 | String reply = _lmHandler.askServer( _request , 4000 ) ; |
828 | |
829 | _message.setMessageObject( reply ) ; |
830 | _message.revertDirection() ; |
831 | sendMessage(_message); |
832 | |
833 | _repliesSent++; |
834 | |
835 | }catch(Exception ee){ |
836 | _log.warn("Problem in 'whereIs' request : "+ee ) ; |
837 | _totalExceptions ++ ; |
838 | } |
839 | } |
840 | |
841 | } |
842 | public String ac_where_is_$_1( Args args ){ |
843 | |
844 | _requestsReceived++ ; |
845 | |
846 | String domainName = args.argv(0) ; |
847 | |
848 | _nucleus.newThread( |
849 | new BackgroundServerRequest( "whereIs "+domainName , getThisMessage() ) , |
850 | "where-is" ).start() ; |
851 | |
852 | return null ; |
853 | } |
854 | // |
855 | // |
856 | // create dmg.cells.services.LocationManager lm "11111" |
857 | // |
858 | // create dmg.cells.network.LocationMgrTunnel connect "dCache lm" |
859 | // |
860 | // create dmg.cells.services.login.LoginManager listen |
861 | // "0 dmg.cells.network.LocationMgrTunnel -prot=raw -lm=lm" |
862 | // |
863 | public String ac_listening_on_$_2( Args args ){ |
864 | |
865 | CellMessage msg = getThisMessage() ; |
866 | String portString = args.argv(1) ; |
867 | |
868 | try{ |
869 | _registered = InetAddress.getLocalHost().getHostName()+":"+portString ; |
870 | }catch( java.net.UnknownHostException uhe ){ |
871 | _log.warn("Couldn't resolve hostname : "+uhe); |
872 | return null ; |
873 | } |
874 | |
875 | String request = "listeningOn "+getCellDomainName()+" "+_registered ; |
876 | |
877 | _requestsReceived++ ; |
878 | |
879 | _nucleus.newThread( new BackgroundServerRequest( request , msg ) ).start() ; |
880 | |
881 | return null ; |
882 | } |
883 | private void startListener( int port , String securityContext ) throws Exception { |
884 | String cellName = "l*" ; |
885 | String inetClass = "dmg.cells.services.login.LoginManager" ; |
886 | String cellClass = "dmg.cells.network.LocationMgrTunnel" ; |
887 | String protocol = null ; |
888 | if( ( securityContext == null ) || |
889 | ( securityContext.length() == 0 ) || |
890 | ( securityContext.equalsIgnoreCase("none") ) ){ |
891 | |
892 | protocol = "-prot=raw" ; |
893 | |
894 | }else if( securityContext.equalsIgnoreCase("ssh") || |
895 | securityContext.equalsIgnoreCase("ssh1") ){ |
896 | |
897 | protocol = "-prot=ssh -auth=dmg.cells.services.login.SshSAuth_A" ; |
898 | |
899 | }else{ |
900 | protocol = securityContext ; |
901 | } |
902 | String cellArgs = ""+port+" "+cellClass+" "+protocol+" -lm="+getCellName(); |
903 | _log.info(" LocationManager starting acceptor with "+cellArgs ) ; |
904 | Cell c = _nucleus.createNewCell( inetClass , cellName , cellArgs , true ) ; |
905 | _log.info( "Created : "+c ) ; |
906 | return ; |
907 | } |
908 | |
909 | private void startConnector(final String remoteDomain) |
910 | throws Exception |
911 | { |
912 | String cellName = "c-"+remoteDomain+"*"; |
913 | String cellClass = "dmg.cells.network.LocationManagerConnector"; |
914 | |
915 | String clientKey = _args.getOpt("clientKey") ; |
916 | clientKey = ( clientKey != null ) && ( clientKey.length() > 0 ) ? |
917 | ("-clientKey="+clientKey ) : "" ; |
918 | String clientName = _args.getOpt("clientUserName") ; |
919 | clientName = ( clientName != null ) && ( clientName.length() > 0 ) ? |
920 | ("-clientUserName="+clientName ) : "" ; |
921 | |
922 | String cellArgs = |
923 | "-domain=" + remoteDomain + " " |
924 | + "-lm=" + getCellName() + " " |
925 | + clientKey + " " |
926 | + clientName; |
927 | |
928 | _log.info("LocationManager starting connector with " + cellArgs); |
929 | Cell c = _nucleus.createNewCell(cellClass, cellName, cellArgs, true); |
930 | _log.info("Created : " + c); |
931 | } |
932 | |
933 | private void setDefaultRoute( String domain ) throws Exception { |
934 | _nucleus.routeAdd( new CellRoute( null , "*@"+domain , CellRoute.DEFAULT ) ) ; |
935 | } |
936 | public void run(){ |
937 | if( Thread.currentThread() == _whatToDo )runWhatToDo() ; |
938 | } |
939 | /** |
940 | * loop until it gets a reasonable 'what to do' list. |
941 | */ |
942 | private void runWhatToDo(){ |
943 | |
944 | String request = "whatToDo "+getCellDomainName() ; |
945 | |
946 | while( true ){ |
947 | |
948 | _state ++ ; |
949 | |
950 | try{ |
951 | |
952 | String reply = _lmHandler.askServer( request , 5000 ) ; |
953 | _log.info( "whatToDo got : "+reply ) ; |
954 | |
955 | Args args = new Args( reply ) ; |
956 | |
957 | if( args.argc() < 2 ) |
958 | throw new |
959 | IllegalArgumentException( "No enough arg. : "+reply ) ; |
960 | |
961 | if( ( ! args.argv(0).equals("do" ) ) || |
962 | ( ! ( args.argv(1).equals(getCellDomainName()) || |
963 | args.argv(1).equals("*") ) ) ) |
964 | throw new |
965 | IllegalArgumentException("Not a 'do' or not for us : "+reply ) ; |
966 | |
967 | if( args.argc() == 2 ){ |
968 | _log.info("Nothing to do for us"); |
969 | return ; |
970 | } |
971 | |
972 | executeToDoList( args ) ; |
973 | |
974 | _toDo = reply ; |
975 | _state = -1 ; |
976 | |
977 | return ; |
978 | |
979 | }catch(InterruptedException ie ){ |
980 | _log.warn( _toDo = "whatToDo : interrupted" ) ; |
981 | break ; |
982 | }catch(InterruptedIOException ie ){ |
983 | _log.warn( _toDo = "whatToDo : interrupted(io)" ) ; |
984 | break ; |
985 | }catch(Exception ee ){ |
986 | _log.warn(_toDo = "whatToDo : exception : "+ee ) ; |
987 | } |
988 | try{ |
989 | Thread.sleep(10000) ; |
990 | }catch(InterruptedException iie ){ |
991 | _log.warn(_toDo = "whatToDo : interrupted sleep") ; |
992 | break ; |
993 | } |
994 | } |
995 | _log.info( "whatToDo finished" ) ; |
996 | |
997 | } |
998 | /** |
999 | * Gets the reply from the 'server' and can |
1000 | * i) create a connector |
1001 | * ii) listens to a given port |
1002 | * iii) sets a default route |
1003 | * |
1004 | * or all of it. |
1005 | */ |
1006 | private void executeToDoList( Args args ) throws Exception { |
1007 | for( int i = 2 ; i < args.argc() ; i++ ){ |
1008 | |
1009 | String arg = args.argv(i) ; |
1010 | |
1011 | try{ |
1012 | // |
1013 | // expected formats |
1014 | // l:[<portNumber>]:[<securityContext>] |
1015 | // c:<DomainName> |
1016 | // d:<DomainName> |
1017 | // |
1018 | if( arg.startsWith("l") ){ |
1019 | int port = 0 ; |
1020 | StringTokenizer st = new StringTokenizer(arg,":"); |
1021 | // |
1022 | // get rid of the 'l' |
1023 | // |
1024 | st.nextToken() ; |
1025 | // |
1026 | // get the port if availble |
1027 | // |
1028 | if( st.hasMoreTokens() ){ |
1029 | String tmp = st.nextToken() ; |
1030 | if( tmp.length() > 0 ) |
1031 | try{ |
1032 | port = Integer.parseInt(tmp); |
1033 | }catch(Exception e ){ |
1034 | _log.warn("Got illegal port numnber <"+arg+">, using random"); |
1035 | } |
1036 | } |
1037 | // |
1038 | // get the security context |
1039 | // |
1040 | String securityContext = null ; |
1041 | if( st.hasMoreTokens() )securityContext = st.nextToken() ; |
1042 | |
1043 | startListener( port , securityContext ) ; |
1044 | |
1045 | }else if( ( arg.length() > 2 ) && |
1046 | arg.startsWith("c:") ){ |
1047 | |
1048 | startConnector(arg.substring(2)) ; |
1049 | |
1050 | }else if( ( arg.length() > 2 ) && |
1051 | arg.startsWith("d:") ){ |
1052 | |
1053 | setDefaultRoute(arg.substring(2)) ; |
1054 | |
1055 | } |
1056 | }catch(InterruptedIOException ioee ){ |
1057 | throw ioee ; |
1058 | }catch(InterruptedException iee ){ |
1059 | throw iee ; |
1060 | }catch(Exception ee ){ |
1061 | _log.warn("Command >"+arg+"< received : "+ee ) ; |
1062 | } |
1063 | } |
1064 | |
1065 | } |
1066 | |
1067 | /** |
1068 | * Shutdown the client. Notice that the method will not wait |
1069 | * for the worker thread to shut down. |
1070 | */ |
1071 | public void shutdown() |
1072 | { |
1073 | _lmHandler.shutdown(); |
1074 | } |
1075 | |
1076 | } |
1077 | /** |
1078 | * Usage : ... [<host>] <port> -noclient |
1079 | * Server Options : -strict=[yes|no] -perm=<helpFilename> -setup=<setupFile> |
1080 | * |
1081 | */ |
1082 | public LocationManager( String name , String args )throws Exception { |
1083 | super( name , args , false ) ; |
1084 | _args = getArgs() ; |
1085 | _nucleus = getNucleus() ; |
1086 | String tmp = null ; |
1087 | try{ |
1088 | int port = 0 ; |
1089 | InetAddress host = null ; |
1090 | if( _args.argc() < 1 ) |
1091 | throw new |
1092 | IllegalArgumentException("Usage : ... [<host>] <port> [-noclient]") ; |
1093 | |
1094 | if( _args.argc() == 1 ){ |
1095 | // |
1096 | // we are a server and a client |
1097 | // |
1098 | port = Integer.parseInt( _args.argv(0) ); |
1099 | host = InetAddress.getByName("localhost") ; |
1100 | _server = new Server( port , _args ) ; |
1101 | _log.info("Server Setup Done") ; |
1102 | }else{ |
1103 | port = Integer.parseInt( _args.argv(1) ); |
1104 | host = InetAddress.getByName( _args.argv(0) ) ; |
1105 | } |
1106 | if( _args.getOpt("noclient") == null ){ |
1107 | _client = new Client( host , port , _args ) ; |
1108 | _log.info("Client started"); |
1109 | } |
1110 | }catch(Exception ee){ |
1111 | _log.warn(ee.toString(), ee) ; |
1112 | start() ; |
1113 | kill() ; |
1114 | throw ee; |
1115 | } |
1116 | start() ; |
1117 | } |
1118 | public void getInfo( PrintWriter pw ){ |
1119 | if( _client != null ){ |
1120 | pw.println( "Client\n--------") ; |
1121 | _client.getInfo( pw ) ; |
1122 | } |
1123 | if( _server != null ){ |
1124 | pw.println( "Server\n--------") ; |
1125 | _server.getInfo( pw ) ; |
1126 | } |
1127 | return ; |
1128 | } |
1129 | |
1130 | public void cleanUp() |
1131 | { |
1132 | if (_server != null) |
1133 | _server.shutdown(); |
1134 | if (_client != null) |
1135 | _client.shutdown(); |
1136 | } |
1137 | |
1138 | public String toString(){ |
1139 | StringBuffer sb = new StringBuffer() ; |
1140 | if( _client != null ) |
1141 | sb.append(_client.toString()). |
1142 | append(_server!=null?";":""); |
1143 | if( _server != null )sb.append(_server.toString()) ; |
1144 | return sb.toString(); |
1145 | } |
1146 | |
1147 | static class XXClient { |
1148 | XXClient( InetAddress address , int port , String message )throws Exception { |
1149 | byte [] data = message.getBytes() ; |
1150 | DatagramPacket packet = |
1151 | new DatagramPacket( data , data.length , address , port ) ; |
1152 | |
1153 | DatagramSocket socket = new DatagramSocket() ; |
1154 | |
1155 | socket.send( packet ) ; |
1156 | packet = new DatagramPacket( new byte[1024] , 1024 ) ; |
1157 | socket.receive( packet ) ; |
1158 | data = packet.getData() ; |
1159 | System.out.println(new String(data,0,data.length) ); |
1160 | } |
1161 | } |
1162 | public static void main(String [] args )throws Exception { |
1163 | if( args.length < 3 ) |
1164 | throw new |
1165 | IllegalArgumentException("Usage : ... <host> <port> <message>" ) ; |
1166 | InetAddress address = InetAddress.getByName( args[0] ) ; |
1167 | int port = Integer.parseInt( args[1] ) ; |
1168 | String message = args[2] ; |
1169 | |
1170 | new XXClient( address , port , message ) ; |
1171 | System.exit(0); |
1172 | } |
1173 | } |