package libcsp.csp.core; import libcsp.csp.CSPManager; import libcsp.csp.Connection; import libcsp.csp.ImmortalEntry; import libcsp.csp.Packet; import libcsp.csp.handlers.RouteHandler; import libcsp.csp.util.Const; import libcsp.csp.util.IDispose; import libcsp.csp.util.Queue; /** * Specific implementation of a CSP Connection that implements all the logic * needed for communication to take place. * * A ConnectionCore is uniquely identified with an identifier. The connection * identifier format is: S000000000 | SRC:5 | SPORT:6 | DST:5 | DPORT:6 | * * @author Mikkel Todberg, Jeppe Lund Andersen * */ public class ConnectionCore implements IDispose, Connection { /* Connection masks */ public final static int MASK_SRC = 0x003E0000; public final static int MASK_SPORT = 0x0001F800; public final static int MASK_DST = 0x000007C0; public final static int MASK_DPORT = 0x0000003F; /* * Connection identifier Format: * S000000000 | SRC:5 | SPORT:6 | DST:5 | DPORT:6 | */ public int id; /* Packets can only be exchanged when the connection is open */ public boolean isOpen; /* Packets stored by the Connection object */ public Queue<PacketCore> packets; /** * Create a new <code>ConnectionCore</code> object that can hold the * specified number of packets. * * @param packetsCapacity * The maximum number of packets that can be stored by the * ConnectionCore object */ public ConnectionCore(byte packetsCapacity) { this.packets = new Queue<PacketCore>(packetsCapacity); } /** * Set the identifier for this Connection * * @param SRC * Source address * @param SPORT * Source port * @param DST * Destination address * @param DPORT * Destination port */ public void setId(byte SRC, byte SPORT, byte DST, byte DPORT) { setSRC(SRC); setSPORT(SPORT); setDST(DST); setDPORT(DPORT); } /** * Returns the destination port of this connection * * @return The destination port of this connection */ public byte getDPORT() { return (byte) (id & MASK_DPORT); } /** * Returns the destination address of this connection * * @return The destination address of this connection */ public byte getDST() { return (byte) ((id & MASK_DST) >>> 6); } /** * Returns the source port of this connection * * @return The source port of this connection */ public byte getSPORT() { return (byte) ((id & MASK_SPORT) >>> 11); } /** * Returns the source address of this connection * * @return The source address of this connection */ public byte getSRC() { return (byte) ((id & MASK_SRC) >>> 17); } /** * Sets the destination port for this connection * * @param DPORT * The destination port */ public void setDPORT(byte DPORT) { id &= ~(MASK_DPORT); id |= (int) DPORT; } /** * Sets the destination address for this connection * * @param DST * The destination address */ public void setDST(byte DST) { id &= ~(MASK_DST); id |= ((int) DST << 6); } /** * Sets the source port for this connection * * @param SPORT * The source port */ public void setSPORT(byte SPORT) { id &= ~(MASK_SPORT); id |= ((int) SPORT << 11); } /** * Sets the source address for this connection * * @param SRC * The source address */ public void setSRC(byte SRC) { id &= ~(MASK_SRC); id |= ((int) SRC << 17); } /** * Attempt to read any packet received in FIFO order. If the packet queue is * not empty, then the packet is removed from the Queue associated with this * ConnectionCore object. A local copy of the packet is created in the scope * of the caller and the dequeued packet is returned to pool of available * Packets. * * A read operation reads from the local packet queue. * * @param timeout * Maximum time in milliseconds to wait for an unused packet from * the packet pool * @return Next packet received on the connection or null if the queue is * empty or the timeout expires */ public PacketCore read(int timeout) { PacketCore packet = packets.dequeue(timeout); if (packet != null) { PacketCore packetCopy = new PacketCore(packet.header, packet.data); ImmortalEntry.resourcePool.putPacket(packet); return packetCopy; } return null; } /** * Attempts to send a packet by inserting it into the router's send queue. * If the router queue has not reached its maximum capacity, then the packet * is enqueued in the router's packet queue. Otherwise the packet is * discarded. * * The send operation writes to the router packet queue. */ public void send(Packet packet) { PacketCore p = (PacketCore) packet; p.setSRC(CSPManager.nodeAddress); p.setSPORT(getSPORT()); p.setDST(getDST()); p.setDPORT(getDPORT()); if (ImmortalEntry.packetsToBeProcessed.count < ImmortalEntry.packetsToBeProcessed.capacity) { ImmortalEntry.packetsToBeProcessed.enqueue(p); } else { //TODO: Isn't it the same as this? //p.dispose(); ImmortalEntry.resourcePool.packets.enqueue(p); } } /** * If the connection is in an open state and the packet queue is not full, * this method adds the packet passed as parameter to the tail of the packet * queue. Otherwise the packet is discarded and returned to its resource * pool. * * The processPacket operation writes to the local packet queue. * * @param packet */ public synchronized void processPacket(PacketCore packet) { if (isOpen && !packets.isFull()) { packets.enqueue(packet); } else { packet.dispose(); } } /** * Closes a connection and returns the Connection object to its resource * pool */ public synchronized void close() { if (isOpen) { byte SPORT = getSPORT(); if (SPORT > Const.MAX_INCOMING_PORTS) { SPORT -= (Const.MAX_INCOMING_PORTS + 1); ImmortalEntry.outgoingPorts &= ~(1 << SPORT); } dispose(); } } /** * Returns the connection ID from a packet header * * @param packet * The packet from where the connection ID will be extracted * @return The connection ID from a packet header * */ public static int getConnectionIdFromPacketHeader(PacketCore packet) { int connectionId = 0; connectionId = (packet.getDST() << 17); connectionId |= (packet.getDPORT() << 11); connectionId |= (packet.getSRC() << 6); connectionId |= packet.getSPORT(); return connectionId; } /** * Returns the connection object into its corresponding resource pool. When * this method is called, the connection state is reset and the local packet * queue is flushed of any remaining packet. */ @Override public void dispose() { this.isOpen = false; this.id = 0; this.packets.reset(); ImmortalEntry.resourcePool.putConnection(this); } }