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)
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()
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)