@@ -13,7 +13,6 @@ import (
1313// PingManagerConfig is a structure containing various parameters that govern
1414// how the PingManager behaves.
1515type PingManagerConfig struct {
16-
1716 // NewPingPayload is a closure that returns the payload to be packaged
1817 // in the Ping message.
1918 NewPingPayload func () []byte
@@ -99,102 +98,102 @@ func NewPingManager(cfg *PingManagerConfig) *PingManager {
9998func (m * PingManager ) Start () error {
10099 var err error
101100 m .started .Do (func () {
102- err = m .start ()
101+ m .pingTicker = time .NewTicker (m .cfg .IntervalDuration )
102+ m .pingTimeout = time .NewTimer (0 )
103+
104+ m .wg .Add (1 )
105+ go m .pingHandler ()
103106 })
104107
105108 return err
106109}
107110
108- func ( m * PingManager ) start () error {
109- m . pingTicker = time . NewTicker ( m . cfg . IntervalDuration )
110-
111- m . pingTimeout = time . NewTimer ( 0 )
111+ // pingHandler is the main goroutine responsible for enforcing the ping/pong
112+ // protocol.
113+ func ( m * PingManager ) pingHandler () {
114+ defer m . wg . Done ( )
112115 defer m .pingTimeout .Stop ()
113116
114117 // Ensure that the pingTimeout channel is empty.
115118 if ! m .pingTimeout .Stop () {
116119 <- m .pingTimeout .C
117120 }
118121
119- m .wg .Add (1 )
120- go func () {
121- defer m .wg .Done ()
122- for {
123- select {
124- case <- m .pingTicker .C :
125- // If this occurs it means that the new ping
126- // cycle has begun while there is still an
127- // outstanding ping awaiting a pong response.
128- // This should never occur, but if it does, it
129- // implies a timeout.
130- if m .outstandingPongSize >= 0 {
131- e := errors .New ("impossible: new ping" +
132- "in unclean state" ,
133- )
134- m .cfg .OnPongFailure (e )
135-
136- return
137- }
138-
139- pongSize := m .cfg .NewPongSize ()
140- ping := & lnwire.Ping {
141- NumPongBytes : pongSize ,
142- PaddingBytes : m .cfg .NewPingPayload (),
143- }
144-
145- // Set up our bookkeeping for the new Ping.
146- if err := m .setPingState (pongSize ); err != nil {
147- m .cfg .OnPongFailure (err )
148-
149- return
150- }
151-
152- m .cfg .SendPing (ping )
153-
154- case <- m .pingTimeout .C :
155- m .resetPingState ()
156-
157- e := errors .New ("timeout while waiting for " +
158- "pong response" ,
122+ for {
123+ select {
124+ case <- m .pingTicker .C :
125+ // If this occurs it means that the new ping cycle has
126+ // begun while there is still an outstanding ping
127+ // awaiting a pong response. This should never occur,
128+ // but if it does, it implies a timeout.
129+ if m .outstandingPongSize >= 0 {
130+ e := errors .New ("impossible: new ping" +
131+ "in unclean state" ,
159132 )
160133 m .cfg .OnPongFailure (e )
161134
162135 return
136+ }
137+
138+ pongSize := m .cfg .NewPongSize ()
139+ ping := & lnwire.Ping {
140+ NumPongBytes : pongSize ,
141+ PaddingBytes : m .cfg .NewPingPayload (),
142+ }
143+
144+ // Set up our bookkeeping for the new Ping.
145+ if err := m .setPingState (pongSize ); err != nil {
146+ m .cfg .OnPongFailure (err )
163147
164- case pong := <- m .pongChan :
165- pongSize := int32 (len (pong .PongBytes ))
166-
167- // Save off values we are about to override
168- // when we call resetPingState.
169- expected := m .outstandingPongSize
170- lastPing := m .pingLastSend
171-
172- m .resetPingState ()
173-
174- // If the pong we receive doesn't match the
175- // ping we sent out, then we fail out.
176- if pongSize != expected {
177- e := errors .New ("pong response does " +
178- "not match expected size" ,
179- )
180- m .cfg .OnPongFailure (e )
181-
182- return
183- }
184-
185- // Compute RTT of ping and save that for future
186- // querying.
187- if lastPing != nil {
188- rtt := time .Since (* lastPing )
189- m .pingTime .Store (& rtt )
190- }
191- case <- m .quit :
192148 return
193149 }
194- }
195- }()
196150
197- return nil
151+ m .cfg .SendPing (ping )
152+
153+ case <- m .pingTimeout .C :
154+ m .resetPingState ()
155+
156+ e := errors .New ("timeout while waiting for " +
157+ "pong response" ,
158+ )
159+
160+ m .cfg .OnPongFailure (e )
161+
162+ return
163+
164+ case pong := <- m .pongChan :
165+ pongSize := int32 (len (pong .PongBytes ))
166+
167+ // Save off values we are about to override when we
168+ // call resetPingState.
169+ expected := m .outstandingPongSize
170+ lastPing := m .pingLastSend
171+
172+ m .resetPingState ()
173+
174+ // If the pong we receive doesn't match the ping we
175+ // sent out, then we fail out.
176+ if pongSize != expected {
177+ e := errors .New ("pong response does " +
178+ "not match expected size" ,
179+ )
180+
181+ m .cfg .OnPongFailure (e )
182+
183+ return
184+ }
185+
186+ // Compute RTT of ping and save that for future
187+ // querying.
188+ if lastPing != nil {
189+ rtt := time .Since (* lastPing )
190+ m .pingTime .Store (& rtt )
191+ }
192+
193+ case <- m .quit :
194+ return
195+ }
196+ }
198197}
199198
200199// Stop interrupts the goroutines that the PingManager owns. Can only be called
0 commit comments