/******************************************************************************* * Copyright 2016 Specure GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ package at.alladin.rmbt.qos.testserver.tcp; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.text.DateFormat; import java.util.Date; import at.alladin.rmbt.qos.testserver.ServerPreferences.TestServerServiceEnum; import at.alladin.rmbt.qos.testserver.TestServer; import at.alladin.rmbt.qos.testserver.servers.AbstractTcpServer; import at.alladin.rmbt.qos.testserver.util.TestServerConsole; /** * * @author lb * */ public class TcpMultiClientServer extends AbstractTcpServer { /** * the ttl of this socket */ public final static long TTL = 30000; /** * needed verbose level of resgister/remove candidate debug output */ public final static int VERBOSE_LEVEL_REGISTER_REMOVE_CANDIDATE = 0; /** * needed verbose level of request/response debug output */ public final static int VERBOSE_LEVEL_REQUEST_RESPONSE = 0; /** * if set to true the socket will be closed and unbound every time a test has finished and there are no active connections */ public final static boolean CLOSE_CONNECTION_IF_NO_CLIENTS_LEFT = true; /** * closes the connection if the TTL has been reached */ public final static boolean CLOSE_CONNECTION_IF_TTL_REACHED = true; /** * socket SO timeout */ public final static int TIMEOUT = 20000; /** * set a socket timeout? */ public final static boolean HAS_TIMEOUT = false; /** * start up timestamp */ private final long startUp = System.currentTimeMillis(); /** * * @param port * @throws IOException */ public TcpMultiClientServer(int port, InetAddress addr) throws IOException { super(addr, port); } /* * prepares this server for listening (=starts thread), or increases the current connection count by 1 * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.servers.AbstractServer#prepare() */ @Override @SuppressWarnings("unused") public synchronized void prepare() throws Exception { TestServerConsole.log("Preparing TCP socket on port " + port + " for TCP/NTP test.", 2, TestServerServiceEnum.TCP_SERVICE); if (TestServer.serverPreferences.isIpCheck()) { if (CLOSE_CONNECTION_IF_NO_CLIENTS_LEFT) { currentConnections.addAndGet(1); TestServerConsole.log("Socket on port " + port + " still opened. Candidate count has been increased by 1 (current count: " + currentConnections.get() + ").", 2, TestServerServiceEnum.TCP_SERVICE); } } //check if this thread is alive boolean isThreadRunning = isAlive(); //refresh the TTL refreshTtl(TTL); if (serverSocket == null) { serverSocket = TestServer.createServerSocket(getPort(), false, getInetAddr()); TestServerConsole.log(getName() + " has been (re)opened.", 2, TestServerServiceEnum.TCP_SERVICE); } if (serverSocket != null && HAS_TIMEOUT) { serverSocket.setSoTimeout(TIMEOUT); } //start thread if not running if (!isThreadRunning) { TestServer.getCommonThreadPool().submit(this); } } /*decreases the number of active connections and closes the socket if necessary * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.servers.AbstractServer#close() */ @Override public synchronized boolean close() throws IOException { if (TestServer.serverPreferences.isIpCheck()) { if (CLOSE_CONNECTION_IF_NO_CLIENTS_LEFT) { final long connectionsLeft = currentConnections.addAndGet(-1); if (this.serverSocket != null && !this.serverSocket.isClosed() && connectionsLeft <= 0) { closeSocket(); TestServerConsole.log("Closed socket on port " + port + "; Reason: empty candidate list.", 2, TestServerServiceEnum.TCP_SERVICE); return true; } } } else { if (CLOSE_CONNECTION_IF_TTL_REACHED) { if (this.serverSocket != null && !this.serverSocket.isClosed() && System.currentTimeMillis() >= ttlTimestamp.get()) { closeSocket(); TestServerConsole.log("Closed socket on port " + port + "; Reason: TTL of " + TTL + "ms reached.", 2, TestServerServiceEnum.TCP_SERVICE); return true; } } } return false; } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.servers.AbstractServer#isAlive() */ @Override public synchronized boolean isAlive() { if (TestServer.serverPreferences.isIpCheck()) { if (CLOSE_CONNECTION_IF_NO_CLIENTS_LEFT) { final long connectionsLeft = currentConnections.get(); return (this.serverSocket != null && !this.serverSocket.isClosed() && connectionsLeft > 0); } } else { if (CLOSE_CONNECTION_IF_TTL_REACHED) { return (this.serverSocket != null && !this.serverSocket.isClosed() && System.currentTimeMillis() < ttlTimestamp.get()); } } return false; } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.servers.AbstractServer#execute() */ @Override protected void execute() throws Exception { Socket clientSocket = serverSocket.accept(); TcpClientHandler tcpClientHandler = new TcpClientHandler(clientSocket, this); TestServer.getCommonThreadPool().execute(tcpClientHandler); } @Override public String toString() { return "TcpMultiClientServer [candidateMap=" + candidateMap + ", currentConnections=" + currentConnections + ", serverSocketTypeClazz=" + serverSocketTypeClazz + ", clientHandlerRunnableClazz=" + clientDataHolderClazz + ", ttlTimestamp=" + ttlTimestamp + ", serverSocket=" + serverSocket + ", port=" + port + ", inetAddr=" + inetAddr + "]"; } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.entity.Observable#isHealthy() */ @Override public boolean isHealthy() { return serverSocket != null && serverSocket.isBound(); } /* * (non-Javadoc) * @see at.alladin.rmbt.qos.testserver.entity.Observable#getStatusMessage() */ @Override public String getStatusMessage() { return "Server start up: " + DateFormat.getDateTimeInstance().format(new Date(startUp)); } }