1
0
mirror of https://github.com/v2fly/v2ray-core.git synced 2024-11-18 02:16:10 -05:00
v2fly/transport/internet/kcp/connection.go

629 lines
14 KiB
Go
Raw Normal View History

2016-06-17 10:51:41 -04:00
package kcp
import (
"io"
"net"
"sync"
2016-07-05 17:53:46 -04:00
"sync/atomic"
2016-06-17 10:51:41 -04:00
"time"
2016-12-08 10:27:41 -05:00
2018-07-28 21:54:15 -04:00
"v2ray.com/core/common"
2017-04-18 15:23:51 -04:00
"v2ray.com/core/common/buf"
"v2ray.com/core/common/signal"
2018-05-27 08:42:53 -04:00
"v2ray.com/core/common/signal/semaphore"
2016-06-17 10:51:41 -04:00
)
var (
2017-04-08 19:43:25 -04:00
ErrIOTimeout = newError("Read/Write timeout")
ErrClosedListener = newError("Listener closed.")
ErrClosedConnection = newError("Connection closed.")
2016-06-17 10:51:41 -04:00
)
2017-12-03 15:45:58 -05:00
// State of the connection
2016-07-05 17:53:46 -04:00
type State int32
2016-07-05 17:02:52 -04:00
2017-12-03 15:45:58 -05:00
// Is returns true if current State is one of the candidates.
2017-04-14 15:38:07 -04:00
func (s State) Is(states ...State) bool {
2016-07-26 15:34:00 -04:00
for _, state := range states {
2017-04-14 15:38:07 -04:00
if s == state {
2016-07-26 15:34:00 -04:00
return true
}
}
return false
}
2016-07-05 17:02:52 -04:00
const (
2017-12-03 15:45:58 -05:00
StateActive State = 0 // Connection is active
StateReadyToClose State = 1 // Connection is closed locally
StatePeerClosed State = 2 // Connection is closed on remote
StateTerminating State = 3 // Connection is ready to be destroyed locally
StatePeerTerminating State = 4 // Connection is ready to be destroyed on remote
2017-12-14 17:02:10 -05:00
StateTerminated State = 5 // Connection is destroyed.
2016-07-05 17:02:52 -04:00
)
2016-06-17 10:51:41 -04:00
func nowMillisec() int64 {
now := time.Now()
return now.Unix()*1000 + int64(now.Nanosecond()/1000000)
}
2016-08-05 15:03:44 -04:00
type RoundTripInfo struct {
2016-07-05 17:53:46 -04:00
sync.RWMutex
variation uint32
srtt uint32
rto uint32
minRtt uint32
updatedTimestamp uint32
2016-07-05 17:53:46 -04:00
}
2017-12-03 15:45:58 -05:00
func (info *RoundTripInfo) UpdatePeerRTO(rto uint32, current uint32) {
info.Lock()
defer info.Unlock()
2017-12-03 15:45:58 -05:00
if current-info.updatedTimestamp < 3000 {
return
}
2017-12-03 15:45:58 -05:00
info.updatedTimestamp = current
info.rto = rto
}
2017-12-03 15:45:58 -05:00
func (info *RoundTripInfo) Update(rtt uint32, current uint32) {
2016-07-05 17:53:46 -04:00
if rtt > 0x7FFFFFFF {
return
}
2017-12-03 15:45:58 -05:00
info.Lock()
defer info.Unlock()
2016-07-05 17:53:46 -04:00
// https://tools.ietf.org/html/rfc6298
2017-12-03 15:45:58 -05:00
if info.srtt == 0 {
info.srtt = rtt
info.variation = rtt / 2
2016-07-05 17:53:46 -04:00
} else {
2017-12-03 15:45:58 -05:00
delta := rtt - info.srtt
if info.srtt > rtt {
delta = info.srtt - rtt
2016-07-05 17:53:46 -04:00
}
2017-12-03 15:45:58 -05:00
info.variation = (3*info.variation + delta) / 4
info.srtt = (7*info.srtt + rtt) / 8
if info.srtt < info.minRtt {
info.srtt = info.minRtt
2016-07-05 17:53:46 -04:00
}
}
var rto uint32
2017-12-03 15:45:58 -05:00
if info.minRtt < 4*info.variation {
rto = info.srtt + 4*info.variation
2016-07-05 17:53:46 -04:00
} else {
2017-12-03 15:45:58 -05:00
rto = info.srtt + info.variation
2016-07-05 17:53:46 -04:00
}
if rto > 10000 {
rto = 10000
}
2017-12-03 15:45:58 -05:00
info.rto = rto * 5 / 4
info.updatedTimestamp = current
2016-07-05 17:53:46 -04:00
}
2017-12-03 15:45:58 -05:00
func (info *RoundTripInfo) Timeout() uint32 {
info.RLock()
defer info.RUnlock()
2016-07-05 17:53:46 -04:00
2017-12-03 15:45:58 -05:00
return info.rto
2016-07-05 17:53:46 -04:00
}
2017-12-03 15:45:58 -05:00
func (info *RoundTripInfo) SmoothedTime() uint32 {
info.RLock()
defer info.RUnlock()
2016-07-05 17:53:46 -04:00
2017-12-03 15:45:58 -05:00
return info.srtt
2016-07-05 17:53:46 -04:00
}
type Updater struct {
2017-02-17 18:04:25 -05:00
interval int64
2018-07-12 17:38:10 -04:00
shouldContinue func() bool
shouldTerminate func() bool
updateFunc func()
2018-05-27 08:42:53 -04:00
notifier *semaphore.Instance
}
2018-07-12 17:38:10 -04:00
func NewUpdater(interval uint32, shouldContinue func() bool, shouldTerminate func() bool, updateFunc func()) *Updater {
u := &Updater{
2017-02-17 18:04:25 -05:00
interval: int64(time.Duration(interval) * time.Millisecond),
shouldContinue: shouldContinue,
shouldTerminate: shouldTerminate,
updateFunc: updateFunc,
2018-05-27 08:42:53 -04:00
notifier: semaphore.New(1),
}
return u
}
2017-12-14 17:02:10 -05:00
func (u *Updater) WakeUp() {
select {
case <-u.notifier.Wait():
go u.run()
default:
}
}
func (u *Updater) run() {
defer u.notifier.Signal()
if u.shouldTerminate() {
return
}
ticker := time.NewTicker(u.Interval())
for u.shouldContinue() {
u.updateFunc()
<-ticker.C
}
ticker.Stop()
}
2017-02-17 18:04:25 -05:00
func (u *Updater) Interval() time.Duration {
return time.Duration(atomic.LoadInt64(&u.interval))
}
func (u *Updater) SetInterval(d time.Duration) {
atomic.StoreInt64(&u.interval, int64(d))
}
2017-12-03 15:29:27 -05:00
type ConnMetadata struct {
2017-12-14 17:24:40 -05:00
LocalAddr net.Addr
RemoteAddr net.Addr
Conversation uint16
2017-12-03 15:29:27 -05:00
}
2017-04-20 05:00:15 -04:00
2016-06-18 10:34:04 -04:00
// Connection is a KCP connection over UDP.
type Connection struct {
2017-12-14 17:24:40 -05:00
meta ConnMetadata
2017-12-03 15:29:27 -05:00
closer io.Closer
rd time.Time
wd time.Time // write deadline
since int64
dataInput *signal.Notifier
dataOutput *signal.Notifier
Config *Config
2016-07-05 17:02:52 -04:00
state State
stateBeginTime uint32
lastIncomingTime uint32
lastPingTime uint32
2016-07-05 17:53:46 -04:00
mss uint32
2016-08-05 15:03:44 -04:00
roundTrip *RoundTripInfo
2016-07-05 17:02:52 -04:00
receivingWorker *ReceivingWorker
sendingWorker *SendingWorker
2016-12-20 16:53:58 -05:00
output SegmentWriter
dataUpdater *Updater
pingUpdater *Updater
2016-06-17 10:51:41 -04:00
}
2016-06-18 10:34:04 -04:00
// NewConnection create a new KCP connection between local and remote.
2017-12-14 17:24:40 -05:00
func NewConnection(meta ConnMetadata, writer PacketWriter, closer io.Closer, config *Config) *Connection {
2017-12-27 15:39:14 -05:00
newError("#", meta.Conversation, " creating connection to ", meta.RemoteAddr).WriteToLog()
2016-07-05 17:02:52 -04:00
2016-11-27 02:58:31 -05:00
conn := &Connection{
2017-12-03 15:29:27 -05:00
meta: meta,
closer: closer,
since: nowMillisec(),
dataInput: signal.NewNotifier(),
dataOutput: signal.NewNotifier(),
Config: config,
2017-12-03 15:29:27 -05:00
output: NewRetryableWriter(NewSegmentWriter(writer)),
mss: config.GetMTUValue() - uint32(writer.Overhead()) - DataSegmentOverhead,
2016-11-27 02:58:31 -05:00
roundTrip: &RoundTripInfo{
rto: 100,
2016-12-23 06:42:25 -05:00
minRtt: config.GetTTIValue(),
2016-11-27 02:58:31 -05:00
},
}
2016-07-05 17:02:52 -04:00
conn.receivingWorker = NewReceivingWorker(conn)
conn.sendingWorker = NewSendingWorker(conn)
2016-06-17 10:51:41 -04:00
2016-10-11 06:30:53 -04:00
isTerminating := func() bool {
return conn.State().Is(StateTerminating, StateTerminated)
}
isTerminated := func() bool {
return conn.State() == StateTerminated
}
conn.dataUpdater = NewUpdater(
2016-12-23 06:42:25 -05:00
config.GetTTIValue(),
2018-07-12 17:38:10 -04:00
func() bool {
return !isTerminating() && (conn.sendingWorker.UpdateNecessary() || conn.receivingWorker.UpdateNecessary())
},
2016-10-11 06:30:53 -04:00
isTerminating,
conn.updateTask)
conn.pingUpdater = NewUpdater(
2016-10-11 06:24:19 -04:00
5000, // 5 seconds
2018-07-12 17:38:10 -04:00
func() bool { return !isTerminated() },
2016-10-11 06:30:53 -04:00
isTerminated,
conn.updateTask)
2016-10-11 06:24:19 -04:00
conn.pingUpdater.WakeUp()
2016-06-17 10:51:41 -04:00
2016-06-18 10:34:04 -04:00
return conn
2016-06-17 10:51:41 -04:00
}
func (c *Connection) Elapsed() uint32 {
return uint32(nowMillisec() - c.since)
2016-12-08 16:50:12 -05:00
}
2017-11-09 16:33:15 -05:00
// ReadMultiBuffer implements buf.Reader.
func (c *Connection) ReadMultiBuffer() (buf.MultiBuffer, error) {
if c == nil {
return nil, io.EOF
}
for {
if c.State().Is(StateReadyToClose, StateTerminating, StateTerminated) {
return nil, io.EOF
}
mb := c.receivingWorker.ReadMultiBuffer()
if !mb.IsEmpty() {
2018-02-10 20:08:20 -05:00
c.dataUpdater.WakeUp()
return mb, nil
}
if c.State() == StatePeerTerminating {
return nil, io.EOF
}
if err := c.waitForDataInput(); err != nil {
2017-12-14 17:02:10 -05:00
return nil, err
}
2017-12-14 17:02:10 -05:00
}
}
func (c *Connection) waitForDataInput() error {
if c.State() == StatePeerTerminating {
2017-12-14 17:02:10 -05:00
return io.EOF
}
duration := time.Minute
if !c.rd.IsZero() {
duration = time.Until(c.rd)
2017-12-14 17:02:10 -05:00
if duration < 0 {
return ErrIOTimeout
}
}
select {
case <-c.dataInput.Wait():
2017-12-14 17:02:10 -05:00
case <-time.After(duration):
if !c.rd.IsZero() && c.rd.Before(time.Now()) {
2017-12-14 17:02:10 -05:00
return ErrIOTimeout
}
}
2017-12-14 17:02:10 -05:00
return nil
}
2016-06-17 10:51:41 -04:00
// Read implements the Conn Read method.
func (c *Connection) Read(b []byte) (int, error) {
if c == nil {
2016-06-17 10:51:41 -04:00
return 0, io.EOF
}
2016-07-05 17:02:52 -04:00
2016-07-06 11:34:38 -04:00
for {
if c.State().Is(StateReadyToClose, StateTerminating, StateTerminated) {
2016-07-06 11:34:38 -04:00
return 0, io.EOF
}
nBytes := c.receivingWorker.Read(b)
2016-07-06 11:34:38 -04:00
if nBytes > 0 {
2018-02-10 20:08:20 -05:00
c.dataUpdater.WakeUp()
2016-07-06 11:34:38 -04:00
return nBytes, nil
}
2016-07-12 17:54:54 -04:00
if err := c.waitForDataInput(); err != nil {
2017-12-14 17:02:10 -05:00
return 0, err
}
2017-12-14 17:02:10 -05:00
}
}
func (c *Connection) waitForDataOutput() error {
2017-12-14 17:02:10 -05:00
duration := time.Minute
if !c.wd.IsZero() {
duration = time.Until(c.wd)
2017-12-14 17:02:10 -05:00
if duration < 0 {
return ErrIOTimeout
2016-07-06 11:34:38 -04:00
}
2017-12-14 17:02:10 -05:00
}
2016-12-08 16:50:12 -05:00
2017-12-14 17:02:10 -05:00
select {
case <-c.dataOutput.Wait():
2017-12-14 17:02:10 -05:00
case <-time.After(duration):
if !c.wd.IsZero() && c.wd.Before(time.Now()) {
2017-12-14 17:02:10 -05:00
return ErrIOTimeout
2016-07-06 11:34:38 -04:00
}
2016-07-05 17:02:52 -04:00
}
2017-12-14 17:02:10 -05:00
return nil
2016-06-17 10:51:41 -04:00
}
2017-12-05 12:04:34 -05:00
// Write implements io.Writer.
func (c *Connection) Write(b []byte) (int, error) {
2018-07-29 04:47:50 -04:00
// This involves multiple copies of the buffer. But we don't expect this method to be used often.
// Only wrapped connections such as TLS and WebSocket will call into this.
// TODO: improve effeciency.
2018-07-28 21:54:15 -04:00
var mb buf.MultiBuffer
common.Must2(mb.Write(b))
if err := c.WriteMultiBuffer(mb); err != nil {
return 0, err
2016-06-17 10:51:41 -04:00
}
2018-07-28 21:54:15 -04:00
return len(b), nil
2016-06-17 10:51:41 -04:00
}
2017-12-05 12:04:34 -05:00
// WriteMultiBuffer implements buf.Writer.
func (c *Connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
2017-12-03 16:53:00 -05:00
defer mb.Release()
updatePending := false
defer func() {
if updatePending {
c.dataUpdater.WakeUp()
}
}()
2017-12-03 16:53:00 -05:00
for {
for {
if c == nil || c.State() != StateActive {
return io.ErrClosedPipe
}
2017-12-03 16:53:00 -05:00
2018-07-28 21:54:15 -04:00
if !c.sendingWorker.Push(&mb) {
break
}
updatePending = true
2018-07-28 21:38:54 -04:00
if mb.IsEmpty() {
2017-12-03 16:53:00 -05:00
return nil
}
}
if updatePending {
c.dataUpdater.WakeUp()
updatePending = false
}
if err := c.waitForDataOutput(); err != nil {
2017-12-14 17:02:10 -05:00
return err
2017-12-03 16:53:00 -05:00
}
}
}
func (c *Connection) SetState(state State) {
current := c.Elapsed()
atomic.StoreInt32((*int32)(&c.state), int32(state))
atomic.StoreUint32(&c.stateBeginTime, current)
newError("#", c.meta.Conversation, " entering state ", state, " at ", current).AtDebug().WriteToLog()
2016-07-05 17:02:52 -04:00
switch state {
case StateReadyToClose:
c.receivingWorker.CloseRead()
2016-07-05 17:02:52 -04:00
case StatePeerClosed:
c.sendingWorker.CloseWrite()
2016-07-05 17:02:52 -04:00
case StateTerminating:
c.receivingWorker.CloseRead()
c.sendingWorker.CloseWrite()
c.pingUpdater.SetInterval(time.Second)
case StatePeerTerminating:
c.sendingWorker.CloseWrite()
c.pingUpdater.SetInterval(time.Second)
2016-07-05 17:02:52 -04:00
case StateTerminated:
c.receivingWorker.CloseRead()
c.sendingWorker.CloseWrite()
c.pingUpdater.SetInterval(time.Second)
c.dataUpdater.WakeUp()
c.pingUpdater.WakeUp()
go c.Terminate()
2016-07-05 17:02:52 -04:00
}
}
2016-06-17 10:51:41 -04:00
// Close closes the connection.
func (c *Connection) Close() error {
if c == nil {
2016-08-07 09:31:24 -04:00
return ErrClosedConnection
2016-07-05 17:02:52 -04:00
}
c.dataInput.Signal()
c.dataOutput.Signal()
2016-07-06 11:34:38 -04:00
switch c.State() {
case StateReadyToClose, StateTerminating, StateTerminated:
2016-08-07 09:31:24 -04:00
return ErrClosedConnection
case StateActive:
c.SetState(StateReadyToClose)
case StatePeerClosed:
c.SetState(StateTerminating)
case StatePeerTerminating:
c.SetState(StateTerminated)
2016-06-17 17:50:08 -04:00
}
2016-06-18 10:34:04 -04:00
2017-12-27 15:39:14 -05:00
newError("#", c.meta.Conversation, " closing connection to ", c.meta.RemoteAddr).WriteToLog()
2016-06-17 10:51:41 -04:00
return nil
}
// LocalAddr returns the local network address. The Addr returned is shared by all invocations of LocalAddr, so do not modify it.
func (c *Connection) LocalAddr() net.Addr {
if c == nil {
2016-06-17 17:50:08 -04:00
return nil
}
return c.meta.LocalAddr
2016-06-17 10:51:41 -04:00
}
// RemoteAddr returns the remote network address. The Addr returned is shared by all invocations of RemoteAddr, so do not modify it.
func (c *Connection) RemoteAddr() net.Addr {
if c == nil {
2016-06-17 17:50:08 -04:00
return nil
}
return c.meta.RemoteAddr
2016-06-17 17:50:08 -04:00
}
2016-06-17 10:51:41 -04:00
// SetDeadline sets the deadline associated with the listener. A zero time value disables the deadline.
func (c *Connection) SetDeadline(t time.Time) error {
if err := c.SetReadDeadline(t); err != nil {
2016-06-30 08:51:49 -04:00
return err
}
2017-12-27 15:39:14 -05:00
return c.SetWriteDeadline(t)
2016-06-17 10:51:41 -04:00
}
// SetReadDeadline implements the Conn SetReadDeadline method.
func (c *Connection) SetReadDeadline(t time.Time) error {
if c == nil || c.State() != StateActive {
2016-08-07 09:31:24 -04:00
return ErrClosedConnection
2016-06-17 17:50:08 -04:00
}
c.rd = t
2016-06-17 10:51:41 -04:00
return nil
}
// SetWriteDeadline implements the Conn SetWriteDeadline method.
func (c *Connection) SetWriteDeadline(t time.Time) error {
if c == nil || c.State() != StateActive {
2016-08-07 09:31:24 -04:00
return ErrClosedConnection
2016-06-17 17:50:08 -04:00
}
c.wd = t
2016-06-17 10:51:41 -04:00
return nil
}
// kcp update, input loop
func (c *Connection) updateTask() {
c.flush()
2016-06-17 10:51:41 -04:00
}
func (c *Connection) Terminate() {
if c == nil {
2016-06-29 04:34:34 -04:00
return
}
2017-12-27 15:39:14 -05:00
newError("#", c.meta.Conversation, " terminating connection to ", c.RemoteAddr()).WriteToLog()
2016-06-29 04:34:34 -04:00
2016-11-27 15:39:09 -05:00
//v.SetState(StateTerminated)
c.dataInput.Signal()
c.dataOutput.Signal()
2016-12-08 16:50:12 -05:00
c.closer.Close()
c.sendingWorker.Release()
c.receivingWorker.Release()
2016-06-29 04:34:34 -04:00
}
2016-07-05 17:02:52 -04:00
func (c *Connection) HandleOption(opt SegmentOption) {
2016-07-05 17:02:52 -04:00
if (opt & SegmentOptionClose) == SegmentOptionClose {
c.OnPeerClosed()
2016-07-05 17:02:52 -04:00
}
}
func (c *Connection) OnPeerClosed() {
switch c.State() {
case StateReadyToClose:
c.SetState(StateTerminating)
case StateActive:
c.SetState(StatePeerClosed)
2016-07-05 17:02:52 -04:00
}
}
// Input when you received a low level packet (eg. UDP packet), call it
func (c *Connection) Input(segments []Segment) {
current := c.Elapsed()
atomic.StoreUint32(&c.lastIncomingTime, current)
2016-07-05 17:02:52 -04:00
2016-12-08 10:27:41 -05:00
for _, seg := range segments {
if seg.Conversation() != c.meta.Conversation {
2016-12-08 16:50:12 -05:00
break
2016-11-27 02:58:31 -05:00
}
2016-07-05 17:02:52 -04:00
switch seg := seg.(type) {
case *DataSegment:
c.HandleOption(seg.Option)
c.receivingWorker.ProcessSegment(seg)
if c.receivingWorker.IsDataAvailable() {
c.dataInput.Signal()
2016-12-08 16:50:12 -05:00
}
c.dataUpdater.WakeUp()
2016-07-05 17:02:52 -04:00
case *AckSegment:
c.HandleOption(seg.Option)
c.sendingWorker.ProcessSegment(current, seg, c.roundTrip.Timeout())
c.dataOutput.Signal()
c.dataUpdater.WakeUp()
2016-07-05 17:02:52 -04:00
case *CmdOnlySegment:
c.HandleOption(seg.Option)
2016-12-08 10:27:41 -05:00
if seg.Command() == CommandTerminate {
switch c.State() {
case StateActive, StatePeerClosed:
c.SetState(StatePeerTerminating)
case StateReadyToClose:
c.SetState(StateTerminating)
case StateTerminating:
c.SetState(StateTerminated)
2016-07-05 17:02:52 -04:00
}
}
2016-12-26 02:22:25 -05:00
if seg.Option == SegmentOptionClose || seg.Command() == CommandTerminate {
c.dataInput.Signal()
c.dataOutput.Signal()
2016-12-26 02:22:25 -05:00
}
2018-01-17 11:36:14 -05:00
c.sendingWorker.ProcessReceivingNext(seg.ReceivingNext)
c.receivingWorker.ProcessSendingNext(seg.SendingNext)
c.roundTrip.UpdatePeerRTO(seg.PeerRTO, current)
2016-07-13 17:15:40 -04:00
seg.Release()
2016-07-05 17:02:52 -04:00
default:
}
}
}
func (c *Connection) flush() {
current := c.Elapsed()
2016-07-05 17:02:52 -04:00
if c.State() == StateTerminated {
2016-07-05 17:02:52 -04:00
return
}
if c.State() == StateActive && current-atomic.LoadUint32(&c.lastIncomingTime) >= 30000 {
c.Close()
2016-07-05 17:02:52 -04:00
}
if c.State() == StateReadyToClose && c.sendingWorker.IsEmpty() {
c.SetState(StateTerminating)
2016-07-12 17:54:54 -04:00
}
2016-07-05 17:02:52 -04:00
if c.State() == StateTerminating {
newError("#", c.meta.Conversation, " sending terminating cmd.").AtDebug().WriteToLog()
c.Ping(current, CommandTerminate)
2016-07-05 17:02:52 -04:00
if current-atomic.LoadUint32(&c.stateBeginTime) > 8000 {
c.SetState(StateTerminated)
2016-07-05 17:02:52 -04:00
}
return
}
if c.State() == StatePeerTerminating && current-atomic.LoadUint32(&c.stateBeginTime) > 4000 {
c.SetState(StateTerminating)
}
2016-07-05 17:02:52 -04:00
if c.State() == StateReadyToClose && current-atomic.LoadUint32(&c.stateBeginTime) > 15000 {
c.SetState(StateTerminating)
2016-07-05 17:02:52 -04:00
}
// flush acknowledges
c.receivingWorker.Flush(current)
c.sendingWorker.Flush(current)
2016-07-05 17:02:52 -04:00
if current-atomic.LoadUint32(&c.lastPingTime) >= 3000 {
c.Ping(current, CommandPing)
2016-07-05 17:02:52 -04:00
}
}
func (c *Connection) State() State {
return State(atomic.LoadInt32((*int32)(&c.state)))
2016-07-05 17:02:52 -04:00
}
2016-10-11 06:24:19 -04:00
func (c *Connection) Ping(current uint32, cmd Command) {
2016-10-11 06:24:19 -04:00
seg := NewCmdOnlySegment()
seg.Conv = c.meta.Conversation
2016-12-08 10:27:41 -05:00
seg.Cmd = cmd
2018-01-17 11:36:14 -05:00
seg.ReceivingNext = c.receivingWorker.NextNumber()
seg.SendingNext = c.sendingWorker.FirstUnacknowledged()
seg.PeerRTO = c.roundTrip.Timeout()
if c.State() == StateReadyToClose {
2016-10-11 06:24:19 -04:00
seg.Option = SegmentOptionClose
}
c.output.Write(seg)
atomic.StoreUint32(&c.lastPingTime, current)
2016-10-11 06:24:19 -04:00
seg.Release()
}