14
14
package vm
15
15
16
16
import (
17
+ "bufio"
17
18
"context"
18
19
"fmt"
19
20
"net"
21
+ "strings"
20
22
"time"
21
23
22
24
"github.com/mdlayher/vsock"
@@ -184,14 +186,6 @@ func vsockConnectMsg(port uint32) string {
184
186
return fmt .Sprintf ("CONNECT %d\n " , port )
185
187
}
186
188
187
- func vsockAckMsg (port uint32 ) string {
188
- // The message a guest-side connection will write after accepting a connection from
189
- // a host dial. This is not part of the official Firecracker vsock spec, but is
190
- // recommended in order to allow the host to verify connections were established
191
- // successfully: https://github.com/firecracker-microvm/firecracker/issues/1272#issuecomment-533004066
192
- return fmt .Sprintf ("IMALIVE %d\n " , port )
193
- }
194
-
195
189
// tryConnect attempts to dial a guest vsock listener at the provided host-side
196
190
// unix socket and provided guest-listener port.
197
191
func tryConnect (logger * logrus.Entry , udsPath string , port uint32 ) (net.Conn , error ) {
@@ -215,10 +209,18 @@ func tryConnect(logger *logrus.Entry, udsPath string, port uint32) (net.Conn, er
215
209
return nil , vsockConnectMsgError {cause : err }
216
210
}
217
211
218
- err = tryConnRead (conn , vsockAckMsg ( port ) , vsockAckMsgTimeout )
212
+ line , err := tryConnReadUntil (conn , '\n' , vsockAckMsgTimeout )
219
213
if err != nil {
220
214
return nil , vsockAckError {cause : err }
221
215
}
216
+
217
+ // The line would be "OK <assigned_hostside_port>\n", but we don't use the hostside port here.
218
+ // https://github.com/firecracker-microvm/firecracker/blob/master/docs/vsock.md#host-initiated-connections
219
+ if ! strings .HasPrefix (line , "OK " ) {
220
+ return nil , vsockAckError {
221
+ cause : errors .Errorf (`expected to read "OK <port>", but instead read %q` , line ),
222
+ }
223
+ }
222
224
return conn , nil
223
225
}
224
226
@@ -240,35 +242,19 @@ func tryAccept(logger *logrus.Entry, listener net.Listener, port uint32) (net.Co
240
242
}
241
243
}()
242
244
243
- err = tryConnWrite (conn , vsockAckMsg (port ), vsockAckMsgTimeout )
244
- if err != nil {
245
- return nil , vsockAckError {cause : err }
246
- }
247
-
248
245
return conn , nil
249
246
}
250
247
251
- // tryConnRead will try to do a read from the provided conn, returning an error if
252
- // the bytes read does not match what was provided or if the read does not complete
248
+ // tryConnReadUntil will try to do a read from the provided conn until the specified
249
+ // end character is encounteed. Returning an error if the read does not complete
253
250
// within the provided timeout. It will reset socket deadlines to none after returning.
254
251
// It's only intended to be used for connect/ack messages, not general purpose reads
255
252
// after the vsock connection is established fully.
256
- func tryConnRead (conn net.Conn , expectedRead string , timeout time.Duration ) error {
253
+ func tryConnReadUntil (conn net.Conn , end byte , timeout time.Duration ) ( string , error ) {
257
254
conn .SetDeadline (time .Now ().Add (timeout ))
258
255
defer conn .SetDeadline (time.Time {})
259
256
260
- actualRead := make ([]byte , len (expectedRead ))
261
- _ , err := conn .Read (actualRead )
262
- if err != nil {
263
- return err
264
- }
265
-
266
- if expectedRead != string (actualRead ) {
267
- return errors .Errorf ("expected to read %q, but instead read %q" ,
268
- expectedRead , string (actualRead ))
269
- }
270
-
271
- return nil
257
+ return bufio .NewReaderSize (conn , 32 ).ReadString (end )
272
258
}
273
259
274
260
// tryConnWrite will try to do a write to the provided conn, returning an error if
0 commit comments