Source code for /engineering/autohit-2003/src/autohit/server/service/SocketRelayService.javaOriginal file SocketRelayService.java
   1 /**
   2  * AUTOHIT 2003
   3  * Copyright Erich P Gatejen (c) 1989,1997,2003,2004
   4  * 
   5  * This program is free software; you can redistribute it and/or modify 
   6  * it under the terms of the GNU General Public License as published by 
   7  * the Free Software Foundation; either version 2 of the License, or (at
   8  * your option) any later version.
   9  * This program is distributed in the hope that it will be useful, but
  10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  12  * more details.
  13  * 
  14  * You should have received a copy of the GNU General Public License along
  15  * with this program; if not, write to the Free Software Foundation, Inc.,
  16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17  *
  18  * Additional license information can be found in the documentation.
  19  * @author Erich P Gatejen
  20  */
  21 package autohit.server.service;
  22 
  23 import java.net.ServerSocket;
  24 import java.net.Socket;
  25 import java.net.SocketTimeoutException;
  26 import java.util.HashSet;
  27 import java.util.Iterator;
  28 
  29 import autohit.common.AutohitErrorCodes;
  30 import autohit.common.AutohitProperties;
  31 import autohit.common.Utils;
  32 
  33 /**
  34  * This is a socket relay service. It's a dumb relay for sockets. Don't ask why
  35  * I did this. It will accept connections on port
  36  * AutohitProperties.value_SOCKETRELAY_SERVER_PORT. It'll relay them to the
  37  * current property settings for
  38  * AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_ADDR and
  39  * AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_PORT for address and port,
  40  * respectively. If either is not set, a default will be used, though there is
  41  * little utility in the default.
  42  * <p>
  43  * <p>
  44  * The relay will stay active until either side drops the connection. There is
  45  * absolutely no filtering or logging.
  46  * 
  47  * @author Erich P. Gatejen
  48  * @version 1.0 <i>Version History</i><code>EPG - Initial - 12SEP03</code>
  49  */
  50 public class SocketRelayService extends Service {
  51 
  52 	final private static int ACCEPT_TIMEOUT = 1000;
  53 	final private static int CLEANUP_THRESHOLD = 200;
  54 
  55 	/**
  56 	 *  accept port */
  57 	ServerSocket listen;
  58 
  59 	/**
  60 	 *  active ports */
  61 	HashSet active;
  62 
  63 	/**
  64 	 *  Default constructor */
  65 	public SocketRelayService() {
  66 		super();
  67 	}
  68 
  69 	/**
  70 	 * Complete construction. This will be called when the VM is initialized. */
  71 	public void construct() throws ServiceException {
  72 
  73 		try {
  74 			
  75 			// How are we confiugred
  76 			int port = AutohitProperties.default_SOCKETRELAY_SERVER_PORT;
  77 			String portString =
  78 				(String) Utils.testGetProperty(
  79 					AutohitProperties.SERVICE_SOCKETRELAY_SERVER_PORT,
  80 					sc.getPropertiesSet());
  81 			if (portString != null) {
  82 				port = Integer.parseInt(portString);
  83 			} 
  84 			
  85 			// Set up communication
  86 			listen = new ServerSocket(port);
  87 			active = new HashSet();
  88 
  89 		} catch (NumberFormatException nee) {
  90 			throw new ServiceException(
  91 				"Failed constructing HttpCommandService.  Bad value for property " +
  92 				AutohitProperties.SERVICE_SOCKETRELAY_SERVER_PORT + ". message=" + nee.getMessage(),
  93 				ServiceException.CODE_SERVICE_STARTUP_FAULT);
  94 			
  95 		} catch (Exception ee) {
  96 			throw new ServiceException(
  97 				"Failed constructing SocketRelayService.  message=" + ee.getMessage(),
  98 				ServiceException.CODE_SERVICE_STARTUP_FAULT);
  99 		}
 100 
 101 	}
 102 
 103 	/**
 104 	 * Fast loop. We spend most of our time waiting for connections. Cycle back
 105 	 * to VM only after an accept or a timeout.
 106 	 * 
 107 	 * @see autohit.vm.VMException
 108 	 */
 109 	public void execute() throws ServiceException {
 110 
 111 		Socket accepted;
 112 		int dport;
 113 		String daddress;
 114 		boolean wirelogging;
 115 
 116 		// Try to accept
 117 		try {
 118 
 119 			// Do we need to clean the active set?
 120 			if (active.size() > CLEANUP_THRESHOLD) {
 121 				this.cleanActive();
 122 			}
 123 
 124 			// ACCEPT
 125 			listen.setSoTimeout(ACCEPT_TIMEOUT);
 126 			accepted = listen.accept();
 127 			myLog.debug("SocketRelayService:Accepted a connection.", AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 128 
 129 			// BUILD HELPER
 130 			daddress =
 131 				(String) Utils.testGetProperty(
 132 					AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_PORT,
 133 					sc.getPropertiesSet());
 134 			if (daddress == null) {
 135 				dport = AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_PORT_default;
 136 			} else {
 137 				dport = Integer.parseInt(daddress);
 138 			}
 139 			daddress =
 140 				(String) Utils.testGetProperty(
 141 					AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_ADDR,
 142 					sc.getPropertiesSet());
 143 			if (daddress == null)
 144 				daddress = AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_ADDR_default;
 145 
 146 			// Do we want to capture wire logging?
 147 			wirelogging =
 148 				Utils.testGetPropertyTruth(AutohitProperties.SERVICE_SOCKETRELAY_WIRELOGGING, sc.getPropertiesSet());
 149 
 150 			// Build helper
 151 			SocketRelayHelper srh = new SocketRelayHelper();
 152 			srh.init(accepted, daddress, dport, myLog, wirelogging);
 153 			myLog.debug(
 154 				"SocketRelayService:Relay helper initialized.  destination=" + daddress + ":" + dport,
 155 				AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 156 
 157 			// dispatch
 158 			srh.start();
 159 			active.add(srh);
 160 			myLog.debug("SocketRelayService:Relay helper dispatched.", AutohitErrorCodes.CODE_DEBUGGING_SERVICES);
 161 
 162 		} catch (NumberFormatException ste) {
 163 			throw new ServiceException(
 164 				"Fault in SocketRelayService.  "
 165 					+ AutohitProperties.SERVICE_SOCKETRELAY_DESTINATION_PORT
 166 					+ " is not a parsable integer.",
 167 				ServiceException.CODE_SERVICE_GENERAL_FAULT);
 168 
 169 		} catch (SocketTimeoutException ste) {
 170 			// This is ok. Ignore and move on
 171 
 172 		} catch (Exception ee) {
 173 			throw new ServiceException(
 174 				"Fault in SocketRelayService.  message=" + ee.getMessage(),
 175 				ServiceException.CODE_SERVICE_GENERAL_FAULT);
 176 		}
 177 	}
 178 
 179 	/**
 180 	 * Helper */
 181 	private void cleanActive() throws Exception {
 182 
 183 		Iterator i = active.iterator();
 184 
 185 		while (i.hasNext()) {
 186 			SocketRelayHelper srh = (SocketRelayHelper) i.next();
 187 			if (!srh.isAlive())
 188 				active.remove(srh);
 189 		}
 190 	}
 191 
 192 	/**
 193 	 * Complete destroy. This will be called when the VM is finalizing. */
 194 	public void destruct() throws ServiceException {
 195 
 196 		Iterator i = active.iterator();
 197 
 198 		while (i.hasNext()) {
 199 			SocketRelayHelper srh = (SocketRelayHelper) i.next();
 200 			active.remove(srh);
 201 			if (srh.isAlive()) {
 202 				try {
 203 					srh.interrupt();
 204 				} catch (Exception eee) { // dont care
 205 				}
 206 			}
 207 		} // end while
 208 
 209 	} // end destruct
 210 
 211 }