head	1.1;
access;
symbols;
locks; strict;
comment	@# @;


1.1
date	2008.10.15.09.17.36;	author martin;	state Exp;
branches;
next	;
commitid	5c4d48f5b52b4567;


desc
@@


1.1
log
@first version of Stefan's ejip changes
@
text
@package ejip123;

import ejip123.util.Dbg;

/** TCP main class. Used for managing TcpConnections and handlers. */
public class Tcp{

/** TCP protocol number. */
public static final int PROTOCOL = 6;

/** Offset of data in words when no options present. */
public static final int OFFSET = Ip.OFFSET + 5;

private static final Object lock = new Object();

private static int MAX_HANDLER = 0;
private static TcpHandler[] list = null;
private static int[] ports = null;
private static TcpConnection[] connections = null;
/** Maximum number of active TCP connections. */
private static int MAX_CON = 0;

private Tcp(){
}

public static void init(int handlerCnt, int concurrConnCnt){
	MAX_HANDLER = handlerCnt <= 0 ? 4 : handlerCnt;
	MAX_CON = handlerCnt <= 0 ? MAX_HANDLER<<1 : concurrConnCnt;

	list = new TcpHandler[MAX_HANDLER];
	ports = new int[MAX_HANDLER];
	connections = new TcpConnection[Tcp.MAX_CON];
	for(int i = 0; i < Tcp.MAX_CON; ++i){
		connections[i] = new TcpConnection();
	}
}

/* Called periodic from Net for timeout processing. */
static void loop(int cur){
	synchronized(lock){
		for(int i = 0; i < MAX_CON; ++i){
			TcpConnection tc = connections[i];
			tc.loop(cur);

		}
	}
}

/* Processes packet and generate reply if necessary. */
static void process(Packet p, int off){
	int[] buf = p.buf;
	int src = buf[3];
	int dst = buf[4];
	// inject pseudo header for tcp checksum into original packet
	// for packets w/o options: ttl, prot and ip checksum are overwritten
	buf[off - 1] = dst;
	buf[off - 2] = src;
	buf[off - 3] = (PROTOCOL<<16) + p.len() - (off<<2);
	if(Ip.chkSum(buf, off - 3, p.len() - ((off - 3)<<2)) != 0){
		Dbg.wr("tcp checksum failed!\n");
		p.free();
		return;
	}

	int dstPort = buf[off];
	int srcPort = dstPort>>>16;
	dstPort &= 0xffff;

	synchronized(lock){
		TcpConnection free = null;
		for(int i = 0; i < MAX_CON; ++i){
			TcpConnection tc = connections[i];
			if(tc.isUsed()){
				if(tc.processPacket(src, dst, srcPort, dstPort, p, off)){
					return;
				}
			} else{
				free = tc;
			}
		}
		// if not found get a new one if possible or drop the packet
		if(free != null){
//			Dbg.wr("new con\n");
			free.newIncoming(src, dst, srcPort, dstPort, p, off);
		} else{
			// TODO rst? port unreachable? protocol unreachable?
			p.free();
		}
	}
}

static int getMaxPayload(int dstIp){
	//  int max = Ip.getMaxPayload(dstIp) - ((Tcp.OFFSET - Ip.OFFSET)<<2);
	//	Dbg.wr("max local link payload=");
	//	Dbg.intVal(max);
	return Ip.getMaxPayload(dstIp) - ((Tcp.OFFSET - Ip.OFFSET)<<2);
}

/**
 Opens a client connection. Fetches an available connection from the pool, sets it up and tries to connect to the remote
 host. Local IP and port will be chosen by the implementation.

 @@param dstIp   The remote IP.
 @@param dstPort The remote port.
 @@param th      The TcpHandler, that will handle events for this connection.
 @@return The fetched connection of null if there was an error. */
public static TcpConnection open(int dstIp, int dstPort, TcpHandler th){
	return open(dstIp, dstPort, dstPort, th);
}

/**
 Opens a client connection. Fetches an available connection from the pool, sets it up and tries to connect to the remote
 host. Local IP will be chosen by the implementation.

 @@param dstIp   The remote IP.
 @@param srcPort The local port.
 @@param dstPort The remote port.
 @@param th      The TcpHandler, that will handle events for this connection.
 @@return The fetched connection of null if there was an error. */
public static TcpConnection open(int dstIp, int srcPort, int dstPort, TcpHandler th){
	int srcIp = Ip.getSrcIp(dstIp);
	return open(srcIp, dstIp, srcPort, dstPort, th);
}

/**
 Opens a client connection. Fetches an available connection from the pool, sets it up and tries to connect to the remote
 host.

 @@param srcIp   The local IP.
 @@param dstIp   The remote IP.
 @@param srcPort The local port.
 @@param dstPort The remote port.
 @@param th      The TcpHandler, that will handle events for this connection.
 @@return The fetched connection of null if there was an error. */
public static TcpConnection open(int srcIp, int dstIp, int srcPort, int dstPort, TcpHandler th){
	synchronized(lock){
		// check that there is no for that port
		if(th == null || getHandler(srcPort) != null)
			return null;

		// check that there is no matching connection yet
		TcpConnection free = null;
		for(int i = 0; i < MAX_CON; ++i){
			TcpConnection tc = connections[i];
			if(tc.isUsed()){
				if(tc.matches(srcIp, dstIp, srcPort, dstPort)){
					return null;
				}
			} else{
				free = tc;
			}
		}
		if(free != null && free.open(dstIp, srcIp, dstPort, srcPort, th))
			return free;
	}
	return null;
}

/**
 Registers a TcpHandler for a port.

 @@param port The port.
 @@param h    The handler.
 @@return True, if successfully registered. False, if list is full or there is already a handler registered for that
 port. */
public static boolean addHandler(int port, TcpHandler h){
	synchronized(lock){
		int free = -1;
		for(int i = 0; i < MAX_HANDLER; ++i){
			if(list[i] == null){
				free = i;
			} else if(ports[i] == port){
				return false;
			}
		}

		if(free != -1){
			ports[free] = port;
			list[free] = h;
			return true;
		}
		return false;
	}
}

/**
 Removes a TCP handler from the list. No new connections will be forwarded to that handler. Existing connection (even not
 yet fully established ones) are not touched by this. A handler has to close all existing non reset connections before it
 totally abandons them.

 @@param port The port the handler wants to be listening to.
 @@return false if it was not in the list. */
public static boolean removeHandler(int port){
	synchronized(lock){
		for(int i = 0; i < MAX_HANDLER; ++i){
			if(list[i] != null && ports[i] == port){
				list[i] = null;
				return true;
			}
		}
	}
	return false;
}

/**
 Fetches a handler.

 @@param port The TCP port in question.
 @@return The TcpHandler registered for that port or null if there is none. */
static TcpHandler getHandler(int port){
	TcpHandler th = null;
	// is a handler registered for that port?
	synchronized(lock){
		for(int i = 0; i < MAX_HANDLER; ++i){
			if(list[i] != null && ports[i] == port){
				th = list[i];
				break;
			}
		}
	}
	return th;
}
}
@
