func requestProcessor() { for request := range requests { if debug { log.Println("Request for", request.relay) } if !client.TestRelay(request.uri, []tls.Certificate{testCert}, time.Second, 2*time.Second, 3) { if debug { log.Println("Test for relay", request.relay, "failed") } request.result <- result{fmt.Errorf("test failed"), 0} continue } mut.Lock() timer, ok := evictionTimers[request.relay.uri.Host] if ok { if debug { log.Println("Stopping existing timer for", request.relay) } timer.Stop() } for i, current := range knownRelays { if current.uri.Host == request.relay.uri.Host { if debug { log.Println("Relay", request.relay, "already exists") } // Evict the old entry anyway, as configuration might have changed. last := len(knownRelays) - 1 knownRelays[i] = knownRelays[last] knownRelays = knownRelays[:last] goto found } } if debug { log.Println("Adding new relay", request.relay) } found: knownRelays = append(knownRelays, request.relay) evictionTimers[request.relay.uri.Host] = time.AfterFunc(evictionTime, evict(request.relay)) mut.Unlock() request.result <- result{nil, evictionTime} } }
func requestProcessor() { for request := range requests { if debug { log.Println("Request for", request.relay) } if !client.TestRelay(request.uri, []tls.Certificate{testCert}, 250*time.Millisecond, 4) { if debug { log.Println("Test for relay", request.relay, "failed") } request.result <- result{fmt.Errorf("test failed"), 0} continue } mut.Lock() timer, ok := evictionTimers[request.relay.uri.Host] if ok { if debug { log.Println("Stopping existing timer for", request.relay) } timer.Stop() } for _, current := range knownRelays { if current.uri.Host == request.relay.uri.Host { if debug { log.Println("Relay", request.relay, "already exists") } goto found } } if debug { log.Println("Adding new relay", request.relay) } knownRelays = append(knownRelays, request.relay) found: evictionTimers[request.relay.uri.Host] = time.AfterFunc(evictionTime, evict(request.relay)) mut.Unlock() request.result <- result{nil, evictionTime} } }
func main() { log.SetOutput(os.Stdout) log.SetFlags(log.LstdFlags | log.Lshortfile) var connect, relay, dir string var join, test bool flag.StringVar(&connect, "connect", "", "Device ID to which to connect to") flag.BoolVar(&join, "join", false, "Join relay") flag.BoolVar(&test, "test", false, "Generic relay test") flag.StringVar(&relay, "relay", "relay://127.0.0.1:22067", "Relay address") flag.StringVar(&dir, "keys", ".", "Directory where cert.pem and key.pem is stored") flag.Parse() certFile, keyFile := filepath.Join(dir, "cert.pem"), filepath.Join(dir, "key.pem") cert, err := tls.LoadX509KeyPair(certFile, keyFile) if err != nil { log.Fatalln("Failed to load X509 key pair:", err) } id := syncthingprotocol.NewDeviceID(cert.Certificate[0]) log.Println("ID:", id) uri, err := url.Parse(relay) if err != nil { log.Fatal(err) } stdin := make(chan string) go stdinReader(stdin) if join { log.Println("Creating client") relay, err := client.NewClient(uri, []tls.Certificate{cert}, nil, 10*time.Second) if err != nil { log.Fatal(err) } log.Println("Created client") go relay.Serve() recv := make(chan protocol.SessionInvitation) go func() { log.Println("Starting invitation receiver") for invite := range relay.Invitations() { select { case recv <- invite: log.Println("Received invitation", invite) default: log.Println("Discarding invitation", invite) } } }() for { conn, err := client.JoinSession(<-recv) if err != nil { log.Fatalln("Failed to join", err) } log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr()) connectToStdio(stdin, conn) log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr()) } } else if connect != "" { id, err := syncthingprotocol.DeviceIDFromString(connect) if err != nil { log.Fatal(err) } invite, err := client.GetInvitationFromRelay(uri, id, []tls.Certificate{cert}, 10*time.Second) if err != nil { log.Fatal(err) } log.Println("Received invitation", invite) conn, err := client.JoinSession(invite) if err != nil { log.Fatalln("Failed to join", err) } log.Println("Joined", conn.RemoteAddr(), conn.LocalAddr()) connectToStdio(stdin, conn) log.Println("Finished", conn.RemoteAddr(), conn.LocalAddr()) } else if test { if client.TestRelay(uri, []tls.Certificate{cert}, time.Second, 2*time.Second, 4) { log.Println("OK") } else { log.Println("FAIL") } } else { log.Fatal("Requires either join or connect") } }