/*
* Copyright (c) 2006-2007 Graz University of Technology. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The names "Graz University of Technology" and "IAIK of Graz University of
* Technology" must not be used to endorse or promote products derived from
* this software without prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package ejip.jtcpip;
import util.Dbg;
import joprt.RtThread;
import ejip_old.Arp;
import ejip_old.LinkLayer;
import ejip_old.Net;
import ejip_old.Packet;
import ejip.jtcpip.util.Debug;
/**
* Network loop class. Creates a thread for a given Net and LinkLayer instance
*
* @author Ulrich Feichter
* @author Tobias Kellner
* @author Christof Rath
* @version $Rev: 984 $ $Date: 2009/01/12 23:00:13 $
*/
public class NwLoopThread // extends RtThread
{
public static TCPConnection conn = null;
public static Payload pay = null;
/** Holds the instance for the singelton pattern */
private static NwLoopThread nwLoop;
/**
* Holds a references to the LinkLayer instances to call the
* LinkLayer.loop()
*/
private LinkLayer linkLayer;
/** counts the loop cycles up to StackParameters.NW_LOOP_CYCLES */
private int cycleCnt = 0;
/**
* if the cycleCnt % tcpModulus == 0 the next TCP connection is tested to
* send new data of the oStream
*/
private int tcpModulus = StackParameters.NW_LOOP_CYCLES
/ StackParameters.TCP_CONNECTION_POOL_SIZE;
/**
* Creates the network loop instance
*
* @param linkLayer
* Instances to the link layers
* @param msDelay
* Delay in milli seconds between two calls
*/
private NwLoopThread(LinkLayer linkLayer, int msDelay) {
this.linkLayer = linkLayer;
}
public void run() {
// Dbg.wr("NWLOOP\n");
if (cycleCnt % tcpModulus == 0) {
int conToTest = cycleCnt / tcpModulus;
if (TCPConnection.pool[conToTest] != null
&& TCPConnection.pool[conToTest].getState() != TCPConnection.STATE_CLOSED) {
if (!TCPConnection.pool[conToTest].pollConnection())
TCPConnection.retryToSendData = conToTest;
}
} else {
if (TCPConnection.retryToSendData > -1) {
if (TCPConnection.pool[TCPConnection.retryToSendData]
.pollConnection())
TCPConnection.retryToSendData = -1;
}
}
int cnt = Payload.waitingPayloadCount();
if (cnt > 0) {
byte status;
for (int i = 0; i < StackParameters.PAYLOAD_POOL_SIZE; i++) {
status = Payload.pool[i].getStatus();
if (status > Payload.PAYLOAD_WND_RX) {
cnt--;
switch (status) {
case Payload.PAYLOAD_FRAGMT:
case Payload.PAYLOAD_SND_RD:
if (preparedSend(Payload.pool[i])) {
// Everything ok -> free payload
Payload.freePayload(Payload.pool[i]);
}
break;
case Payload.PAYLOAD_ARP_WT:
if (Arp.inCache(IPPacket.getDestAddr(Payload.pool[i]))) {
if (Payload.pool[i].getOffset() == 0)
Payload.pool[i].setStatus(
Payload.PAYLOAD_SND_RD, 0);
else
Payload.pool[i].setStatus(
Payload.PAYLOAD_FRAGMT, Payload.pool[i]
.getOffset());
}
if (Payload.pool[i].isTimeout()) {
if (Debug.enabled)
Debug.println("ARP timeout!", Debug.DBG_OTHER);
Payload.freePayload(Payload.pool[i]);
// No one to inform (ICMP) -> free payload
}
break;
case Payload.PAYLOAD_RESMBL:
if (Payload.pool[i].isTimeout()) {
if (Payload.pool[i].getOffset() == 0)
// The first fragment has been received
// -> So we can inform the remote host
ICMP.sendTimeExceeded(Payload.pool[i]);
else
Payload.freePayload(Payload.pool[i]);
// Just free the payload
}
break;
default:
if (Debug.enabled)
Debug.println("Unknown Payload status: ",
Debug.DBG_OTHER);
}
}
if (cnt <= 0)
break;
}
}
Packet p = Packet.getPacket(Packet.RCV, Packet.ALLOC);
if (p != null){
IP.receivePacket(p);
Dbg.wr("Ip.receive returned\n");
}
if((conn != null) && (pay != null)){
TCP.sendPackets(conn, pay);
conn = null;
pay = null;
}
cycleCnt++;
if (cycleCnt >= StackParameters.NW_LOOP_CYCLES)
cycleCnt = 0;
}
/**
* Tries to send a payload that is in the PAYLOAD_SND_RD state
*
* @param pay
* @return true if the complete payload has been sent
*/
protected static boolean preparedSend(Payload pay) {
if (Debug.enabled)
Debug.println("prepared send", Debug.DBG_OTHER);
// TODO for Dhcp
// int firstHopDest = (LinkLayer.isSameSubnet(IPPacket.getDestAddr(pay))
// ? IPPacket
// .getDestAddr(pay)
// : Net.linkLayer.gateway);
int firstHopDest = IPPacket.getDestAddr(pay);
// System.out.println(IPPacket.getDestAddr(pay));
// FIXME: For LinkLayers that do not require ARP (e.g. Slip, Loopback)
// this has to be modified
boolean inCache = (Arp.inCache(firstHopDest)
|| (firstHopDest == Net.linkLayer.getIpAddress())
// loopback to same addr
|| (firstHopDest >= 2130706433 && firstHopDest <= 2147483646));
// loopback to 127.x.x.x
Packet p = Packet.getPacket(Packet.FREE, Packet.ALLOC, Net.linkLayer);
if (p == null)
return false;
if (!inCache)
pay.setStatus(Payload.PAYLOAD_ARP_WT, StackParameters.ARP_TIMEOUT);
int offset = 0;
if (inCache)
offset = pay.getOffset();
else
offset = Math.max(pay.length / 4 - 1, 0);
// int offset = inCache ? pay.getOffset() : Math
// .max(pay.length / 4 - 1, 0);
// // If ARP request use just the minimum of Payload
offset = IP.payloadToPacket(pay, p, offset);
if (firstHopDest == Net.linkLayer.getIpAddress() // loopback to same
// addr
|| (firstHopDest >= 2130706433 && firstHopDest <= 2147483646)) // loopback
// to
// 127.x.x.x
p.setStatus(Packet.RCV);
else {
if (!inCache && IPPacket.getDestAddr(pay) != firstHopDest) { // Request
// ARP
// resolution
// for
// gateway
// IP destination address (without gateway) is
// at position 4 for IP packets and at 6 for ARP packets
int addrPos = p.llh[6] == 0x0806 ? 6 : 4;
p.buf[addrPos] = firstHopDest;
}
p.setStatus(Packet.SND_DGRAM);
}
if (offset > 0)
pay.setStatus(Payload.PAYLOAD_FRAGMT, offset);
return inCache && offset == 0;
}
/**
* Creates and start the network loop thread
*
* @param linkLayer
* @return The instance of the network loop
*/
public static NwLoopThread createInstance(LinkLayer linkLayer) {
if (nwLoop == null) {
nwLoop = new NwLoopThread(linkLayer,
StackParameters.NW_LOOP_TIMEOUT);
// nwLoop.start();
}
return nwLoop;
}
/**
* Returns the instance of the network loop
*
* @return NwLoopThread
*/
public static NwLoopThread getInstance() {
return nwLoop;
}
}