|  | @@ -233,10 +233,11 @@ func NewConnection(conv uint16, writerCloser io.WriteCloser, local *net.UDPAddr,
 | 
											
												
													
														|  |  		},
 |  |  		},
 | 
											
												
													
														|  |  		conn.updateTask)
 |  |  		conn.updateTask)
 | 
											
												
													
														|  |  	conn.pingUpdater = NewUpdater(
 |  |  	conn.pingUpdater = NewUpdater(
 | 
											
												
													
														|  | -		3000, // 3 seconds
 |  | 
 | 
											
												
													
														|  | 
 |  | +		5000, // 5 seconds
 | 
											
												
													
														|  |  		func() bool { return conn.State() != StateTerminated },
 |  |  		func() bool { return conn.State() != StateTerminated },
 | 
											
												
													
														|  |  		func() bool { return conn.State() == StateTerminated },
 |  |  		func() bool { return conn.State() == StateTerminated },
 | 
											
												
													
														|  |  		conn.updateTask)
 |  |  		conn.updateTask)
 | 
											
												
													
														|  | 
 |  | +	conn.pingUpdater.WakeUp()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	return conn
 |  |  	return conn
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
										
											
												
													
														|  | @@ -333,24 +334,22 @@ func (this *Connection) SetState(state State) {
 | 
											
												
													
														|  |  	switch state {
 |  |  	switch state {
 | 
											
												
													
														|  |  	case StateReadyToClose:
 |  |  	case StateReadyToClose:
 | 
											
												
													
														|  |  		this.receivingWorker.CloseRead()
 |  |  		this.receivingWorker.CloseRead()
 | 
											
												
													
														|  | -		this.dataUpdater.WakeUp()
 |  | 
 | 
											
												
													
														|  |  	case StatePeerClosed:
 |  |  	case StatePeerClosed:
 | 
											
												
													
														|  |  		this.sendingWorker.CloseWrite()
 |  |  		this.sendingWorker.CloseWrite()
 | 
											
												
													
														|  | -		this.dataUpdater.WakeUp()
 |  | 
 | 
											
												
													
														|  |  	case StateTerminating:
 |  |  	case StateTerminating:
 | 
											
												
													
														|  |  		this.receivingWorker.CloseRead()
 |  |  		this.receivingWorker.CloseRead()
 | 
											
												
													
														|  |  		this.sendingWorker.CloseWrite()
 |  |  		this.sendingWorker.CloseWrite()
 | 
											
												
													
														|  | -		this.dataUpdater.interval = time.Second
 |  | 
 | 
											
												
													
														|  | -		this.dataUpdater.WakeUp()
 |  | 
 | 
											
												
													
														|  | 
 |  | +		this.pingUpdater.interval = time.Second
 | 
											
												
													
														|  |  	case StatePeerTerminating:
 |  |  	case StatePeerTerminating:
 | 
											
												
													
														|  |  		this.sendingWorker.CloseWrite()
 |  |  		this.sendingWorker.CloseWrite()
 | 
											
												
													
														|  | -		this.dataUpdater.WakeUp()
 |  | 
 | 
											
												
													
														|  | 
 |  | +		this.pingUpdater.interval = time.Second
 | 
											
												
													
														|  |  	case StateTerminated:
 |  |  	case StateTerminated:
 | 
											
												
													
														|  |  		this.receivingWorker.CloseRead()
 |  |  		this.receivingWorker.CloseRead()
 | 
											
												
													
														|  |  		this.sendingWorker.CloseWrite()
 |  |  		this.sendingWorker.CloseWrite()
 | 
											
												
													
														|  | -		this.dataUpdater.interval = time.Second
 |  | 
 | 
											
												
													
														|  | 
 |  | +		this.pingUpdater.interval = time.Second
 | 
											
												
													
														|  |  		this.dataUpdater.WakeUp()
 |  |  		this.dataUpdater.WakeUp()
 | 
											
												
													
														|  | -		this.Terminate()
 |  | 
 | 
											
												
													
														|  | 
 |  | +		this.pingUpdater.WakeUp()
 | 
											
												
													
														|  | 
 |  | +		go this.Terminate()
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -488,7 +487,6 @@ func (this *Connection) OnPeerClosed() {
 | 
											
												
													
														|  |  func (this *Connection) Input(data []byte) int {
 |  |  func (this *Connection) Input(data []byte) int {
 | 
											
												
													
														|  |  	current := this.Elapsed()
 |  |  	current := this.Elapsed()
 | 
											
												
													
														|  |  	atomic.StoreUint32(&this.lastIncomingTime, current)
 |  |  	atomic.StoreUint32(&this.lastIncomingTime, current)
 | 
											
												
													
														|  | -	this.dataUpdater.WakeUp()
 |  | 
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	var seg Segment
 |  |  	var seg Segment
 | 
											
												
													
														|  |  	for {
 |  |  	for {
 | 
											
										
											
												
													
														|  | @@ -502,10 +500,12 @@ func (this *Connection) Input(data []byte) int {
 | 
											
												
													
														|  |  			this.HandleOption(seg.Option)
 |  |  			this.HandleOption(seg.Option)
 | 
											
												
													
														|  |  			this.receivingWorker.ProcessSegment(seg)
 |  |  			this.receivingWorker.ProcessSegment(seg)
 | 
											
												
													
														|  |  			this.dataInputCond.Signal()
 |  |  			this.dataInputCond.Signal()
 | 
											
												
													
														|  | 
 |  | +			this.dataUpdater.WakeUp()
 | 
											
												
													
														|  |  		case *AckSegment:
 |  |  		case *AckSegment:
 | 
											
												
													
														|  |  			this.HandleOption(seg.Option)
 |  |  			this.HandleOption(seg.Option)
 | 
											
												
													
														|  |  			this.sendingWorker.ProcessSegment(current, seg)
 |  |  			this.sendingWorker.ProcessSegment(current, seg)
 | 
											
												
													
														|  |  			this.dataOutputCond.Signal()
 |  |  			this.dataOutputCond.Signal()
 | 
											
												
													
														|  | 
 |  | +			this.dataUpdater.WakeUp()
 | 
											
												
													
														|  |  		case *CmdOnlySegment:
 |  |  		case *CmdOnlySegment:
 | 
											
												
													
														|  |  			this.HandleOption(seg.Option)
 |  |  			this.HandleOption(seg.Option)
 | 
											
												
													
														|  |  			if seg.Command == CommandTerminate {
 |  |  			if seg.Command == CommandTerminate {
 | 
											
										
											
												
													
														|  | @@ -545,12 +545,7 @@ func (this *Connection) flush() {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	if this.State() == StateTerminating {
 |  |  	if this.State() == StateTerminating {
 | 
											
												
													
														|  |  		log.Debug("KCP|Connection: #", this.conv, " sending terminating cmd.")
 |  |  		log.Debug("KCP|Connection: #", this.conv, " sending terminating cmd.")
 | 
											
												
													
														|  | -		seg := NewCmdOnlySegment()
 |  | 
 | 
											
												
													
														|  | -		defer seg.Release()
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -		seg.Conv = this.conv
 |  | 
 | 
											
												
													
														|  | -		seg.Command = CommandTerminate
 |  | 
 | 
											
												
													
														|  | -		this.output.Write(seg)
 |  | 
 | 
											
												
													
														|  | 
 |  | +		this.Ping(current, CommandTerminate)
 | 
											
												
													
														|  |  		this.output.Flush()
 |  |  		this.output.Flush()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  		if current-atomic.LoadUint32(&this.stateBeginTime) > 8000 {
 |  |  		if current-atomic.LoadUint32(&this.stateBeginTime) > 8000 {
 | 
											
										
											
												
													
														|  | @@ -570,19 +565,8 @@ func (this *Connection) flush() {
 | 
											
												
													
														|  |  	this.receivingWorker.Flush(current)
 |  |  	this.receivingWorker.Flush(current)
 | 
											
												
													
														|  |  	this.sendingWorker.Flush(current)
 |  |  	this.sendingWorker.Flush(current)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -	if current-atomic.LoadUint32(&this.lastPingTime) >= 3000 {
 |  | 
 | 
											
												
													
														|  | -		seg := NewCmdOnlySegment()
 |  | 
 | 
											
												
													
														|  | -		seg.Conv = this.conv
 |  | 
 | 
											
												
													
														|  | -		seg.Command = CommandPing
 |  | 
 | 
											
												
													
														|  | -		seg.ReceivinNext = this.receivingWorker.nextNumber
 |  | 
 | 
											
												
													
														|  | -		seg.SendingNext = this.sendingWorker.firstUnacknowledged
 |  | 
 | 
											
												
													
														|  | -		seg.PeerRTO = this.roundTrip.Timeout()
 |  | 
 | 
											
												
													
														|  | -		if this.State() == StateReadyToClose {
 |  | 
 | 
											
												
													
														|  | -			seg.Option = SegmentOptionClose
 |  | 
 | 
											
												
													
														|  | -		}
 |  | 
 | 
											
												
													
														|  | -		this.output.Write(seg)
 |  | 
 | 
											
												
													
														|  | -		this.lastPingTime = current
 |  | 
 | 
											
												
													
														|  | -		seg.Release()
 |  | 
 | 
											
												
													
														|  | 
 |  | +	if current-atomic.LoadUint32(&this.lastPingTime) >= 1000 {
 | 
											
												
													
														|  | 
 |  | +		this.Ping(current, CommandPing)
 | 
											
												
													
														|  |  	}
 |  |  	}
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  	// flash remain segments
 |  |  	// flash remain segments
 | 
											
										
											
												
													
														|  | @@ -592,3 +576,18 @@ func (this *Connection) flush() {
 | 
											
												
													
														|  |  func (this *Connection) State() State {
 |  |  func (this *Connection) State() State {
 | 
											
												
													
														|  |  	return State(atomic.LoadInt32((*int32)(&this.state)))
 |  |  	return State(atomic.LoadInt32((*int32)(&this.state)))
 | 
											
												
													
														|  |  }
 |  |  }
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +func (this *Connection) Ping(current uint32, cmd Command) {
 | 
											
												
													
														|  | 
 |  | +	seg := NewCmdOnlySegment()
 | 
											
												
													
														|  | 
 |  | +	seg.Conv = this.conv
 | 
											
												
													
														|  | 
 |  | +	seg.Command = cmd
 | 
											
												
													
														|  | 
 |  | +	seg.ReceivinNext = this.receivingWorker.nextNumber
 | 
											
												
													
														|  | 
 |  | +	seg.SendingNext = this.sendingWorker.firstUnacknowledged
 | 
											
												
													
														|  | 
 |  | +	seg.PeerRTO = this.roundTrip.Timeout()
 | 
											
												
													
														|  | 
 |  | +	if this.State() == StateReadyToClose {
 | 
											
												
													
														|  | 
 |  | +		seg.Option = SegmentOptionClose
 | 
											
												
													
														|  | 
 |  | +	}
 | 
											
												
													
														|  | 
 |  | +	this.output.Write(seg)
 | 
											
												
													
														|  | 
 |  | +	atomic.StoreUint32(&this.lastPingTime, current)
 | 
											
												
													
														|  | 
 |  | +	seg.Release()
 | 
											
												
													
														|  | 
 |  | +}
 |