1 //
2 package server;
3 import java.net.*;
4 import java.io.*;
5 import java.util.*;
6 import java.applet.*;
7 import java.text.*;
8 import dx.protocol.server.*;
9 
10 public class DXServer extends Object
11 {
12 
13     private static ServerSocket serverSocket = null;
14     private static int java_id = 1;
15     public static Vector actions;
16     private static Vector users;
17     private static Date started_at;
18     private static CleanUpDaemon Cud;
19     private static boolean debug = false;
20     private static String output_dir = null;
21     private static String output_url = null;
22     private static int max_sessions = 1;
23     private static String max_session_str = null;
24 
25     //
26     // How long in seconds should we let a copy of dxexec hang around
27     // with no users before killing it.  We never flush cache or flush
28     // dictionary because we assume that every copy of dxexec has
29     // important state internally that we would rather not lose.
30     //
31     private final static int DXIdleTime = 600;
32 
33     private static Hashtable CachedConns = null;
34 
35     //
36     // control (re)reading of the hosts file
37     //
38     private static String HostFileUsed = null;
39     private static long HostFileModified = 0;
40     private static Vector HostNames = null;
41     private static Enumeration HostEnum;
42 
DXLSend( long dxl, String value )43     public static native int DXLSend( long dxl, String value );
DXLStartDX( String cmdstr, String host )44     private static native long DXLStartDX( String cmdstr, String host );
DXLExitDX( long dxl )45     private static native int DXLExitDX( long dxl );
46 
getStartDate()47     public static String getStartDate()
48     {
49         return DateFormat.getDateInstance().format(started_at);
50     }
51 
getServedCount()52     public static int getServedCount()
53     {
54         return java_id -1;
55     }
56 
57     private static int maxThreads;
getMaxThreads()58     public static int getMaxThreads()
59     {
60         return DXServer.maxThreads;
61     }
62 
63     private final static int Port = 4655;
64 
65     final static int MajorVersion = 2;
66     final static int MinorVersion = 0;
67     final static int MicroVersion = 0;
68 
69     //
70     // Minor version bumped:
71     // 3: dx.protocol package, frame threads
72     // 4: changed hardcoded strings to class names
73     //
74 
75     public final static String VersionString =
76         "" + MajorVersion + "." + MinorVersion + "." + MicroVersion;
77 
78 
79     public final static int STARTDX = 1;
80     public final static int STATUS = 4;
81     public final static int SHUTDOWN = 5;
82 
getOutputDir()83     public static String getOutputDir()
84     {
85         return output_dir;
86     }
87 
getOutputUrl()88     public static String getOutputUrl()
89     {
90         return output_url;
91     }
92 
93 
main( String[] args )94     public static void main( String[] args )
95     {
96 
97         try {
98             serverSocket = new ServerSocket( DXServer.Port );
99         }
100 
101         catch ( IOException e ) {
102             System.out.println( "Could not listen on port: " + DXServer.Port + ", " + e );
103             System.exit( 1 );
104         }
105 
106         String dbgmsgs = System.getProperty( "DXServer.debug" );
107 
108         if ( dbgmsgs != null ) debug = true;
109         else debug = false;
110 
111         users = new Vector( 50 );
112 
113         DXServerThread.ClassInitialize();
114 
115         DXServer.HostFileUsed = null;
116 
117         DXServer.HostFileModified = 0;
118 
119         DXServer.HostNames = new Vector( 20 );
120 
121         DXServer.HostEnum = null;
122 
123         DXServer.ReadHostFile();
124 
125         DXServer.CachedConns = new Hashtable();
126 
127         DXServer.Cud = new CleanUpDaemon();
128 
129         DXServer.Cud.start();
130 
131         DXServer.maxThreads = 1;
132 
133         String mxstr = System.getProperty ( "DXServer.dxsessions" );
134 
135         if ( mxstr != null ) {
136             try {
137                 DXServer.maxThreads = ( new Integer( mxstr ) ).intValue();
138             }
139 
140             catch ( Exception e ) {}
141 
142         }
143 
144         output_dir = System.getProperty( "DXServer.outDir" );
145 
146         if ( output_dir == null ) output_dir = "./";
147 
148         output_url = System.getProperty( "DXServer.outUrl" );
149 
150         if ( output_url == null ) output_url = "./";
151 
152         if ( ( output_dir == null ) || ( output_url == null ) ) {
153             System.out.println ( "DXServer requires output file name and url." );
154             System.exit( 1 );
155         }
156 
157         actions = new Vector( 10 );
158 
159         try {
160             actions.addElement ( ( Object )
161                                  new ServerCommand( startMsg.GetCommand(), DXServer.STARTDX ) );
162             actions.addElement ( ( Object )
163                                  new ServerCommand( statusMsg.GetCommand(), DXServer.STATUS ) );
164             actions.addElement ( ( Object )
165                                  new ServerCommand( shutdownMsg.GetCommand(), DXServer.SHUTDOWN ) );
166         }
167 
168         catch ( ClassNotFoundException cnfe ) {
169             cnfe.printStackTrace();
170             System.exit( 1 );
171         }
172 
173         System.out.println( "Starting DXServer... ready for clients" );
174         started_at = new Date();
175 
176         while ( true ) {
177             try {
178                 Socket clientSocket = serverSocket.accept();
179                 ConnectThread ct = new ConnectThread( clientSocket );
180                 ct.start();
181                 ct = null;
182             }
183 
184             catch ( IOException e ) {
185                 System.out.println( "Accept failed: " + DXServer.Port + ", " + e );
186                 break;
187             }
188 
189             catch ( Exception e ) {
190                 System.out.println( "Unknown error" );
191                 break;
192             }
193         }
194 
195         shutdown ( null, null );
196 
197     }
198 
versionMatch( String client_version )199     public static boolean versionMatch ( String client_version )
200     {
201         boolean retval = false;
202 
203         serverVersionMsg svm = new serverVersionMsg( client_version );
204 
205         //
206         // We require a server whose Major,Minor are at least what ours are
207         // If Micro is less than ours, we'll proceed.
208         //
209 
210         if ( ( svm.getMajor() >= DXServer.MajorVersion ) &&
211                 ( svm.getMinor() >= DXServer.MinorVersion ) )
212             retval = true;
213 
214         if ( debug ) {
215             System.out.println ( "DXServer: versionMatch(" + retval + ") " +
216                                  client_version );
217         }
218 
219         return retval;
220     }
221 
getUserCount()222     public synchronized static int getUserCount()
223     {
224         return users.size();
225     }
226 
startDX( dx.protocol.server.serverMsg msg, Socket csock )227     public synchronized static boolean startDX( dx.protocol.server.serverMsg msg, Socket csock )
228     {
229         if ( debug ) {
230             System.out.println ( "DXServer: " + msg.toString() );
231         }
232 
233         DXServerThread dxst = new DXServerThread( csock, java_id );
234         dxst.start();
235         users.addElement( ( Object ) dxst );
236         java_id++;
237         return true;
238     }
239 
status( dx.protocol.server.serverMsg msg, Socket csock )240     public static boolean status ( dx.protocol.server.serverMsg msg, Socket csock )
241     {
242         StatusThread st = new StatusThread( csock );
243         st.start();
244         return true;
245     }
246 
shutdown( dx.protocol.server.serverMsg msg, Socket csock )247     public static boolean shutdown ( dx.protocol.server.serverMsg msg, Socket csock )
248     {
249         if ( debug )
250             System.out.println ( "DXServer: " + msg.toString() );
251 
252         //
253         // DXServer should always go this way when exiting.  It cleans up files.
254         //
255         DXServer.Cud.interrupt();
256 
257         DXServer.CleanUp();
258 
259         Enumeration enum1 = users.elements();
260 
261         while ( enum1.hasMoreElements() ) {
262             DXServerThread dxst = ( DXServerThread ) enum1.nextElement();
263 
264             if ( dxst.isAlive() == true ) {
265                 if ( debug )
266                     System.out.println ( "     ***** DXServer: requesting thread shutdown" );
267 
268                 dxst.cleanUp();
269 
270                 dxst.interrupt();
271             }
272         }
273 
274         //
275         // don't return from this point.
276         //
277         System.exit( 0 );
278 
279         return true;
280     }
281 
282     //
283     // Check every thread for alive-ness
284     //
285 
CleanUp()286     public synchronized static void CleanUp()
287     {
288         Vector dead_users;
289         dead_users = new Vector( 10 );
290         Enumeration enum1 = users.elements();
291 
292         while ( enum1.hasMoreElements() ) {
293             DXServerThread old_dxst = ( DXServerThread ) enum1.nextElement();
294 
295             if ( old_dxst.isAlive() == false )
296                 dead_users.addElement( old_dxst );
297         }
298 
299         enum1 = dead_users.elements();
300 
301         while ( enum1.hasMoreElements() ) {
302             DXServerThread dead_user = ( DXServerThread ) enum1.nextElement();
303             users.removeElement( ( Object ) dead_user );
304         }
305 
306         synchronized ( DXServer.CachedConns ) {
307             Vector killed = new Vector( 4 );
308             enum1 = DXServer.CachedConns.elements();
309 
310             while ( enum1.hasMoreElements() ) {
311                 ConnectionEntry existing = ( ConnectionEntry ) enum1.nextElement();
312 
313                 if ( existing.getUserCount() == 0 ) {
314                     if ( existing.getIdleTime() > DXServer.DXIdleTime ) {
315                         Long dxlcon = existing.getDXLConnection();
316                         DXServer.DXLExitDX ( dxlcon.longValue() );
317                         killed.addElement( dxlcon );
318 
319                         if ( debug )
320                             System.out.println ( "DXServer: terminate Data Explorer session" );
321                     }
322                 }
323             }
324 
325             enum1 = killed.elements();
326 
327             while ( enum1.hasMoreElements() ) {
328                 Long dxlcon = ( Long ) enum1.nextElement();
329                 ConnectionEntry ce = ( ConnectionEntry ) DXServer.CachedConns.get( dxlcon );
330                 ce.deleteFiles();
331                 DXServer.CachedConns.remove( dxlcon );
332             }
333 
334             killed.removeAllElements();
335         }
336     }
337 
338 
GetThread( int java_id )339     public synchronized static DXServerThread GetThread( int java_id )
340     {
341         DXServerThread dxst = null;
342         Enumeration enum1 = users.elements();
343 
344         while ( enum1.hasMoreElements() ) {
345             dxst = ( DXServerThread ) enum1.nextElement();
346 
347             if ( dxst.isAlive() ) {
348                 int id = dxst.getIdDX();
349 
350                 if ( id == java_id )
351                     break;
352             }
353         }
354 
355         return dxst;
356     }
357 
EndConnection( Long dxl, DXServerThread dxst )358     public static void EndConnection( Long dxl, DXServerThread dxst )
359     {
360         synchronized ( DXServer.CachedConns ) {
361             ConnectionEntry ce = ( ConnectionEntry ) DXServer.CachedConns.get( dxl );
362             ce.detachUser( dxst );
363         }
364     }
365 
createNet( String path, DXServerThread dxst )366     public synchronized static String createNet( String path, DXServerThread dxst )
367     {
368         ConnectionEntry ce = ( ConnectionEntry ) CachedConns.get( dxst.getDXLConnection() );
369         return ce.getNetName( dxst );
370     }
371 
LockConnection( DXServerThread dxst )372     public static void LockConnection( DXServerThread dxst )
373     {
374         ConnectionEntry ce = ( ConnectionEntry ) CachedConns.get( dxst.getDXLConnection() );
375         ce.getConnectionLock();
376     }
377 
UnlockConnection( DXServerThread dxst )378     public static void UnlockConnection( DXServerThread dxst )
379     {
380         ConnectionEntry ce = ( ConnectionEntry ) CachedConns.get( dxst.getDXLConnection() );
381         ce.releaseConnectionLock();
382     }
383 
NewConnection( DXServerThread dxst, String path )384     public static Long NewConnection( DXServerThread dxst, String path )
385     {
386         ConnectionEntry ce = null;
387 
388         synchronized ( DXServer.CachedConns ) {
389             if ( DXServer.CachedConns.size() > 0 ) {
390                 ConnectionEntry minEntry = null;
391                 Enumeration enum1 = CachedConns.elements();
392 
393                 while ( enum1.hasMoreElements() ) {
394                     ConnectionEntry existing = ( ConnectionEntry ) enum1.nextElement();
395 
396                     if ( existing.isFailed() ) {}
397                     else if ( minEntry == null ) {
398                         minEntry = existing;
399                     }
400 
401                     else if ( existing.getUserCount() < minEntry.getUserCount() ) {
402                         minEntry = existing;
403                     }
404 
405                     else if ( existing.getUserCount() == minEntry.getUserCount() ) {
406                         if ( existing.getUserTime() < minEntry.getUserTime() ) {
407                             minEntry = existing;
408                         }
409                     }
410 
411                     if ( ( minEntry != null ) && ( minEntry.getUserCount() == 0 ) )
412                         break;
413                 }
414 
415                 ce = minEntry;
416             }
417 
418             boolean more_capacity = false;
419 
420             if ( DXServer.GetMaxSessions() > DXServer.CachedConns.size() )
421                 more_capacity = true;
422 
423             if ( ( ce != null ) && ( ce.getUserCount() >= 1 ) && ( more_capacity ) )
424                 ce = null;
425 
426             if ( ce == null ) {
427                 String host = DXServer.GetNextHost();
428                 long dxlcon = 0;
429                 try {
430                     dxlcon =
431                     DXServer.DXLStartDX( "dx -optimize memory -execonly -processors 1 -highlight off", host );
432                 } catch (Exception e) {
433                 	System.out.println ( "Problem starting one of your hosts." );
434                 	System.out.println ("Startup was: dx -optimize memory -execonly -processors 1 -highlight off :" + host);
435             		System.exit( 1 );
436             	}
437             	if (dxlcon == 0) {
438             		System.out.println ( "Problem starting one of your hosts." );
439                 	System.out.println ("Startup was: dx -optimize memory -execonly -processors 1 -highlight off :" + host);
440             		System.exit( 1 );
441             	}
442 
443                 Long C = new Long( dxlcon );
444                 ce = new ConnectionEntry( C );
445                 CachedConns.put( C, ce );
446             }
447 
448             if ( ce == null ) return null;
449 
450             ce.attachUser( dxst, path );
451         }
452 
453         return ce.getDXLConnection();
454     }
455 
GetMaxSessions()456     public static int GetMaxSessions()
457     {
458         if ( DXServer.max_session_str == null ) {
459             DXServer.max_session_str = System.getProperty( "DXServer.max_sessions" );
460 
461             if ( DXServer.max_session_str == null ) DXServer.max_session_str = "1";
462 
463             try {
464                 Integer I = new Integer( DXServer.max_session_str );
465                 DXServer.max_sessions = I.intValue();
466             }
467 
468             catch ( NumberFormatException nfe ) {
469                 DXServer.max_session_str = "1";
470                 DXServer.max_sessions = 1;
471             }
472         }
473 
474         return DXServer.max_sessions;
475     }
476 
477     //
478     // Read the contents of dxserver.hosts
479     // Look in:
480     // 1) /etc
481     // 2) current working dir
482     // 3) environment variable DXServer.hostsFile
483     // Don't look for multiple copies of the file.  Stop after reading the first one found.
484     // N.B. The caller is responsible for locking before both of these class methods.
485     //
GetNextHost()486     private static String GetNextHost()
487     {
488         if ( DXServer.HostEnum.hasMoreElements() == false )
489             DXServer.HostEnum = HostNames.elements();
490 
491         return ( String ) DXServer.HostEnum.nextElement();
492     }
493 
ReadHostFile()494     private static void ReadHostFile()
495     {
496         boolean file_found = false;
497         boolean file_read = false;
498         Vector paths;
499 
500         paths = new Vector( 5 );
501 
502         if ( DXServer.HostFileUsed != null )
503             paths.addElement( ( Object ) DXServer.HostFileUsed );
504 
505         paths.addElement( ( Object ) File.separator + "etc" + File.separator + "dxserver.hosts" );
506 
507         paths.addElement( ( Object ) "." + File.separator + "dxserver.hosts" );
508 
509         paths.addElement( ( Object ) System.getProperty( "DXServer.hostsFile" ) );
510 
511         synchronized ( DXServer.HostNames ) {
512             try {
513 
514                 Enumeration enum1 = paths.elements();
515 
516                 while ( ( !file_read ) && ( enum1.hasMoreElements() ) ) {
517                     String path = ( String ) enum1.nextElement();
518                     File hf = new File( path );
519 
520                     if ( hf.exists() == false ) continue;
521 
522                     if ( hf.canRead() == false ) continue;
523 
524                     if ( hf.isFile() == false ) continue;
525 
526                     file_found = true;
527 
528                     long modified = hf.lastModified();
529 
530                     //
531                     // If we've already read an up-to-date hosts file, then
532                     // do nothing.
533                     //
534                     if ( ( DXServer.HostFileUsed != null ) &&
535                             ( DXServer.HostFileUsed.equals( path ) ) &&
536                             ( DXServer.HostFileModified >= modified ) )
537                         break;
538 
539                     DXServer.HostNames.removeAllElements();
540 
541                     FileReader hfr = new FileReader( hf );
542 
543                     BufferedReader hbr = new BufferedReader ( hfr );
544 
545                     String host;
546 
547                     while ( ( host = hbr.readLine() ) != null ) {
548                     	host = host.trim();
549 
550                         if ( host.startsWith( "//" ) ) continue;
551 
552                         if ( host.startsWith( "!#" ) ) continue;
553 
554                         if ( host.startsWith( "#" ) ) continue;
555 
556                         if ( host.length() == 0) continue;
557 
558                         HostNames.addElement( ( Object ) host );
559                     }
560 
561                     DXServer.HostFileUsed = hf.getPath();
562                     DXServer.HostFileModified = modified;
563                     file_read = true;
564                 }
565             }
566 
567             catch ( Exception e ) {
568                 e.printStackTrace();
569             }
570 
571             if ( !file_found ) {
572                 DXServer.HostFileUsed = null;
573                 DXServer.HostNames.removeAllElements();
574             }
575 
576             if ( DXServer.HostNames.size() == 0 )
577                 DXServer.HostNames.addElement( ( Object ) "localhost" );
578 
579             if ( ( !file_found ) || ( file_read ) )
580                 DXServer.HostEnum = DXServer.HostNames.elements();
581         }
582     }
583 } // end DXServer
584 
585 
586 
587