MCPcopy Index your code
hub / github.com/coder/coder / handshake

Function handshake

vpn/speaker.go:254–326  ·  view source on GitHub ↗

handshake performs the initial CoderVPN protocol handshake over the given conn

(
	ctx context.Context, conn io.ReadWriteCloser, logger slog.Logger, me, them SpeakerRole,
)

Source from the content-addressed store, hash-verified

252
253// handshake performs the initial CoderVPN protocol handshake over the given conn
254func handshake(
255 ctx context.Context, conn io.ReadWriteCloser, logger slog.Logger, me, them SpeakerRole,
256) error {
257 // read and write simultaneously to avoid deadlocking if the conn is not buffered
258 errCh := make(chan error, 2)
259 go func() {
260 ours := headerString(me, CurrentSupportedVersions)
261 _, err := conn.Write([]byte(ours))
262 logger.Debug(ctx, "wrote out header")
263 if err != nil {
264 err = xerrors.Errorf("write header: %w", err)
265 }
266 errCh <- err
267 }()
268 headerCh := make(chan string, 1)
269 go func() {
270 // we can't use bufio.Scanner here because we need to ensure we don't read beyond the
271 // first newline. So, we'll read one byte at a time. It's inefficient, but the initial
272 // header is only a few characters, so we'll keep this code simple.
273 buf := make([]byte, 256)
274 have := 0
275 for {
276 _, err := conn.Read(buf[have : have+1])
277 if err != nil {
278 errCh <- xerrors.Errorf("read header: %w", err)
279 return
280 }
281 if buf[have] == '\n' {
282 logger.Debug(ctx, "got newline header delimiter")
283 // use have (not have+1) since we don't want the delimiter for verification.
284 headerCh <- string(buf[:have])
285 return
286 }
287 have++
288 if have >= len(buf) {
289 errCh <- xerrors.Errorf("header malformed or too large: %s", string(buf))
290 return
291 }
292 }
293 }()
294
295 writeOK := false
296 theirHeader := ""
297 readOK := false
298 for !(readOK && writeOK) {
299 select {
300 case <-ctx.Done():
301 _ = conn.Close() // ensure our read/write goroutines get a chance to clean up
302 return ctx.Err()
303 case err := <-errCh:
304 if err == nil {
305 // write goroutine sends nil when completing successfully.
306 logger.Debug(ctx, "write ok")
307 writeOK = true
308 continue
309 }
310 _ = conn.Close()
311 return err

Callers 1

newSpeakerFunction · 0.85

Calls 8

headerStringFunction · 0.85
validateHeaderFunction · 0.85
ErrMethod · 0.80
WriteMethod · 0.65
ReadMethod · 0.65
CloseMethod · 0.65
ErrorfMethod · 0.45
DoneMethod · 0.45

Tested by

no test coverage detected