Skip to content

Commit 47f7ef4

Browse files
committed
fix: concurrent map access for mutexes for in-flight messages
This commit replaces the map with chan to better handle in flight messages while listening to concurrent events. This also solves the concurrency issue where the application crashes due to concurrent map writes. Signed-off-by: Alf-Rune Siqveland <alf.rune@northern.tech>
1 parent 658bbc2 commit 47f7ef4

1 file changed

Lines changed: 20 additions & 20 deletions

File tree

cmd/portforward_tcp.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222
"net"
2323
"os"
2424
"strconv"
25-
"sync"
2625

2726
"github.com/google/uuid"
2827
"github.com/mendersoftware/go-lib-micro/ws"
@@ -37,7 +36,6 @@ type TCPPortForwarder struct {
3736
listen net.Listener
3837
remoteHost string
3938
remotePort uint16
40-
mutexAck map[string]*sync.Mutex
4139
}
4240

4341
func NewTCPPortForwarder(
@@ -55,7 +53,6 @@ func NewTCPPortForwarder(
5553
listen: listen,
5654
remoteHost: remoteHost,
5755
remotePort: remotePort,
58-
mutexAck: map[string]*sync.Mutex{},
5956
}, nil
6057
}
6158

@@ -110,10 +107,8 @@ func (p *TCPPortForwarder) handleRequest(
110107
) {
111108
defer conn.Close()
112109

113-
p.mutexAck[connectionID] = &sync.Mutex{}
114-
defer func() {
115-
delete(p.mutexAck, connectionID)
116-
}()
110+
ackChan := make(chan struct{})
111+
defer func() { close(ackChan) }()
117112

118113
errChan := make(chan error)
119114
dataChan := make(chan []byte)
@@ -195,9 +190,7 @@ func (p *TCPPortForwarder) handleRequest(
195190
}
196191
} else if m.Header.Proto == ws.ProtoTypePortForward &&
197192
m.Header.MsgType == wspf.MessageTypePortForwardAck {
198-
if m, ok := p.mutexAck[connectionID]; ok {
199-
m.Unlock()
200-
}
193+
<-ackChan
201194
}
202195
case <-ctx.Done():
203196
return
@@ -206,17 +199,11 @@ func (p *TCPPortForwarder) handleRequest(
206199
}(connectionID)
207200

208201
// go routine to handle sent messages
209-
for {
202+
for err == nil {
210203
select {
211-
case err := <-errChan:
212-
if err != io.EOF {
213-
fmt.Fprintf(os.Stderr, "error: %v\n", err.Error())
214-
}
215-
return
216-
case data := <-dataChan:
217-
// lock the ack mutex, we don't allow more than one in-flight message
218-
p.mutexAck[connectionID].Lock()
204+
case err = <-errChan:
219205

206+
case data := <-dataChan:
220207
m := &ws.ProtoMsg{
221208
Header: ws.ProtoHdr{
222209
Proto: ws.ProtoTypePortForward,
@@ -229,10 +216,23 @@ func (p *TCPPortForwarder) handleRequest(
229216
Body: data,
230217
}
231218
msgChan <- m
219+
// wait for the ack to be received before processing more data
220+
select {
221+
case ackChan <- struct{}{}:
222+
case <-ctx.Done():
223+
err = ctx.Err()
224+
225+
case err = <-errChan:
226+
227+
}
232228
case <-ctx.Done():
233-
return
229+
err = ctx.Err()
234230
}
235231
}
232+
233+
if err != io.EOF {
234+
fmt.Fprintf(os.Stderr, "error: %v\n", err.Error())
235+
}
236236
}
237237

238238
func (p *TCPPortForwarder) handleRequestConnection(

0 commit comments

Comments
 (0)