Skip to content

Write doesn't check if connection is closed before returning error #215

Closed
@zhangyoufu

Description

@zhangyoufu

If Conn.Close is called when there's on-going read/write, read/write may return I/O error instead of wrapping a CloseError, and there is no trivial way to examine whether this I/O error is caused by calling Conn.Close.

Of course I can record the code and reason before I call Conn.Close, but there is still a race between my call to Conn.Close and something like WebSocket protocol error. My recorded code and reason may not reflect what actually sent to remote peer in the close frame.

How to reproduce

package main

import (
	"context"
	"log"
	"time"

	"nhooyr.io/websocket"
)

func work(ctx context.Context) (err error) {
	client, _, err := websocket.Dial(ctx, "ws://demos.kaazing.com/echo", nil)
	if err != nil { return }
	log.Print("connected")

	// write something in background
	errCh := make(chan error)
	go func() {
		for {
			err := client.Write(ctx, websocket.MessageText, []byte("hello"))
			if err != nil {
				errCh <- err
				return
			}
			time.Sleep(50 * time.Millisecond)
		}
	}()

	// close after some time
	time.Sleep(3 * time.Second)
	log.Print("closing")
	err = client.Close(websocket.StatusNormalClosure, "bye")
	if err != nil { return err }
	log.Print("closed")

	return <-errCh
}

func main() {
	err := work(context.Background())
	if err != nil && websocket.CloseStatus(err) != websocket.StatusNormalClosure {
		log.Fatal(err)
	}
}

Expected output

2020/03/15 14:14:00 connected
2020/03/15 14:14:03 closing
2020/03/15 14:14:03 closed

Actual output (sometimes, due to race)

2020/03/15 14:13:54 connected
2020/03/15 14:13:57 closing
2020/03/15 14:13:58 failed to close WebSocket: failed to read frame header: read tcp 192.168.1.2:57362->34.209.17.111:80: read: connection reset by peer

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions