Browse Source

lib/upnp: Exit quicker (#6339)

During NAT discovery we block for 10s (NatTimeoutS) before returning.
This is mostly noticeable when Ctrl-C:ing a Syncthing directly after
startup as we wait for those ten seconds before shutting down. This
makes it check the context a little bit more frequently.
Jakob Borg 5 năm trước cách đây
mục cha
commit
71de6fe290
1 tập tin đã thay đổi với 21 bổ sung10 xóa
  1. 21 10
      lib/upnp/upnp.go

+ 21 - 10
lib/upnp/upnp.go

@@ -160,12 +160,6 @@ USER-AGENT: syncthing/1.0
 	}
 	defer socket.Close() // Make sure our socket gets closed
 
-	err = socket.SetDeadline(time.Now().Add(timeout))
-	if err != nil {
-		l.Debugln("UPnP discovery: setting socket deadline:", err)
-		return
-	}
-
 	l.Debugln("Sending search request for device type", deviceType, "on", intf.Name)
 
 	_, err = socket.WriteTo(search, ssdp)
@@ -178,16 +172,33 @@ USER-AGENT: syncthing/1.0
 
 	l.Debugln("Listening for UPnP response for device type", deviceType, "on", intf.Name)
 
-	// Listen for responses until a timeout is reached
+	ctx, cancel := context.WithTimeout(ctx, timeout)
+	defer cancel()
+
+	// Listen for responses until a timeout is reached or the context is
+	// cancelled
+	resp := make([]byte, 65536)
+loop:
 	for {
-		resp := make([]byte, 65536)
+		if err := socket.SetDeadline(time.Now().Add(250 * time.Millisecond)); err != nil {
+			l.Infoln("UPnP socket:", err)
+			break
+		}
+
 		n, _, err := socket.ReadFrom(resp)
 		if err != nil {
-			if e, ok := err.(net.Error); !ok || !e.Timeout() {
-				l.Infoln("UPnP read:", err) //legitimate error, not a timeout.
+			select {
+			case <-ctx.Done():
+				break loop
+			default:
+			}
+			if e, ok := err.(net.Error); ok && e.Timeout() {
+				continue // continue reading
 			}
+			l.Infoln("UPnP read:", err) //legitimate error, not a timeout.
 			break
 		}
+
 		igds, err := parseResponse(ctx, deviceType, resp[:n])
 		if err != nil {
 			switch err.(type) {