| 
					
				 | 
			
			
				@@ -18,6 +18,16 @@ var ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	errClosedConnection = errors.New("Connection closed.") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+type State int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+const ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	StateActive       State = 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	StateReadyToClose State = 1 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	StatePeerClosed   State = 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	StateTerminating  State = 3 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	StateTerminated   State = 4 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	headerSize uint32 = 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -30,17 +40,36 @@ func nowMillisec() int64 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Connection is a KCP connection over UDP. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 type Connection struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	sync.RWMutex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	kcp           *KCP // the core ARQ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	kcpAccess     sync.Mutex 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	block         Authenticator 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	local, remote net.Addr 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	wd            time.Time // write deadline 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	writer        io.WriteCloser 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	since         int64 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conv             uint16 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	state            State 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	stateBeginTime   uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	lastIncomingTime uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	lastPayloadTime  uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sendingUpdated   bool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	lastPingTime     uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	mss                        uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	rx_rttvar, rx_srtt, rx_rto uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	interval                   uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	receivingWorker *ReceivingWorker 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	sendingWorker   *SendingWorker 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	fastresend        uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	congestionControl bool 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	output            *BufferedSegmentWriter 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // NewConnection create a new KCP connection between local and remote. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, remote *net.UDPAddr, block Authenticator) *Connection { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	log.Debug("KCP|Connection: creating connection ", conv) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	conn := new(Connection) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	conn.local = local 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	conn.remote = remote 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -52,8 +81,16 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Authenticator: block, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		Writer:        writerCloser, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	conn.kcp = NewKCP(conv, authWriter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	conn.kcp.current = conn.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.conv = conv 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.output = NewSegmentWriter(authWriter) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.mss = authWriter.Mtu() - DataSegmentOverhead 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.rx_rto = 100 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.interval = effectiveConfig.Tti 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.receivingWorker = NewReceivingWorker(conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.fastresend = 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.congestionControl = effectiveConfig.Congestion 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	conn.sendingWorker = NewSendingWorker(conn) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	go conn.updateTask() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -66,39 +103,37 @@ func (this *Connection) Elapsed() uint32 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Read implements the Conn Read method. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) Read(b []byte) (int, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if this == nil || this.kcp.state == StateTerminating || this.kcp.state == StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return 0, io.EOF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	return this.kcp.receivingWorker.Read(b) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	state := this.State() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateTerminating || state == StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 0, io.EOF 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return this.receivingWorker.Read(b) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Write implements the Conn Write method. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) Write(b []byte) (int, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if this == nil || this.kcp.state != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this == nil || this.State() != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return 0, io.ErrClosedPipe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	totalWritten := 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	for { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.RLock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if this == nil || this.kcp.state != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-			this.RUnlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if this == nil || this.State() != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			return totalWritten, io.ErrClosedPipe 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.RUnlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcpAccess.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		nBytes := this.kcp.sendingWorker.Push(b[totalWritten:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		nBytes := this.sendingWorker.Push(b[totalWritten:]) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if nBytes > 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			totalWritten += nBytes 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if totalWritten == len(b) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				return totalWritten, nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		if !this.wd.IsZero() && this.wd.Before(time.Now()) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			return totalWritten, errTimeout 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -108,21 +143,46 @@ func (this *Connection) Write(b []byte) (int, error) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) SetState(state State) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.state = state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.stateBeginTime = this.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	switch state { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case StateReadyToClose: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.receivingWorker.CloseRead() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case StatePeerClosed: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.sendingWorker.CloseWrite() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case StateTerminating: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.receivingWorker.CloseRead() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.sendingWorker.CloseWrite() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	case StateTerminated: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.receivingWorker.CloseRead() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.sendingWorker.CloseWrite() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Close closes the connection. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) Close() error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if this == nil || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcp.state == StateReadyToClose || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcp.state == StateTerminating || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcp.state == StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return errClosedConnection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	state := this.State() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateReadyToClose || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		state == StateTerminating || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		state == StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return errClosedConnection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	log.Debug("KCP|Connection: Closing connection to ", this.remote) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer this.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcpAccess.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcp.OnClose() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.SetState(StateReadyToClose) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StatePeerClosed { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.SetState(StateTerminating) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -156,36 +216,29 @@ func (this *Connection) SetDeadline(t time.Time) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // SetReadDeadline implements the Conn SetReadDeadline method. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) SetReadDeadline(t time.Time) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if this == nil || this.kcp.state != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this == nil || this.State() != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return errClosedConnection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcpAccess.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcp.receivingWorker.SetReadDeadline(t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.receivingWorker.SetReadDeadline(t) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // SetWriteDeadline implements the Conn SetWriteDeadline method. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) SetWriteDeadline(t time.Time) error { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	if this == nil || this.kcp.state != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this == nil || this.State() != StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		return errClosedConnection 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	defer this.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	this.wd = t 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	return nil 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // kcp update, input loop 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) updateTask() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	for this.kcp.state != StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		current := this.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcpAccess.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcp.Update(current) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for this.State() != StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.flush() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		interval := time.Duration(effectiveConfig.Tti) * time.Millisecond 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		if this.kcp.state == StateTerminating { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if this.State() == StateTerminating { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			interval = time.Second 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		time.Sleep(interval) 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -193,13 +246,6 @@ func (this *Connection) updateTask() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	this.Terminate() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-func (this *Connection) kcpInput(data []byte) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcpAccess.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcp.current = this.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcp.Input(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	this.kcpAccess.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				- 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func (this *Connection) FetchInputFrom(conn net.Conn) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	go func() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		for { 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -211,7 +257,7 @@ func (this *Connection) FetchInputFrom(conn net.Conn) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			payload.Slice(0, nBytes) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			if this.block.Open(payload) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-				this.kcpInput(payload.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				this.Input(payload.Value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 				log.Info("KCP|Connection: Invalid response from ", conn.RemoteAddr()) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			} 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -234,3 +280,151 @@ func (this *Connection) Terminate() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	this.writer.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 } 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) HandleOption(opt SegmentOption) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if (opt & SegmentOptionClose) == SegmentOptionClose { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.OnPeerClosed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) OnPeerClosed() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	state := this.State() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateReadyToClose { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.SetState(StateTerminating) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateActive { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.SetState(StatePeerClosed) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// https://tools.ietf.org/html/rfc6298 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) update_ack(rtt int32) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.Lock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer this.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this.rx_srtt == 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.rx_srtt = uint32(rtt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.rx_rttvar = uint32(rtt) / 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		delta := rtt - int32(this.rx_srtt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if delta < 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			delta = -delta 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.rx_rttvar = (3*this.rx_rttvar + uint32(delta)) / 4 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.rx_srtt = (7*this.rx_srtt + uint32(rtt)) / 8 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if this.rx_srtt < this.interval { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this.rx_srtt = this.interval 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var rto uint32 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this.interval < 4*this.rx_rttvar { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		rto = this.rx_srtt + 4*this.rx_rttvar 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} else { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		rto = this.rx_srtt + this.interval 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if rto > 10000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		rto = 10000 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.rx_rto = rto * 3 / 2 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+// Input when you received a low level packet (eg. UDP packet), call it 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (kcp *Connection) Input(data []byte) int { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	current := kcp.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	kcp.lastIncomingTime = current 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var seg Segment 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg, data = ReadSegment(data) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if seg == nil { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			break 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		switch seg := seg.(type) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		case *DataSegment: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.HandleOption(seg.Opt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.receivingWorker.ProcessSegment(seg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.lastPayloadTime = current 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		case *AckSegment: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.HandleOption(seg.Opt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.sendingWorker.ProcessSegment(current, seg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.lastPayloadTime = current 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		case *CmdOnlySegment: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.HandleOption(seg.Opt) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if seg.Cmd == SegmentCommandTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				if kcp.state == StateActive || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					kcp.state == StateReadyToClose || 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					kcp.state == StatePeerClosed { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					kcp.SetState(StateTerminating) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} else if kcp.state == StateTerminating { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					kcp.SetState(StateTerminated) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.sendingWorker.ProcessReceivingNext(seg.ReceivinNext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			kcp.receivingWorker.ProcessSendingNext(seg.SendingNext) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		default: 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return 0 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) flush() { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	current := this.Elapsed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	state := this.State() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateTerminated { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateActive && current-this.lastPayloadTime >= 30000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateTerminating { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.output.Write(&CmdOnlySegment{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Conv: this.conv, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			Cmd:  SegmentCommandTerminated, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		}) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.output.Flush() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if current-this.stateBeginTime > 8000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			this.SetState(StateTerminated) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		return 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if state == StateReadyToClose && current-this.stateBeginTime > 15000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.SetState(StateTerminating) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// flush acknowledges 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.receivingWorker.Flush(current) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.sendingWorker.Flush(current) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if this.sendingWorker.PingNecessary() || this.receivingWorker.PingNecessary() || current-this.lastPingTime >= 5000 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg := NewCmdOnlySegment() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg.Conv = this.conv 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg.Cmd = SegmentCommandPing 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg.ReceivinNext = this.receivingWorker.nextNumber 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg.SendingNext = this.sendingWorker.firstUnacknowledged 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if state == StateReadyToClose { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			seg.Opt = SegmentOptionClose 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.output.Write(seg) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.lastPingTime = current 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		this.sendingUpdated = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		seg.Release() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// flash remain segments 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.output.Flush() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func (this *Connection) State() State { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	this.RLock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer this.RUnlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	return this.state 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 |