Skip to content

Commit fc3e5bd

Browse files
committed
Fix deadlock or bad data read in CI connection when sending data burst
When reading from a TCP connection, a buffered reader was created for each read. As it turns out, it can happen that the buffer reads more than needed and the next buffer is missing that data. It instead reads the package size from the payload, which results in random behavior (lock or incomplete packages).
1 parent 94f344b commit fc3e5bd

File tree

9 files changed

+51
-33
lines changed

9 files changed

+51
-33
lines changed

cmd/ssl-auto-ref-client/main.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ var clientIdentifier = flag.String("identifier", "test", "The identifier of the
2626
var privateKey *rsa.PrivateKey
2727

2828
type Client struct {
29-
conn net.Conn
30-
token string
29+
conn net.Conn
30+
reader *bufio.Reader
31+
token string
3132
}
3233

3334
func main() {
@@ -56,6 +57,7 @@ func main() {
5657
log.Printf("Connected to game-controller at %v", *refBoxAddr)
5758
c := Client{}
5859
c.conn = conn
60+
c.reader = bufio.NewReaderSize(conn, 1)
5961

6062
c.register()
6163

@@ -103,7 +105,7 @@ func main() {
103105

104106
func (c *Client) register() {
105107
reply := rcon.ControllerToAutoRef{}
106-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
108+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
107109
log.Fatal("Failed receiving controller reply: ", err)
108110
}
109111
if reply.GetControllerReply() == nil || reply.GetControllerReply().NextToken == nil {
@@ -122,7 +124,7 @@ func (c *Client) register() {
122124
}
123125
log.Print("Sent registration, waiting for reply")
124126
reply = rcon.ControllerToAutoRef{}
125-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
127+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
126128
log.Fatal("Failed receiving controller reply: ", err)
127129
}
128130
if reply.GetControllerReply().StatusCode == nil || *reply.GetControllerReply().StatusCode != rcon.ControllerReply_OK {
@@ -209,7 +211,7 @@ func (c *Client) sendRequest(request *rcon.AutoRefToController, doLog bool) {
209211

210212
logIf(doLog, "Waiting for reply...")
211213
reply := rcon.ControllerToAutoRef{}
212-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
214+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
213215
log.Fatal("Failed receiving controller reply: ", err)
214216
}
215217
logIf(doLog, "Received reply: ", reply)

cmd/ssl-ci-test-client/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,10 @@ func send(conn net.Conn) {
123123
}
124124

125125
func receive(conn net.Conn) {
126+
reader := bufio.NewReaderSize(conn, 1)
126127
for {
127128
output := ci.CiOutput{}
128-
if err := sslconn.ReceiveMessage(conn, &output); err != nil {
129+
if err := sslconn.ReceiveMessage(reader, &output); err != nil {
129130
log.Println("Could not receive message: ", err)
130131
}
131132
log.Println("RefereeMsg: ", output.RefereeMsg)

cmd/ssl-remote-control-client/main.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ var team = flag.String("team", "YELLOW", "The team to control, either YELLOW or
2727
var privateKey *rsa.PrivateKey
2828

2929
type Client struct {
30-
conn net.Conn
31-
token string
30+
conn net.Conn
31+
reader *bufio.Reader
32+
token string
3233
}
3334

3435
func main() {
@@ -57,6 +58,7 @@ func main() {
5758
log.Printf("Connected to game-controller at %v", *refBoxAddr)
5859
c := Client{}
5960
c.conn = conn
61+
c.reader = bufio.NewReaderSize(conn, 1)
6062

6163
c.register()
6264

@@ -142,7 +144,7 @@ func main() {
142144

143145
func (c *Client) register() {
144146
reply := rcon.ControllerToRemoteControl{}
145-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
147+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
146148
log.Fatal("Failed receiving controller reply: ", err)
147149
}
148150
if reply.GetControllerReply().NextToken == nil {
@@ -162,7 +164,7 @@ func (c *Client) register() {
162164
}
163165
log.Print("Sent registration, waiting for reply")
164166
reply = rcon.ControllerToRemoteControl{}
165-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
167+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
166168
log.Fatal("Failed receiving controller reply: ", err)
167169
}
168170
if reply.GetControllerReply().StatusCode == nil || *reply.GetControllerReply().StatusCode != rcon.ControllerReply_OK {
@@ -200,7 +202,7 @@ func (c *Client) sendRequest(request *rcon.RemoteControlToController) (accepted
200202

201203
log.Print("Waiting for reply...")
202204
reply := rcon.ControllerToRemoteControl{}
203-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
205+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
204206
log.Fatal("Failed receiving controller reply: ", err)
205207
}
206208
log.Print("Received reply: ", proto.MarshalTextString(&reply))

cmd/ssl-team-client/main.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package main
22

33
import (
4+
"bufio"
45
"crypto/rsa"
56
"flag"
67
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/rcon"
@@ -21,8 +22,9 @@ var teamName = flag.String("teamName", "Test Team", "The name of the team as it
2122
var privateKey *rsa.PrivateKey
2223

2324
type Client struct {
24-
conn net.Conn
25-
token string
25+
conn net.Conn
26+
reader *bufio.Reader
27+
token string
2628
}
2729

2830
func main() {
@@ -51,6 +53,7 @@ func main() {
5153
log.Printf("Connected to game-controller at %v", *refBoxAddr)
5254
c := Client{}
5355
c.conn = conn
56+
c.reader = bufio.NewReaderSize(conn, 1)
5457

5558
c.register()
5659
for !c.sendDesiredKeeper(3) {
@@ -64,7 +67,7 @@ func main() {
6467

6568
func (c *Client) register() {
6669
reply := rcon.ControllerToTeam{}
67-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
70+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
6871
log.Fatal("Failed receiving controller reply: ", err)
6972
}
7073
if reply.GetControllerReply().NextToken == nil {
@@ -83,7 +86,7 @@ func (c *Client) register() {
8386
}
8487
log.Print("Sent registration, waiting for reply")
8588
reply = rcon.ControllerToTeam{}
86-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
89+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
8790
log.Fatal("Failed receiving controller reply: ", err)
8891
}
8992
if reply.GetControllerReply().StatusCode == nil || *reply.GetControllerReply().StatusCode != rcon.ControllerReply_OK {
@@ -121,7 +124,7 @@ func (c *Client) sendRequest(request *rcon.TeamToController) (accepted bool) {
121124

122125
log.Print("Waiting for reply...")
123126
reply := rcon.ControllerToTeam{}
124-
if err := sslconn.ReceiveMessage(c.conn, &reply); err != nil {
127+
if err := sslconn.ReceiveMessage(c.reader, &reply); err != nil {
125128
log.Fatal("Failed receiving controller reply: ", err)
126129
}
127130
log.Print("Received reply: ", proto.MarshalTextString(&reply))

internal/app/ci/ci.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package ci
22

33
import (
4+
"bufio"
45
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/engine"
56
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/sslconn"
67
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
@@ -74,9 +75,10 @@ func (s *Server) serve(conn net.Conn) {
7475
}
7576
}()
7677

78+
reader := bufio.NewReaderSize(conn, 1)
7779
for {
7880
input := CiInput{}
79-
if data, err := sslconn.Receive(conn); err != nil {
81+
if data, err := sslconn.Receive(reader); err != nil {
8082
log.Println("Could not receive message from CI connection: ", err)
8183
return
8284
} else if err := sslconn.Unmarshal(data, &input); err != nil {

internal/app/rcon/server_autoref.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rcon
22

33
import (
4+
"bufio"
45
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/engine"
56
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/sslconn"
67
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
@@ -28,9 +29,9 @@ func NewAutoRefServer(address string, gcEngine *engine.Engine) (s *AutoRefServer
2829
return
2930
}
3031

31-
func (c *AutoRefClient) receiveRegistration(server *AutoRefServer) error {
32+
func (c *AutoRefClient) receiveRegistration(reader *bufio.Reader, server *AutoRefServer) error {
3233
registration := AutoRefRegistration{}
33-
if err := sslconn.ReceiveMessage(c.conn, &registration); err != nil {
34+
if err := sslconn.ReceiveMessage(reader, &registration); err != nil {
3435
return err
3536
}
3637

@@ -66,10 +67,12 @@ func (s *AutoRefServer) handleClientConnection(conn net.Conn) {
6667
}
6768
}()
6869

70+
reader := bufio.NewReaderSize(conn, 1)
71+
6972
client := AutoRefClient{Client: &Client{conn: conn, token: uuid.New()}}
7073
client.reply(client.Ok())
7174

72-
err := client.receiveRegistration(s)
75+
err := client.receiveRegistration(reader, s)
7376
if err != nil {
7477
client.reply(client.Reject(err.Error()))
7578
return
@@ -102,7 +105,7 @@ func (s *AutoRefServer) handleClientConnection(conn net.Conn) {
102105

103106
for {
104107
req := AutoRefToController{}
105-
if err := sslconn.ReceiveMessage(conn, &req); err != nil {
108+
if err := sslconn.ReceiveMessage(reader, &req); err != nil {
106109
if err == io.EOF {
107110
return
108111
}

internal/app/rcon/server_remotecontrol.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rcon
22

33
import (
4+
"bufio"
45
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/engine"
56
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/sslconn"
67
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
@@ -33,9 +34,9 @@ func NewRemoteControlServer(address string, gcEngine *engine.Engine) (s *RemoteC
3334
return
3435
}
3536

36-
func (c *RemoteControlClient) receiveRegistration(server *RemoteControlServer) error {
37+
func (c *RemoteControlClient) receiveRegistration(reader *bufio.Reader, server *RemoteControlServer) error {
3738
registration := RemoteControlRegistration{}
38-
if err := sslconn.ReceiveMessage(c.conn, &registration); err != nil {
39+
if err := sslconn.ReceiveMessage(reader, &registration); err != nil {
3940
return err
4041
}
4142

@@ -73,13 +74,15 @@ func (s *RemoteControlServer) handleClientConnection(conn net.Conn) {
7374
}
7475
}()
7576

77+
reader := bufio.NewReaderSize(conn, 1)
78+
7679
client := RemoteControlClient{
7780
Client: &Client{conn: conn, token: uuid.New()},
7881
gcEngine: s.gcEngine,
7982
}
8083
client.reply(client.Ok())
8184

82-
err := client.receiveRegistration(s)
85+
err := client.receiveRegistration(reader, s)
8386
if err != nil {
8487
client.reply(client.Reject(err.Error()))
8588
return
@@ -96,7 +99,7 @@ func (s *RemoteControlServer) handleClientConnection(conn net.Conn) {
9699

97100
for {
98101
req := RemoteControlToController{}
99-
if err := sslconn.ReceiveMessage(conn, &req); err != nil {
102+
if err := sslconn.ReceiveMessage(reader, &req); err != nil {
100103
if err == io.EOF {
101104
return
102105
}

internal/app/rcon/server_team.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package rcon
22

33
import (
4+
"bufio"
45
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/engine"
56
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/sslconn"
67
"github.com/RoboCup-SSL/ssl-game-controller/internal/app/state"
@@ -30,9 +31,9 @@ func NewTeamServer(address string, gcEngine *engine.Engine) (s *TeamServer) {
3031
return
3132
}
3233

33-
func (c *TeamClient) receiveRegistration(server *TeamServer) error {
34+
func (c *TeamClient) receiveRegistration(reader *bufio.Reader, server *TeamServer) error {
3435
registration := TeamRegistration{}
35-
if err := sslconn.ReceiveMessage(c.conn, &registration); err != nil {
36+
if err := sslconn.ReceiveMessage(reader, &registration); err != nil {
3637
return err
3738
}
3839

@@ -83,10 +84,12 @@ func (s *TeamServer) handleClientConnection(conn net.Conn) {
8384
}
8485
}()
8586

87+
reader := bufio.NewReaderSize(conn, 1)
88+
8689
client := TeamClient{Client: &Client{conn: conn, token: uuid.New()}}
8790
client.reply(client.Ok())
8891

89-
err := client.receiveRegistration(s)
92+
err := client.receiveRegistration(reader, s)
9093
if err != nil {
9194
client.reply(client.Reject(err.Error()))
9295
return
@@ -117,7 +120,7 @@ func (s *TeamServer) handleClientConnection(conn net.Conn) {
117120

118121
for {
119122
req := TeamToController{}
120-
if err := sslconn.ReceiveMessage(conn, &req); err != nil {
123+
if err := sslconn.ReceiveMessage(reader, &req); err != nil {
121124
if err == io.EOF {
122125
return
123126
}

internal/app/sslconn/sslconn.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,8 @@ func SendMessage(conn net.Conn, message proto.Message) error {
3939
}
4040

4141
// Receive reads data and the preceding size from the given connection
42-
func Receive(conn net.Conn) ([]byte, error) {
42+
func Receive(reader *bufio.Reader) ([]byte, error) {
4343

44-
reader := bufio.NewReaderSize(conn, 1)
4544
dataLength, err := readDataLength(reader)
4645
if err != nil {
4746
return nil, err
@@ -65,9 +64,9 @@ func Unmarshal(data []byte, message proto.Message) error {
6564
}
6665

6766
// ReceiveMessage reads a protobuf message and the preceding size from the given connection
68-
func ReceiveMessage(conn net.Conn, message proto.Message) error {
67+
func ReceiveMessage(reader *bufio.Reader, message proto.Message) error {
6968

70-
data, err := Receive(conn)
69+
data, err := Receive(reader)
7170
if err != nil {
7271
return err
7372
}

0 commit comments

Comments
 (0)