/** * removes this connection from the connections map the datagram channel still sticks around in * case it needs to be reused */ static void removeConnection(RDPConnection con) { lock.lock(); try { if (Log.loggingNet) Log.net("RDPServer.removeConnection: removing con " + con); con.setState(RDPConnection.CLOSED); DatagramChannel dc = con.getDatagramChannel(); // first we get the set of connections attached to the given dc Map<ConnectionInfo, RDPConnection> dcConMap = allConMap.get(dc); if (dcConMap == null) { throw new MVRuntimeException("RDPServer.removeConnection: cannot find dc"); } int localPort = con.getLocalPort(); int remotePort = con.getRemotePort(); InetAddress remoteAddr = con.getRemoteAddr(); ConnectionInfo conInfo = new ConnectionInfo(remoteAddr, remotePort, localPort); Object rv = dcConMap.remove(conInfo); if (rv == null) { throw new MVRuntimeException("RDPServer.removeConnection: could not find the connection"); } // close the datagramchannel if needed // conditions: no other connections on this datagramchannel // no socket listening on this datagramchannel if (dcConMap.isEmpty()) { Log.net("RDPServer.removeConnection: no other connections for this datagramchannel (port)"); // there are no more connections on this datagram channel // check if there is a serversocket listening if (getRDPSocket(dc) == null) { Log.net("RDPServer.removeConnection: no socket listening on this port - closing"); // no socket either, close the datagramchannel dc.socket().close(); channelMap.remove(localPort); Log.net("RDPServer.removeConnection: closed and removed datagramchannel/socket"); } else { Log.net("RDPServer.removeConnection: there is a socket listening on this port"); } } else { Log.net("RDPServer.removeConnection: there are other connections on this port"); } } finally { lock.unlock(); } }
/** * we have a packet that belongs to the passed in connection. process the packet for the * connection. It returns true if the connection is open and the packet was a data packet */ boolean processExistingConnection(RDPConnection con, RDPPacket packet) { if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: con state=" + con + ", packet=" + packet); packetCounter.add(); int state = con.getState(); if (state == RDPConnection.LISTEN) { // something is wrong, we shouldn't be here // we get to this method after looking in the connections map // but all LISTEN connections should be listed direct // from serversockets Log.error("RDPServer.processExistingConnection: connection shouldnt be in LISTEN state"); return false; } if (state == RDPConnection.SYN_SENT) { if (!packet.isAck()) { Log.warn("got a non-ack packet when we're in SYN_SENT"); return false; } if (!packet.isSyn()) { Log.warn("got a non-syn packet when we're in SYN_SENT"); return false; } if (Log.loggingNet) Log.net("good: got syn-ack packet in syn_sent"); // make sure its acking our initial segment # if (packet.getAckNum() != con.getInitialSendSeqNum()) { if (Log.loggingNet) Log.net("syn's ack number does not match initial seq #"); return false; } con.setRcvCur(packet.getSeqNum()); con.setRcvIrs(packet.getSeqNum()); con.setMaxSendUnacks(packet.getSendUnacks()); con.setMaxReceiveSegmentSize(packet.getMaxRcvSegmentSize()); con.setSendUnackd(packet.getAckNum() + 1); // ack first before setting state to open // otherwise some other thread will get woken up and send data // before we send the ack if (Log.loggingNet) Log.net("new connection state: " + con); RDPPacket replyPacket = new RDPPacket(con); con.sendPacketImmediate(replyPacket, false); con.setState(RDPConnection.OPEN); return false; } if (state == RDPConnection.SYN_RCVD) { if (packet.getSeqNum() <= con.getRcvIrs()) { Log.error("seqnum is not above rcv initial seq num"); return false; } if (packet.getSeqNum() > (con.getRcvCur() + (con.getRcvMax() * 2))) { Log.error("seqnum is too big"); return false; } if (packet.isAck()) { if (packet.getAckNum() == con.getInitialSendSeqNum()) { if (Log.loggingNet) Log.net("got ack for our syn - setting state to open"); con.setState(RDPConnection.OPEN); // this will notify() // call the accept callback // first find the serversocket DatagramChannel dc = con.getDatagramChannel(); if (dc == null) { throw new MVRuntimeException( "RDPServer.processExistingConnection: no datagramchannel for connection that just turned OPEN"); } RDPServerSocket rdpSocket = RDPServer.getRDPSocket(dc); if (rdpSocket == null) { throw new MVRuntimeException( "RDPServer.processExistingConnection: no socket for connection that just turned OPEN"); } ClientConnection.AcceptCallback acceptCB = rdpSocket.getAcceptCallback(); if (acceptCB != null) { acceptCB.acceptConnection(con); } else { Log.warn("serversocket has no accept callback"); } if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: got ACK, removing from unack list: " + packet.getSeqNum()); con.removeUnackPacket(packet.getSeqNum()); } } } if (state == RDPConnection.CLOSE_WAIT) { // reply with a reset on all packets if (!packet.isRst()) { RDPPacket rstPacket = RDPPacket.makeRstPacket(); con.sendPacketImmediate(rstPacket, false); } } if (state == RDPConnection.OPEN) { if (packet.isRst()) { // the other side wants to close the connection // set the state, // dont call con.close() since that will send a reset packet if (Log.loggingDebug) Log.debug("RDPServer.processExistingConnection: got reset packet for con " + con); if (con.getState() != RDPConnection.CLOSE_WAIT) { con.setState(RDPConnection.CLOSE_WAIT); con.setCloseWaitTimer(); // Only invoke callback when moving into CLOSE_WAIT // state. This prevents two calls to connectionReset. Log.net("RDPServer.processExistingConnection: calling reset callback"); ClientConnection.MessageCallback pcb = con.getCallback(); pcb.connectionReset(con); } return false; } if (packet.isSyn()) { // this will close the connection (put into CLOSE_WAIT) // send a reset packet and call the connectionReset callback Log.error( "RDPServer.processExistingConnection: closing connection because we got a syn packet, con=" + con); con.close(); return false; } // TODO: shouldnt it be ok for it to have same seq num? // if it is a 0 data packet? long rcvCur = con.getRcvCur(); if (packet.getSeqNum() <= rcvCur) { if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: seqnum too small - acking/not process"); if (packet.getData() != null) { if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: sending ack even though seqnum out of range"); RDPPacket replyPacket = new RDPPacket(con); con.sendPacketImmediate(replyPacket, false); } return false; } if (packet.getSeqNum() > (rcvCur + (con.getRcvMax() * 2))) { Log.error("RDPServer.processExistingConnection: seqnum too big - discarding"); return false; } if (packet.isAck()) { if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: processing ack " + packet.getAckNum()); // lock for race condition (read then set) con.getLock().lock(); try { if (packet.getAckNum() >= con.getSendNextSeqNum()) { // acking something we didnt even send yet Log.error( "RDPServer.processExistingConnection: discarding -- got ack #" + packet.getAckNum() + ", but our next send seqnum is " + con.getSendNextSeqNum() + " -- " + con); return false; } if (con.getSendUnackd() <= packet.getAckNum()) { con.setSendUnackd(packet.getAckNum() + 1); if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: updated send_unackd num to " + con.getSendUnackd() + " (one greater than packet ack) - " + con); con.removeUnackPacketUpTo(packet.getAckNum()); } if (packet.isEak()) { List eackList = packet.getEackList(); Iterator iter = eackList.iterator(); while (iter.hasNext()) { Long seqNum = (Long) iter.next(); if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: got EACK: " + seqNum); con.removeUnackPacket(seqNum.longValue()); } } } finally { con.getLock().unlock(); if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: processed ack " + packet.getAckNum()); } } // process the data byte[] data = packet.getData(); if ((data != null) || packet.isNul()) { dataCounter.add(); // lock - since racecondition: we read then set con.getLock().lock(); try { rcvCur = con.getRcvCur(); // update rcvCur if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: rcvcur is " + rcvCur); ClientConnection.MessageCallback pcb = con.getCallback(); if (pcb == null) { Log.warn("RDPServer.processExistingConnection: no packet callback registered"); } // call callback only if we havent seen it already - eackd if (!con.hasEack(packet.getSeqNum())) { if (con.isSequenced()) { // this is a sequential connection, // make sure this is the 'next' packet // is this the next sequential packet if (packet.getSeqNum() == (rcvCur + 1)) { // this is the next packet if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: conn is sequenced and received next packet, rcvCur=" + rcvCur + ", packet=" + packet); if ((pcb != null) && (data != null)) { queueForCallbackProcessing(pcb, con, packet); } } else { // not the next packet, place it in queue if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: conn is sequenced, BUT PACKET is OUT OF ORDER: rcvcur=" + rcvCur + ", packet=" + packet); con.addSequencePacket(packet); } } else { if ((pcb != null) && (data != null)) { // make sure we havent already processed packet queueForCallbackProcessing(pcb, con, packet); } } } else { if (Log.loggingNet) Log.net(con.toString() + " already seen this packet"); } // is this the next sequential packet if (packet.getSeqNum() == (rcvCur + 1)) { con.setRcvCur(rcvCur + 1); if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection RCVD: incremented last sequenced rcvd: " + (rcvCur + 1)); // packet in order - dont add to eack // Take any additional sequential packets off eack long seqNum = rcvCur + 2; while (con.removeEack(seqNum)) { if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: removing/collapsing eack: " + seqNum); con.setRcvCur(seqNum++); } if (con.isSequenced()) { rcvCur++; // since we just process the last one Log.net( "RDPServer.processExistingConnection: connection is sequenced, processing collapsed packets."); // send any saved sequential packets also Iterator iter = con.getSequencePackets().iterator(); while (iter.hasNext()) { RDPPacket p = (RDPPacket) iter.next(); if (Log.loggingNet) Log.net( "rdpserver: stored packet seqnum=" + p.getSeqNum() + ", if equal to (rcvcur + 1)=" + (rcvCur + 1)); if (p.getSeqNum() == (rcvCur + 1)) { Log.net( "RDPServer.processExistingConnection: this is the next packet, processing"); // this is the next packet - update rcvcur rcvCur++; // process this packet Log.net( "RDPServer.processExistingConnection: processing stored sequential packet " + p); byte[] storedData = p.getData(); if (pcb != null && storedData != null) { queueForCallbackProcessing(pcb, con, packet); } iter.remove(); } } } else { if (Log.loggingNet) Log.net("RDPServer.processExistingConnection: connection is not sequenced"); } } else { if (Log.loggingNet) Log.net( "RDPServer.processExistingConnection: RCVD OUT OF ORDER: packet seq#: " + packet.getSeqNum() + ", but last sequential rcvd packet was: " + con.getRcvCur() + " -- not incrementing counter"); if (packet.getSeqNum() > rcvCur) { // must be at least + 2 larger than rcvCur if (Log.loggingNet) Log.net("adding to eack list " + packet); con.addEack(packet); } } } finally { con.getLock().unlock(); } return true; } } return false; }