Browse Source

Patch qguic-go

- Prevent deadlock on shutdown

- Don't shutdown on temporary net error
Rod Hynes 6 years ago
parent
commit
5d27fb5254
1 changed files with 31 additions and 3 deletions
  1. 31 3
      psiphon/common/quic/gquic-go/packet_handler_map.go

+ 31 - 3
psiphon/common/quic/gquic-go/packet_handler_map.go

@@ -111,10 +111,32 @@ func (h *packetHandlerMap) close(e error) error {
 		}
 	}
 
+	// [Psiphon]
+	// Call h.server.setCloseError(e) outside of mutex to prevent deadlock
+	//
+	//    sync.(*RWMutex).Lock
+	//    [...]/lucas-clemente/quic-go.(*packetHandlerMap).CloseServer
+	//    [...]/lucas-clemente/quic-go.(*server).closeWithMutex
+	//    [...]/lucas-clemente/quic-go.(*server).closeWithError
+	//    [...]/lucas-clemente/quic-go.(*packetHandlerMap).close
+	//    [...]/lucas-clemente/quic-go.(*packetHandlerMap).listen
+	//
+	//    packetHandlerMap.CloseServer is attempting to lock the same mutex that
+	//    is already locked in packetHandlerMap.close, which deadlocks. As
+	//    packetHandlerMap and its mutex are used by all client sessions, this
+	//    effectively hangs the entire server.
+
+	var server unknownPacketHandler
 	if h.server != nil {
-		h.server.closeWithError(e)
+		server = h.server
 	}
+
 	h.mutex.Unlock()
+
+	if server != nil {
+		server.closeWithError(e)
+	}
+
 	wg.Wait()
 	return nil
 }
@@ -127,8 +149,14 @@ func (h *packetHandlerMap) listen() {
 		// If it does, we only read a truncated packet, which will then end up undecryptable
 		n, addr, err := h.conn.ReadFrom(data)
 		if err != nil {
-			h.close(err)
-			return
+
+			// [Psiphon]
+			// Do not unconditionally shutdown
+			if netErr, ok := err.(net.Error); !ok || !netErr.Temporary() {
+				h.close(err)
+				return
+			}
+
 		}
 		data = data[:n]