/*
/ Copyright (C) 2009 Risto Känsäkoski - Sesca ISW Ltd
/
/ This file is part of SIP-Applet (www.sesca.com, www.purplescout.com)
/ This file is modified from MjSip (http://www.mjsip.org)
/
/ This program is free software; you can redistribute it and/or
/ modify it under the terms of the GNU General Public License
/ as published by the Free Software Foundation; either version 2
/ of the License, or (at your option) any later version.
/
/ This program is distributed in the hope that it will be useful,
/ but WITHOUT ANY WARRANTY; without even the implied warranty of
/ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
/ GNU General Public License for more details.
/
/ You should have received a copy of the GNU General Public License
/ along with this program; if not, write to the Free Software
/ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package com.sesca.voip.transport;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.SocketException;
import java.nio.ByteBuffer;
import org.zoolu.net.IpAddress;
import com.sesca.misc.Logger;
public class HttpTunnelConnection extends Thread
{
private boolean initialized = false;
/** The reading buffer size */
protected static final int BUFFER_SIZE = 65535;
/**
* Default value for the maximum time that the tcp connection can remain
* active after been halted (in milliseconds)
*/
public static final int DEFAULT_SOCKET_TIMEOUT = 2000; // 2sec
/** The TCP socket */
protected HttpTunnelSocket socket;
/**
* Maximum time that the connection can remain active after been halted (in
* milliseconds)
*/
protected int socket_timeout;
/**
* Maximum time that the connection remains active without receiving data (in
* milliseconds)
*/
protected long alive_time;
/** The InputStream */
// protected InputStream istream;
/** The OutputStream */
// protected OutputStream ostream;
/** InputStream/OutputStream error */
protected Exception error;
/** Whether it has been halted */
protected boolean stop;
/** Whether it is running */
protected boolean is_running;
protected ByteBuffer outputBuffer;
protected ByteBuffer inputBuffer;
/** TcpConnection listener */
protected HttpTunnelConnectionListener listener;
public HttpTunnelConnection(HttpTunnelSocket socket, HttpTunnelConnectionListener listener)
{
this.setPriority(8);
Logger.info("HttpConnection2 constructed");
init(socket, 0, listener);
start();
}
public HttpTunnelConnection(HttpTunnelSocket socket, long alive_time, HttpTunnelConnectionListener listener)
{
this.setPriority(8);
Logger.info("HttpConnection1 constructed");
init(socket, alive_time, listener);
start();
}
/** Runs the http tunnel receiver */
public void run()
{
// Logger.debug("HttpTunnelConnection.run()");
// try {
// sleep(20);
// } catch (InterruptedException e1) {
// TODO Auto-generated catch block
// e1.printStackTrace();
// }
// byte[] buff=new byte[BUFFER_SIZE];
// ByteBuffer buff=ByteBuffer.allocate(BUFFER_SIZE);
this.setPriority(8);
//System.out.println("HttpTunnelConnection has priority:"+this.getPriority());
//System.out.println("max priority is"+Thread.MAX_PRIORITY);
long expire = 0;
if(alive_time > 0)
expire = System.currentTimeMillis() + alive_time;
try
{
if(error != null)
throw error;
// socket.setSoTimeout(socket_timeout);
// loop
while (!this.stop)
{
int len = 0;
if(true)
{
try
{
inputBuffer.clear();
len = socket.channel.read(inputBuffer);
}
catch (InterruptedIOException ie)
{
if(alive_time > 0 && System.currentTimeMillis() > expire)
{
Logger.warning("Connection closed due to timeout.");
halt();
}
continue;
}
catch (SocketException se)
{
Logger.error("Socketti on kiinni");
halt();
}
}
if(len < 0)
{ // error=new Exception("TCP connection closed");
//Logger.warning("No incoming traffic. HTTP tunnel connection closed.");
Logger.warning("No incoming traffic. HttpTunnelConnection falls into sleep.");
//this.stop = true;
Thread.sleep(100);
}
else if(len > 0)
{
// Logger.debug("HttpTunnelConnection.run() incoming data from
// tunnel");
inputBuffer.flip();
byte[] bbuff = new byte[BUFFER_SIZE];
inputBuffer.get(bbuff, 0, len);
String tunniste = new String(bbuff, 0, 4);
String message = new String(bbuff);
Logger.hysteria("\nIncoming packet:");
Logger.hysteria(message);
Logger.hysteria("Timestamp:"+System.currentTimeMillis());
Logger.hysteria("Frame size:"+len);
if(!tunniste.equals("HTTP"))
{
if(listener != null)
listener.onReceivedData(this, bbuff, len);
else
Logger.warning("HttpTunnelConnection: listener=null");
}
else
{
Logger.hysteria(bbuff.toString());
}
if(alive_time > 0)
expire = System.currentTimeMillis() + alive_time;
}
else if(len == 0)
{
//Logger.warning("No data available in tunnel");
Thread.sleep(2);
}
}
}
catch (Exception e)
{
error = e;
Logger.warning("HTTP tunnel connection closed unexpectedly");
e.printStackTrace();
this.stop = true;
}
is_running = false;
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
if(listener != null)
listener.onConnectionTerminated(this, error);
listener = null;
}
/** Sends data */
public void send(byte[] buff, int offset, int len, int flush) throws IOException
{
if(!this.stop)
{
if((flush & 1) == 1)
{
}
outputBuffer.clear();
outputBuffer.put(buff);
outputBuffer.flip();
socket.channel.write(outputBuffer);
if((flush & 2) == 2)
{
}
}
}
/** Sends data */
public void send(byte[] buff, int flush) throws IOException
{
send(buff, 0, buff.length, flush);
}
/** Stops running */
public void halt()
{
this.stop = true;
try
{
socket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
Logger.warning("HttpTunnelConnection.halt() HTTP tunnel connection closed.");
}
/** Gets the remote IP address */
public IpAddress getRemoteAddress()
{
return socket.getAddress();
}
/** Gets the remote port */
public int getRemotePort()
{
return socket.getPort();
}
/** Gets the TcpSocket */
public HttpTunnelSocket getSocket()
{
return socket;
}
private void init(HttpTunnelSocket socket, long alive_time, HttpTunnelConnectionListener listener)
{
if(!initialized)
{
initialized = true;
this.listener = listener;
this.socket = socket;
this.socket_timeout = DEFAULT_SOCKET_TIMEOUT;
this.alive_time = alive_time;
this.stop = false;
this.is_running = true;
outputBuffer = ByteBuffer.allocate(BUFFER_SIZE);
inputBuffer = ByteBuffer.allocate(BUFFER_SIZE);
this.error = null;
try
{}
catch (Exception e)
{
error = e;
}
}
}
/** Gets a String representation of the Object */
public String toString()
{
return "http:" + socket.getLocalAddress() + ":" + socket.getLocalPort() + "<->" + socket.getAddress() + ":" + socket.getPort();
}
/** Whether the service is running */
public boolean isRunning()
{
return is_running;
}
}