55 "fmt"
66 "io"
77 "net"
8+ "sync/atomic"
89 "time"
910
1011 "github.com/gorilla/websocket"
@@ -35,9 +36,10 @@ func NetConn(c *websocket.Conn) net.Conn {
3536}
3637
3738type netConn struct {
38- c * websocket.Conn
39- reader io.Reader
40- readEOFed bool
39+ c * websocket.Conn
40+ reader io.Reader
41+ futureWriteDeadline atomic.Pointer [time.Time ]
42+ readEOFed bool
4143}
4244
4345func (nc * netConn ) Close () (retErr error ) {
@@ -53,6 +55,16 @@ func (nc *netConn) Close() (retErr error) {
5355}
5456
5557func (nc * netConn ) Write (p []byte ) (int , error ) {
58+ old := nc .futureWriteDeadline .Swap (nil )
59+ if old != nil {
60+ // Unsynchronized write deadline field is read in the WriteMessage() call below.
61+ // Hence, it is safe to call SetWriteDeadline() here as it must not be called concurrently
62+ // since that would be a data race.
63+ err := nc .c .SetWriteDeadline (* old )
64+ if err != nil {
65+ return 0 , err
66+ }
67+ }
5668 err := nc .c .WriteMessage (websocket .BinaryMessage , p )
5769 if err != nil {
5870 return 0 , err
@@ -115,15 +127,13 @@ func (nc *netConn) SetDeadline(t time.Time) error {
115127}
116128
117129func (nc * netConn ) SetWriteDeadline (t time.Time ) error {
118- // The method below doesn't set the write deadline on the underlying network connection, but it should.
119- // Hence, we should call the underlying method too to make it possible to abort stuck writes.
120- err := nc .c .SetWriteDeadline (t )
121- if err != nil {
122- return err
123- }
124- return nc .c .UnderlyingConn ().SetWriteDeadline (t )
130+ // This method must be thread safe - e.g. it is safe to call concurrently to abort a connection.
131+ // We cannot use nc.c.SetWriteDeadline() here directly since it is not thread safe - cannot be called
132+ // concurrently with WriteMessage(). So, we are making our own version with similar functionality.
133+ nc .futureWriteDeadline .Store (& t )
134+ return nc .c .NetConn ().SetWriteDeadline (t )
125135}
126136
127137func (nc * netConn ) SetReadDeadline (t time.Time ) error {
128- return nc .c .UnderlyingConn ().SetReadDeadline (t )
138+ return nc .c .NetConn ().SetReadDeadline (t )
129139}
0 commit comments