001 package com.croftsoft.core.net; 002 003 import java.io.*; 004 import java.net.*; 005 import java.util.*; 006 007 // Need to drop thread priority 008 009 /********************************************************************* 010 * PortServer creates a java.net.ServerSocket which accepts connections 011 * and passes them on to com.orbs.net.SocketServer threads. 012 * 013 * @version 014 * $Id: PortServer.java,v 1.2 2008/09/20 04:12:46 croft Exp $ 015 * @since 016 * 1997-04-19 017 * @author 018 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 019 *********************************************************************/ 020 021 public final class PortServer implements Runnable { 022 ////////////////////////////////////////////////////////////////////// 023 ////////////////////////////////////////////////////////////////////// 024 025 private static final String COPYRIGHT 026 = "PortServer (C) Copyright 1997 David Wallace Croft"; 027 028 private static final int DEFAULT_PORT = 1234; 029 030 private static final String HELP 031 = "java com.orbs.net.PortServer <classname> <port> <filename>\n" 032 + "\n" 033 + "<classname> must designate a class that implements\n" 034 + "com.orbs.net.SocketServer.\n" 035 + "\n" 036 + "If <port> is not specified, the default value of\n" 037 + DEFAULT_PORT + " will be used.\n" 038 + "\n" 039 + "If <shutdown_semaphore_filename> is specified and the file\n" 040 + "does not exist, the program will not start. If the file is\n" 041 + "deleted, shutdown will occur immediately after the next\n" 042 + "connection.\n"; 043 044 private Class serverClass; 045 private int port; 046 private File semaphore; 047 048 private boolean shutdown = false; 049 private ServerSocket serverSocket; 050 private Thread thread; 051 private long nextUniqueID = 0; 052 053 private Vector thread_Vector = new Vector ( ); 054 private Vector socket_Vector = new Vector ( ); 055 private Vector server_Vector = new Vector ( ); 056 057 ////////////////////////////////////////////////////////////////////// 058 ////////////////////////////////////////////////////////////////////// 059 060 /********************************************************************* 061 *********************************************************************/ 062 public static final void main ( String [ ] args ) { 063 ////////////////////////////////////////////////////////////////////// 064 System.out.println ( COPYRIGHT ); 065 try { 066 Class serverClass = Class.forName ( args [ 0 ] ); 067 int port = DEFAULT_PORT; 068 if ( args.length > 1 ) port = Integer.parseInt ( args [ 1 ] ); 069 File semaphore = null; 070 if ( args.length > 2 ) semaphore = new File ( args [ 2 ] ); 071 new PortServer ( serverClass, port, semaphore ); 072 } catch ( Throwable t ) { 073 t.printStackTrace ( ); 074 System.out.println ( HELP ); 075 System.out.println ( t.getMessage ( ) ); 076 return; 077 } 078 } 079 080 public PortServer ( 081 Class serverClass, int port, File semaphore ) { 082 ////////////////////////////////////////////////////////////////////// 083 boolean found = false; 084 Class [ ] interfaces = serverClass.getInterfaces ( ); 085 for ( int i = 0; i < interfaces.length; i++ ) { 086 if ( interfaces [ i ].getName ( ).equals ( 087 "com.croftsoft.core.net.SocketServer" ) ) { 088 found = true; 089 break; 090 } 091 } 092 if ( !found ) { 093 throw new RuntimeException ( 094 "Class that implements com.orbs.net.SocketServer required." ); 095 } 096 if ( ( port < 0 ) || ( port > 65535 ) ) { 097 throw new RuntimeException ( 098 "Port number must be between 0 and 65535 inclusive." ); 099 } 100 if ( ( semaphore != null ) && !semaphore.exists ( ) ) { 101 throw new RuntimeException ( 102 "Semaphore file must be exist upon startup." ); 103 } 104 105 this.serverClass = serverClass; 106 this.port = port; 107 this.semaphore = semaphore; 108 109 ( thread = new Thread ( this ) ).start ( ); 110 } 111 112 public final void run ( ) { 113 ////////////////////////////////////////////////////////////////////// 114 try { 115 serverSocket = new ServerSocket ( port ); 116 while ( !shutdown ) { 117 if ( ( semaphore != null ) && !semaphore.exists ( ) ) { 118 throw new Exception ( "Semaphore file does not exist." ); 119 } 120 synchronized ( thread_Vector ) { 121 Enumeration e = thread_Vector.elements ( ); 122 while ( e.hasMoreElements ( ) ) { 123 Thread serverThread = ( Thread ) e.nextElement ( ); 124 if ( !serverThread.isAlive ( ) ) { 125 terminate ( serverThread ); 126 } 127 } 128 } 129 Socket socket = serverSocket.accept ( ); 130 SocketServer socketServer 131 = ( SocketServer ) serverClass.newInstance ( ); 132 socketServer.setPortServer ( this ); 133 socketServer.setSocket ( socket ); 134 socketServer.setUniqueID ( getNextUniqueID ( ) ); 135 Thread serverThread = new Thread ( socketServer ); 136 add ( socketServer, serverThread, socket ); 137 serverThread.start ( ); 138 } 139 } catch ( Throwable t ) { terminate ( t ); } 140 } 141 142 private synchronized final void add ( 143 SocketServer socketServer, Thread serverThread, Socket socket ) { 144 ////////////////////////////////////////////////////////////////////// 145 server_Vector.addElement ( socketServer ); 146 thread_Vector.addElement ( serverThread ); 147 socket_Vector.addElement ( socket ); 148 } 149 150 public synchronized final void terminate ( Throwable t ) { 151 ////////////////////////////////////////////////////////////////////// 152 if ( shutdown ) return; 153 shutdown = true; 154 if ( t != null ) t.printStackTrace ( ); 155 Enumeration e = thread_Vector.elements ( ); 156 while ( e.hasMoreElements ( ) ) { 157 terminate ( ( Thread ) e.nextElement ( ) ); 158 } 159 try { serverSocket.close ( ); } catch ( Throwable t1 ) { } 160 try { thread.stop ( ); } catch ( Throwable t1 ) { } 161 } 162 163 public synchronized final void terminate ( 164 SocketServer socketServer ) { 165 ////////////////////////////////////////////////////////////////////// 166 int i = server_Vector.indexOf ( socketServer ); 167 terminate ( i ); 168 } 169 170 private synchronized final void terminate ( Thread thread ) { 171 ////////////////////////////////////////////////////////////////////// 172 int i = thread_Vector.indexOf ( thread ); 173 terminate ( i ); 174 } 175 176 private synchronized final void terminate ( int i ) { 177 ////////////////////////////////////////////////////////////////////// 178 if ( i < 0 ) return; 179 try { ( ( Socket ) socket_Vector.elementAt ( i ) ).close ( ); } 180 catch ( Throwable t1 ) { } 181 try { ( ( Thread ) thread_Vector.elementAt ( i ) ).stop ( ); } 182 catch ( Throwable t2 ) { } 183 try { 184 server_Vector.removeElementAt ( i ); 185 socket_Vector.removeElementAt ( i ); 186 thread_Vector.removeElementAt ( i ); 187 } catch ( Throwable t ) { 188 t.printStackTrace ( ); 189 } 190 } 191 192 public final Vector clone_server_Vector ( ) { 193 ////////////////////////////////////////////////////////////////////// 194 return ( Vector ) server_Vector.clone ( ); 195 } 196 197 private final synchronized long getNextUniqueID ( ) { 198 ////////////////////////////////////////////////////////////////////// 199 return nextUniqueID++; 200 } 201 202 ////////////////////////////////////////////////////////////////////// 203 ////////////////////////////////////////////////////////////////////// 204 }