| 
														
															@@ -5,11 +5,11 @@ package client 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 import ( 
														 | 
														
														 | 
														
															 import ( 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"context" 
														 | 
														
														 | 
														
															 	"context" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"crypto/tls" 
														 | 
														
														 | 
														
															 	"crypto/tls" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+	"errors" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"fmt" 
														 | 
														
														 | 
														
															 	"fmt" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"net" 
														 | 
														
														 | 
														
															 	"net" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"net/url" 
														 | 
														
														 | 
														
															 	"net/url" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"strconv" 
														 | 
														
														 | 
														
															 	"strconv" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-	"strings" 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"time" 
														 | 
														
														 | 
														
															 	"time" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"github.com/syncthing/syncthing/lib/dialer" 
														 | 
														
														 | 
														
															 	"github.com/syncthing/syncthing/lib/dialer" 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -17,6 +17,15 @@ import ( 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	"github.com/syncthing/syncthing/lib/relay/protocol" 
														 | 
														
														 | 
														
															 	"github.com/syncthing/syncthing/lib/relay/protocol" 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 ) 
														 | 
														
														 | 
														
															 ) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+type incorrectResponseCodeErr struct { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+	code int32 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+	msg  string 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+func (e incorrectResponseCodeErr) Error() string { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+	return fmt.Sprintf("incorrect response code %d: %s", e.code, e.msg) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 func GetInvitationFromRelay(ctx context.Context, uri *url.URL, id syncthingprotocol.DeviceID, certs []tls.Certificate, timeout time.Duration) (protocol.SessionInvitation, error) { 
														 | 
														
														 | 
														
															 func GetInvitationFromRelay(ctx context.Context, uri *url.URL, id syncthingprotocol.DeviceID, certs []tls.Certificate, timeout time.Duration) (protocol.SessionInvitation, error) { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	if uri.Scheme != "relay" { 
														 | 
														
														 | 
														
															 	if uri.Scheme != "relay" { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		return protocol.SessionInvitation{}, fmt.Errorf("unsupported relay scheme: %v", uri.Scheme) 
														 | 
														
														 | 
														
															 		return protocol.SessionInvitation{}, fmt.Errorf("unsupported relay scheme: %v", uri.Scheme) 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -53,7 +62,7 @@ func GetInvitationFromRelay(ctx context.Context, uri *url.URL, id syncthingproto 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	switch msg := message.(type) { 
														 | 
														
														 | 
														
															 	switch msg := message.(type) { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	case protocol.Response: 
														 | 
														
														 | 
														
															 	case protocol.Response: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-		return protocol.SessionInvitation{}, fmt.Errorf("incorrect response code %d: %s", msg.Code, msg.Message) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+		return protocol.SessionInvitation{}, incorrectResponseCodeErr{msg.Code, msg.Message} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	case protocol.SessionInvitation: 
														 | 
														
														 | 
														
															 	case protocol.SessionInvitation: 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		l.Debugln("Received invitation", msg, "via", conn.LocalAddr()) 
														 | 
														
														 | 
														
															 		l.Debugln("Received invitation", msg, "via", conn.LocalAddr()) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		ip := net.IP(msg.Address) 
														 | 
														
														 | 
														
															 		ip := net.IP(msg.Address) 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -104,13 +113,13 @@ func JoinSession(ctx context.Context, invitation protocol.SessionInvitation) (ne 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	} 
														 | 
														
														 | 
														
															 	} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 } 
														 | 
														
														 | 
														
															 } 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															-func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep, timeout time.Duration, times int) bool { 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep, timeout time.Duration, times int) error { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	id := syncthingprotocol.NewDeviceID(certs[0].Certificate[0]) 
														 | 
														
														 | 
														
															 	id := syncthingprotocol.NewDeviceID(certs[0].Certificate[0]) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	invs := make(chan protocol.SessionInvitation, 1) 
														 | 
														
														 | 
														
															 	invs := make(chan protocol.SessionInvitation, 1) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	c, err := NewClient(uri, certs, invs, timeout) 
														 | 
														
														 | 
														
															 	c, err := NewClient(uri, certs, invs, timeout) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	if err != nil { 
														 | 
														
														 | 
														
															 	if err != nil { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		close(invs) 
														 | 
														
														 | 
														
															 		close(invs) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-		return false 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+		return fmt.Errorf("creating client: %w", err) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	} 
														 | 
														
														 | 
														
															 	} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	go c.Serve() 
														 | 
														
														 | 
														
															 	go c.Serve() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	defer func() { 
														 | 
														
														 | 
														
															 	defer func() { 
														 | 
													
												
											
										
											
												
													
														 | 
														
															@@ -119,16 +128,17 @@ func TestRelay(ctx context.Context, uri *url.URL, certs []tls.Certificate, sleep 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	}() 
														 | 
														
														 | 
														
															 	}() 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	for i := 0; i < times; i++ { 
														 | 
														
														 | 
														
															 	for i := 0; i < times; i++ { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-		_, err := GetInvitationFromRelay(ctx, uri, id, certs, timeout) 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+		_, err = GetInvitationFromRelay(ctx, uri, id, certs, timeout) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		if err == nil { 
														 | 
														
														 | 
														
															 		if err == nil { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-			return true 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+			return nil 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		} 
														 | 
														
														 | 
														
															 		} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-		if !strings.Contains(err.Error(), "Incorrect response code") { 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-			return false 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+		if !errors.As(err, &incorrectResponseCodeErr{}) { 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+			return fmt.Errorf("getting invitation: %w", err) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		} 
														 | 
														
														 | 
														
															 		} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 		time.Sleep(sleep) 
														 | 
														
														 | 
														
															 		time.Sleep(sleep) 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 	} 
														 | 
														
														 | 
														
															 	} 
														 | 
													
												
											
												
													
														| 
														 | 
														
															-	return false 
														 | 
														
														 | 
														
															 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+ 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 
														 | 
														
														 | 
														
															+	return fmt.Errorf("getting invitation: %w", err) // last of the above errors 
														 | 
													
												
											
												
													
														| 
														 | 
														
															 } 
														 | 
														
														 | 
														
															 } 
														 | 
													
												
											
												
													
														| 
														 | 
														
															  
														 | 
														
														 | 
														
															  
														 | 
													
												
											
												
													
														| 
														 | 
														
															 func configForCerts(certs []tls.Certificate) *tls.Config { 
														 | 
														
														 | 
														
															 func configForCerts(certs []tls.Certificate) *tls.Config { 
														 |