class TcpTask extends AbstractQoSTask {

	public QoSTestResult call() throws Exception {
		final QoSTestResult result = initQoSTestResult(QosMeasurementType.TCP);
		try {
			onStart(result);
			
			if (this.testPortIn != null) {
				result.getResultMap().put(RESULT_IN, "FAILED");			
			}
			if (this.testPortOut != null) {
				result.getResultMap().put(RESULT_OUT, "FAILED");			
			}
			
			Socket socketIn = null;
			
			try {
				System.out.println("TCPTASK: " + getTestServerAddr() + ":" + getTestServerPort());
		    	
		    	String response = null;
		    	
		    	if (this.testPortOut != null) {
		    		//needed for timeout:
		    		final CountDownLatch latch = new CountDownLatch(1);
		    		
		    		//response handler
		    		final ControlConnectionResponseCallback callback = new ControlConnectionResponseCallback() {
						
						public void onResponse(final String response, final String request) {
				    		if (response != null && response.startsWith("OK")) {
				    			System.out.println("got response: " + response);
				    			Socket socketOut = null;
				    			
				    			try {
					    			socketOut = getSocket(getTestServerAddr(), testPortOut, false, (int)(timeout/1000000));
					    			socketOut.setSoTimeout((int)(timeout/1000000));
					    			sendMessage(socketOut, "PING\n");
					    			final String testResponse = readLine(socketOut);
								
					    			System.out.println("TCP OUT TEST response: " + testResponse);
								
					    			result.getResultMap().put(RESULT_RESPONSE_OUT, testResponse);
					    			socketOut.close();
					    			result.getResultMap().put(RESULT_OUT, "OK");
				    			}
				    			catch (SocketTimeoutException e) {
				    				result.getResultMap().put(RESULT_OUT, "TIMEOUT");
				    			}
				    			catch (Exception e) {
				    				result.getResultMap().put(RESULT_OUT, "ERROR");
				    			}
				    			finally {
					    			latch.countDown();
				    			}
				    		} else {
				    			// we don't need to await the timeout on wrong response (and it shouldn't be a timeout)
								result.getResultMap().put(RESULT_OUT, "ERROR");
								latch.countDown();
							}
						}
					};	    				
		    		
					sendCommand("TCPTEST OUT " + testPortOut, callback);
					if(!latch.await(timeout, TimeUnit.NANOSECONDS)) {
						result.getResultMap().put(RESULT_OUT, "TIMEOUT");
					}
		    	}
				
		    	if (this.testPortIn != null) {
		    		try (ServerSocket serverSocket = new ServerSocket(testPortIn)) {
						sendCommand("TCPTEST IN " + testPortIn, null);

						serverSocket.setSoTimeout((int)(timeout/1000000));
						socketIn = serverSocket.accept();
						socketIn.setSoTimeout((int)(timeout/1000000));
						response = readLine(socketIn);
						System.out.println("TCP IN TEST response: " + response);						
						result.getResultMap().put(RESULT_RESPONSE_IN, response);
						socketIn.close();
						result.getResultMap().put(RESULT_IN, "OK");	    				    			
		    		}
					catch (SocketTimeoutException e) {
						result.getResultMap().put(RESULT_IN, "TIMEOUT");
					}
					catch (Exception e) {
						result.getResultMap().put(RESULT_IN, "ERROR");
					}
		    	}
				
			}
			catch (Exception e) {
				e.printStackTrace();
			}
			
			if (this.testPortIn != null) {
				result.getResultMap().put(RESULT_PORT_IN, testPortIn);			
			}

			if (this.testPortOut != null) {
				result.getResultMap().put(RESULT_PORT_OUT, testPortOut);	
			}
			
			result.getResultMap().put(RESULT_TIMEOUT, timeout);
			
			return result;			
		}
		catch (Exception e)  {
			throw e;
		}
		finally {
			onEnd(result);
		}
	}

	public  TcpTask(QualityOfServiceTest nnTest, TaskDesc taskDesc, int threadId);

}