Thank you, that was what I was looking for. I had forgotten about deadlines, and I didn't realise that you could change a deadline even while a read was in progress.
In case it's helpful to anyone, here's a proof-of-concept. It doesn't work on play.golang.org because of the network communication. package main import ( "context" "fmt" "io" "net" "os" "time" ) type ConnWithContext struct { net.Conn Ctx context.Context } func NewConnWithContext(ctx context.Context, conn net.Conn) *ConnWithContext { go func() { <-ctx.Done() conn.SetDeadline(time.Now()) }() return &ConnWithContext{ Conn: conn, Ctx: ctx, } } func (c *ConnWithContext) Read(b []byte) (n int, err error) { return c.Conn.Read(b) } func main() { ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() conn, err := net.Dial("tcp", "smtp.gmail.com:25") if err != nil { fmt.Println(err) return } cwc := NewConnWithContext(ctx, conn) n, err := io.Copy(os.Stdout, cwc) fmt.Println(n, err) cwc.Close() } -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/c7d926b1-7b05-47a0-9eb3-f0e1533b81a6o%40googlegroups.com.