Beispiel #1
0
    def recvHELLO(self, pkt):
        """Receive a HELLO packet.

        :param pkt: Decoded control packet.
        :return: None.

        """
        self.logger.debug(
            "Receive a Hello message from remote, send a ZLB to it")
        return L2tpv3ControlPacket.L2tpv3ZLB(self.remoteConnID)
Beispiel #2
0
    def TimetickCallback(self):
        """Check the timers, we should process the lastSendtime and
        lastRecvTime."""
        currtime = time.time()

        # if some one changed the system time
        time_offset = 0
        if currtime - self.lastTimetick >= 5:
            self.logger.warn(
                "Transport[localAddr:%s, remoteAddr:%s, localConnectionID:%d, remoteConnection:%d] "
                "detected time change, current time is %f, lasttime tick time is %f" % (
                    self.localAddr, self.remoteAddr, self.connection.localConnID,
                    self.connection.remoteConnID, currtime,
                    self.lastTimetick
                ))
            # Try to update the resend list packet timeout
            if len(self.sendList) > 0:
                tLast = self.sendList[len(self.sendList) - 1]["time"]
                for resendStructure in self.sendList:
                    resendStructure["time"] = currtime + (
                        resendStructure["time"] - tLast)

            # Try to update the last recv time and last send time
            time_offset = currtime - self.lastTimetick

        elif currtime - self.lastTimetick < 0:
            self.logger.warn(
                "Transport[localAddr:%s, remoteAddr:%s, localConnectionID:%d, remoteConnection:%d] "
                "detected time change, current time is %f, lasttime tick time is %f" % (
                    self.localAddr, self.remoteAddr, self.connection.localConnID,
                    self.connection.remoteConnID, currtime, self.lastTimetick
                ))
            # Update sth, and trigger an event
            self.lastSendTime = self.lastTimetick - currtime - 1000
            if self.helloMsgTimeout > self.connectionTimeout:
                self.lastRecvTime = currtime - self.helloMsgTimeout - 1
            else:
                self.lastRecvTime = currtime - self.connectionTimeout - 1

            # Update the sendlist
            if len(self.sendList) > 0:
                tLast = self.sendList[len(self.sendList) - 1]["time"]
                for resendStructure in self.sendList:
                    resendStructure["time"] = currtime + (
                        resendStructure["time"] - tLast)

            # Try to update the last recv time and last send time
            time_offset = currtime - self.lastTimetick

        self.lastRecvTime += time_offset
        self.lastSendTime += time_offset
        self.lastTimetick = currtime
        if self.needSendZlb and self.lastSendTime + self.sendZlbTimeout < currtime:
            self.logger.debug("Send a ZLB message remote")
            self.SendPacket(
                L2tpv3ControlPacket.L2tpv3ZLB(self.connection.remoteConnID))
            self.needSendZlb = False

        # Process the lastSend
        if self.lastSendTime + self.helloMsgTimeout < currtime and self.lastRecvTime + self.helloMsgTimeout < currtime:
            self.logger.debug(
                "We don't receive any packet for long time, send a hello to remote.")
            if self.connection.fsm.current == self.connection.fsm.StateEstablished:
                self.SendPacket(
                    L2tpv3ControlPacket.L2tpv3Hello(self.connection.remoteConnID))

        if self.lastRecvTime + self.connectionTimeout < currtime:
            self.logger.debug(
                "The connection[%d] seems dead, close it!" % self.connection.localConnID, )
            self.notify.error(rpd_event_def.RPD_EVENT_L2TP_CONN_ERR[0],
                              rpd_event_def.RpdEventTag.ccap_ip(self.connection.remoteAddr))
            self.connection.CloseConnection()

        # Process the send list
        for resendStructure in self.sendList:
            if currtime > resendStructure["time"] + self.sendTimeout:
                self.logger.warn(
                    "Resend the packet %s to remote." % resendStructure)
                pkt = resendStructure["pkt"]
                self._reSendPacket(pkt)
                resendStructure["time"] = time.time()
                resendStructure["sendTimes"] += 1

                # if we resend the packets for a long time and not get the
                # response
                if resendStructure["sendTimes"] > self.resendTimes:
                    self.logger.warn("Connection[%d] has tried to send packet %d time(s), no response from remote, "
                                     "close the connection.", self.connection.localConnID,
                                     resendStructure["sendTimes"])
                    self.connection.CloseConnection()
Beispiel #3
0
    def ReceivePacket(self, pkt, addr):
        """The pkt is a control packet, with a connection ID Based on the
        RFc3931, we will use the ns value as the key, however, ns value only
        has 16bit, say, it will wrap when we reach 65535, so we have to
        consider this situation. A windowsize is considered to start from the
        self.ackNr, for wrap reason, we will add an wrap count variable, so the
        window start from:

            wrapCount * 65536 + self.ackNr
        AckNr|-------windowsize--------|

        a packet is considered to in the window:
            (pkt.ns >= ackNr) and (pkt.ns < ackNr + windowSize)
            (pkt.ns < ackNr) and (pkt.ns + 65536 > ackNr + windowSize)

        we also need to identify if the packet is early, or late.
        early, means the pkt is beyond the window, we will do nothing for the packet.
        late, we will consider we have processed this message, will send ack to it.

        """
        # The pkt should be decoded
        if not isinstance(pkt, L2tpv3ControlPacket.L2tpv3ControlPacket):
            self.logger.warn(L2tpv3TransportError.ParameterTypeError + ", the dispatcher is not instance of "
                             "L2tpv3ControlPacket.")
            raise L2tpv3TransportError(L2tpv3TransportError.ParameterTypeError)

        if self.connection.isInRecovery:
            self.logger.info(
                "Drop the control message since connection is in recovery")
            return

        if self.connection.isRecoveryTunnel:
            if not pkt.isZlb and pkt.avps[0].messageType not in L2tpv3RFC3931AVPs.ControlMessageAVP.RecoveryTunnelMesagedSet:
                self.logger.warn(
                    "Receive an invalid control message in recovery tunnel")
                return

        self.lastRecvTime = time.time()  # for process the connection timeout

        ns = pkt.ns
        nr = pkt.nr
        self.logger.debug("Receive a packet in transport layer:ns = %d, Nr = %d, "
                          "Current ns= %d and ackNr = %d " % (ns, nr, self.ns, self.ackNr))

        pkt.SetPacketTransport(self)
        pkt.SetPktConnection(self.connection)

        # remove the ack send
        while len(self.sendList) > 0 and self.sendList[0]["pkt"].ns < nr:
            self.sendList.pop(0)
        if pkt.isZlb:
            # For ZLB message, will not in the receive window
            return

        # insert the packet into the window, process the duplicate one and the
        # skip one
        tmpNs = ns
        if ns < self.ackNr:
            tmpNs += 65536

        # Check if the packet is a early packet, maybe we can use the 16bit
        # signed number for this:)
        tmpNr = self.ackNr
        if tmpNr < ns:
            tmpNr += 65536
        if (tmpNr - ns < 32768) and (tmpNr - ns > 0):  # late ones
            # will send the ZLB to remote
            self.logger.debug(
                "This packet is considered a duplicated one, send ack to it")
            self.SendPacket(L2tpv3ControlPacket.L2tpv3ZLB(
                self.connection.remoteConnID), addr)
            return

        if (tmpNs >= self.ackNr) and (tmpNs < self.ackNr + self.receiveWindowSize):
            if len(self.receiveWindow) >= self.receiveWindowSize:
                self.logger.warn(
                    "Receive window size reaches the max : %d", self.receiveWindowSize)
                pass  # Do we need send a ack?
            for item in self.receiveWindow.irange(pkt, pkt):
                self.logger.debug(
                    "pkt ns[%d] is already in receiveWindow", pkt.ns)
                break
            else:
                self.receiveWindow.add(pkt)
        else:
            self.logger.warn(
                "Receive a packet with wrong Nr/Ns, Nr:%d, Ns:%d, ackNr:%d, wrap_count:%d",
                nr, ns, self.ackNr, self.wrapCount)
            return

        # Give a chance to process the receive window
        # If we did not receive the window for a long time,
        self.logger.debug(
            "Receive a packet with windowsize:%d,firstNs=%d, ackNr=%d",
            len(self.receiveWindow), self.receiveWindow[0].ns, self.ackNr)
        while len(self.receiveWindow) > 0 and self.receiveWindow[0].ns == self.ackNr:
            self.ackNr += 1

            if self.ackNr >= 65536:
                self.wrapCount += 1
                self.ackNr = 0
            pktProcessing = self.receiveWindow.pop(0)
            retPkt = self.connection.HandlePkt(pktProcessing)
            if retPkt is not None:
                self.SendPacket(retPkt, addr=addr)