Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion contract/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ type Plugin struct {
conn net.Conn // the underlying unix sock file connection
pending map[uint64]chan isFSMToPlugin_Payload // the outstanding requests from the contract
requestContract map[uint64]*Contract // maps request IDs to their contract context for concurrent operations
l sync.Mutex // thread safety
l sync.Mutex // thread safety for pending/requestContract maps
writeMu sync.Mutex // thread safety for concurrent writes to the socket connection
config Config // general app config
}

Expand Down Expand Up @@ -266,6 +267,12 @@ func (p *Plugin) sendLengthPrefixed(bz []byte) *PluginError {
// create the length prefix (4 bytes, big endian)
lengthPrefix := make([]byte, 4)
binary.BigEndian.PutUint32(lengthPrefix, uint32(len(bz)))
// serialize writes: ListenForInbound() spawns a goroutine per inbound message, and each
// can independently write to the shared connection (either as a direct FSM response or
// via a nested StateRead/StateWrite call). Without this lock, concurrent writers can
// interleave mid-message and corrupt the length-prefixed framing on the wire.
p.writeMu.Lock()
defer p.writeMu.Unlock()
// write the message (length prefixed)
if _, er := p.conn.Write(append(lengthPrefix, bz...)); er != nil {
return ErrFailedPluginWrite(er)
Expand Down