org.jnode.net.ipv4.tcp.TCPProtocol.java Source code

Java tutorial

Introduction

Here is the source code for org.jnode.net.ipv4.tcp.TCPProtocol.java

Source

/*
 * $Id: TCPProtocol.java 4241 2008-06-15 12:50:44Z lsantha $
 *
 * JNode.org
 * Copyright (C) 2003-2006 JNode.org
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This library 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 Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library; If not, write to the Free Software Foundation, Inc., 
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
/*
 * 2008 - 2010 (c) Waterford Institute of Technology
 *         TSSG, EU ICT 4WARD
 *
 * 2010 (c) Pouzin Society
 *   - Forked from EU ICT 4WARD Open Source Distribution.
 *   - Organisation Strings updated to reflect fork.
 *
 *
 * Author        : pphelan(at)tssg.org
 *
 * Modifications : Changes to port JNode code base to OSGi platform.
 *                 - log4j -> apache commons
 *                 - java.net -> jnode.net
 *
 */
package org.jnode.net.ipv4.tcp;

import java.net.BindException;
import java.net.SocketException;
import jnode.net.DatagramSocketImplFactory;
import jnode.net.SocketImplFactory;
import org.apache.commons.logging.*;
import org.jnode.driver.net.NetworkException;
import org.jnode.net.SocketBuffer;
import org.jnode.net.ipv4.IPv4Address;
import org.jnode.net.ipv4.IPv4Constants;
import org.jnode.net.ipv4.IPv4Header;
import org.jnode.net.ipv4.IPv4Protocol;
import org.jnode.net.ipv4.IPv4Service;
import org.jnode.net.ipv4.icmp.ICMPUtils;
import org.jnode.util.Statistics;

/**
 * @author epr
 */
public class TCPProtocol implements IPv4Protocol, IPv4Constants, TCPConstants {
    private static final boolean DEBUG = false;

    /**
     * The IP service I'm a part of
     */
    private final IPv4Service ipService;

    /** The ICMP service */
    @SuppressWarnings("unused")
    private final ICMPUtils icmp;

    /**
     * My statistics
     */
    private final TCPStatistics stat = new TCPStatistics();

    /**
     * The SocketImpl factory for TCP
     */
    private final TCPSocketImplFactory socketImplFactory;

    /**
     * My control blocks
     */
    private final TCPControlBlockList controlBlocks;

    /**
     * The timer
     */
    private final TCPTimer timer;

    /**
     * My logger
     */
    private static final Log log = LogFactory.getLog(TCPProtocol.class);

    /**
     * Initialize a new instance
     *
     * @param ipService
     */
    public TCPProtocol(IPv4Service ipService) throws NetworkException {
        this.ipService = ipService;
        this.icmp = new ICMPUtils(ipService);
        this.controlBlocks = new TCPControlBlockList(this);
        this.timer = new TCPTimer(controlBlocks);
        this.socketImplFactory = new TCPSocketImplFactory(this);

        ipService.registerProtocol(this);
        timer.start();
        log.info("TCPProtocol Started");
    }

    /**
     * @see org.jnode.net.TransportLayer#getDatagramSocketImplFactory()
     */
    public DatagramSocketImplFactory getDatagramSocketImplFactory() throws SocketException {
        throw new SocketException("TCP is socket based");
    }

    /**
     * @see org.jnode.net.TransportLayer#getName()
     */
    public String getName() {
        return "tcp";
    }

    /**
     * @see org.jnode.net.TransportLayer#getProtocolID()
     */
    public int getProtocolID() {
        return IPPROTO_TCP;
    }

    /**
     * @see org.jnode.net.TransportLayer#getSocketImplFactory()
     */
    public SocketImplFactory getSocketImplFactory() throws SocketException {
        return socketImplFactory;
    }

    /**
     * @see org.jnode.net.TransportLayer#getStatistics()
     */
    public Statistics getStatistics() {
        return stat;
    }

    /**
     * @see org.jnode.net.TransportLayer#receive(org.jnode.net.SocketBuffer)
     */
    public void receive(SocketBuffer skbuf) throws SocketException {

        // Increment stats
        stat.ipackets.inc();

        // Get the IP header
        final IPv4Header ipHdr = (IPv4Header) skbuf.getNetworkLayerHeader();

        // Read the TCP header
        final TCPHeader hdr = new TCPHeader(skbuf);

        // Set the TCP header in the buffer-field
        skbuf.setTransportLayerHeader(hdr);
        // Remove the TCP header from the head of the buffer
        skbuf.pull(hdr.getLength());
        // Trim the buffer up to the length in the TCP header
        skbuf.trim(hdr.getDataLength());

        if (!hdr.isChecksumOk()) {
            if (DEBUG) {
                if (log.isDebugEnabled()) {
                    log.debug("Receive: badsum: " + hdr);
                }
            }
            stat.badsum.inc();
        } else {
            if (DEBUG) {
                if (log.isDebugEnabled()) {
                    log.debug("Receive: " + hdr);
                }
            }

            // Find the corresponding control block
            final TCPControlBlock cb = (TCPControlBlock) controlBlocks.lookup(ipHdr.getSource(), hdr.getSrcPort(),
                    ipHdr.getDestination(), hdr.getDstPort(), true);

            log.debug("src: " + ipHdr.getSource().toString() + ":" + hdr.getSrcPort() + " dst: "
                    + ipHdr.getDestination().toString() + ":" + hdr.getDstPort());
            if (cb == null) {
                final boolean ack = hdr.isFlagAcknowledgeSet();
                final boolean rst = hdr.isFlagResetSet();

                stat.noport.inc();

                // Port unreachable
                if (ack && rst) {
                    // the source is also unreachable
                    log.debug("Dropping segment due to: connection refused as the source is also unreachable");
                } else {
                    processPortUnreachable(ipHdr, hdr);
                }
            } else {
                // Let the cb handle the receive
                cb.receive(hdr, skbuf);
            }
        }
    }

    /**
     * @see org.jnode.net.ipv4.IPv4Protocol#receiveError(org.jnode.net.SocketBuffer)
     */
    public void receiveError(SocketBuffer skbuf) throws SocketException {
        // TODO Auto-generated method stub

    }

    /**
     * Process a segment whose destination port is unreachable
     *
     * @param hdr
     */
    private void processPortUnreachable(IPv4Header ipHdr, TCPHeader hdr) throws SocketException {
        final TCPHeader replyHdr = new TCPHeader(hdr.getDstPort(), hdr.getSrcPort(), 0, 0, hdr.getSequenceNr() + 1,
                0, 0);
        replyHdr.setFlags(TCPF_ACK | TCPF_RST);
        final IPv4Header replyIpHdr = new IPv4Header(ipHdr);
        replyIpHdr.swapAddresses();
        send(replyIpHdr, replyHdr, new SocketBuffer());
    }

    /**
     * Create a binding for a local address
     *
     * @param lAddr
     * @param lPort
     */
    public TCPControlBlock bind(IPv4Address lAddr, int lPort) throws BindException {
        log.debug("Bind: " + lAddr.toString() + ":" + lPort);
        return (TCPControlBlock) controlBlocks.bind(lAddr, lPort);
    }

    /**
     * Send an TCP packet
     *
     * @param skbuf
     */
    protected void send(IPv4Header ipHdr, TCPHeader tcpHdr, SocketBuffer skbuf) throws SocketException {
        if (DEBUG) {
            if (log.isDebugEnabled()) {
                log.debug("send(ipHdr, " + tcpHdr + ")");
            }
        }
        skbuf.setTransportLayerHeader(tcpHdr);
        tcpHdr.prefixTo(skbuf);
        ipHdr.setDataLength(skbuf.getSize());
        ipService.transmit(ipHdr, skbuf);
        stat.opackets.inc();
    }

    /**
     * Get the current time counter
     */
    protected long getTimeCounter() {
        return timer.getCounter();
    }
}