func (ds *DiscoveryBrowser) Browse(service *NetworkWebSocket_Service, intervalSeconds, timeoutSeconds int) { // Don't run two browse processes at the same time if ds.inprogress { return } ds.inprogress = true entries := make(chan *mdns.ServiceEntry, 255) recordsCache := make(map[string]*NetworkWebSocket_DNSRecord) timeout := time.Duration(timeoutSeconds) * time.Second interval := time.Duration(intervalSeconds) * time.Second var targetIPv4 *net.UDPAddr var targetIPv6 *net.UDPAddr targetIPv4 = network_ipv4Addr targetIPv6 = network_ipv6Addr // Only look for Named Web Socket DNS-SD services params := &mdns.QueryParam{ Service: "_nws._tcp", Domain: "local", Timeout: timeout, Entries: entries, IPv4mdns: targetIPv4, IPv6mdns: targetIPv6, } go func() { complete := false timeoutFinish := time.After(timeout) intervalFinish := time.After(interval) // Wait for responses until timeout for !complete { select { case discoveredService, ok := <-entries: if !ok { continue } serviceRecord, err := NewNetworkWebSocketRecordFromDNSRecord(discoveredService) if err != nil { log.Printf("err: %v", err) continue } // Ignore our own NetworkWebSocket services if service.isOwnProxyService(serviceRecord) { continue } // Ignore previously discovered NetworkWebSocket proxy services if service.isActiveProxyService(serviceRecord) { continue } // Resolve discovered service hash provided against available services var sock *NetworkWebSocket for _, knownService := range service.Channels { if bcrypt.Match(knownService.serviceName, serviceRecord.Hash_BCrypt) { sock = knownService break } } if sock != nil { // Create new web socket connection toward discovered proxy if _, dErr := sock.dialFromDNSRecord(serviceRecord); dErr != nil { log.Printf("err: %v", dErr) continue } } else { // Store as an unresolved DNS-SD record recordsCache[serviceRecord.Hash_Base64] = serviceRecord continue } case <-timeoutFinish: // Replace unresolved DNS records cache ds.cachedDNSRecords = recordsCache ds.inprogress = false case <-intervalFinish: complete = true } } }() // Run the mDNS/DNS-SD query err := mdns.Query(params) time.Sleep(interval) // sleep until next loop is scheduled if err != nil { log.Printf("Could not perform mDNS/DNS-SD query. %v", err) return } }
func (ds *DiscoveryServer) Browse() { entries := make(chan *mdns.ServiceEntry, 255) timeout := 2 * time.Second params := &mdns.QueryParam{ Service: "_ws._tcp", Domain: "local", Timeout: timeout, Entries: entries, } go func() { complete := false finish := time.After(timeout) // Wait for responses until timeout for !complete { select { case e, ok := <-entries: if !ok { continue } nameComponents := strings.Split(e.Name, ".") shortName := "" for i := len(nameComponents) - 1; i >= 0; i-- { if nameComponents[i] == "_ws" { shortName = strings.Join(nameComponents[:i], ".") break } } // DEBUG //log.Printf("Found proxy web socket [%s] @ [%s:%d] TXT[%s]", shortName, e.Host, e.Port, e.Info) // Is this a BroadcastWebSocket service? if isValid := NetworkServiceMatcher.MatchString(shortName); !isValid { continue } // Ignore our own BroadcastWebSocket services if isOwned := advertisedServiceNames[shortName]; isOwned { continue } // Ignore previously discovered BroadcastWebSocket services if isRegistered := registeredServiceNames[shortName]; isRegistered { continue } // Build websocket data from returned information servicePath := "/" serviceParts := strings.FieldsFunc(e.Info, func(r rune) bool { return r == '=' || r == ',' || r == ';' || r == ' ' }) if len(serviceParts) > 1 { for i := 0; i < len(serviceParts); i += 2 { if strings.ToLower(serviceParts[i]) == "path" { servicePath = serviceParts[i+1] break } } } // Generate unique id for connection rand.Seed(time.Now().UTC().UnixNano()) newPeerId := rand.Int() // Build URL remoteWSUrl := &url.URL{ Scheme: "ws", Host: fmt.Sprintf("%s:%d", e.Host, e.Port), Path: fmt.Sprintf("%s/%d", servicePath, newPeerId), } serviceName := path.Base(servicePath) // Resolve websocket connection sock := namedWebSockets[servicePath] if sock == nil { sock = NewNamedWebSocket(serviceName, true, ds.Port) namedWebSockets[servicePath] = sock } log.Printf("Establishing proxy broadcast websocket connection to ws://%s%s", remoteWSUrl.Host, remoteWSUrl.Path) ws, _, nErr := websocket.DefaultDialer.Dial(remoteWSUrl.String(), map[string][]string{ "Origin": []string{ds.Host}, "X-BroadcastWebSocket-Proxy": []string{"true"}, }) if nErr != nil { log.Printf("Proxy broadcast websocket connection failed: %s", nErr) return } proxyConn := NewProxyConnection(newPeerId, ws, false) proxyConn.addConnection(sock) registeredServiceNames[shortName] = true case <-finish: complete = true } } }() // Run the mDNS query err := mdns.Query(params) if err != nil { log.Fatalf("err: %v", err) } }
func (ds *DiscoveryBrowser) Browse(service *Service, timeoutSeconds int) { entries := make(chan *mdns.ServiceEntry, 255) recordsCache := make(map[string]*DNSRecord, 255) timeout := time.Duration(timeoutSeconds) * time.Second var targetIPv4 *net.UDPAddr var targetIPv6 *net.UDPAddr targetIPv4 = network_ipv4Addr targetIPv6 = network_ipv6Addr // Only look for Network Web Socket DNS-SD services params := &mdns.QueryParam{ Service: "_nws._tcp", Domain: "local", Timeout: timeout, Entries: entries, IPv4mdns: targetIPv4, IPv6mdns: targetIPv6, } go func() { complete := false timeoutFinish := time.After(timeout) // Wait for responses until timeout for !complete { select { case discoveredService, ok := <-entries: if !ok { continue } serviceRecord, err := NewServiceRecordFromDNSRecord(discoveredService) if err != nil { log.Printf("err: %v", err) continue } // Ignore our own Channel services if service.isOwnProxyService(serviceRecord) { continue } // Ignore previously discovered Channel proxy services if service.isActiveProxyService(serviceRecord) { continue } // Resolve discovered service hash provided against available services var channel *Channel for _, knownService := range service.Channels { if bcrypt.Match(knownService.serviceName, serviceRecord.Hash_BCrypt) { channel = knownService break } } if channel != nil { // Create new web socket connection toward discovered proxy if dErr := dialProxyFromDNSRecord(serviceRecord, channel); dErr != nil { log.Printf("err: %v", dErr) continue } } else { // Store as an unresolved DNS-SD record recordsCache[serviceRecord.Hash_Base64] = serviceRecord continue } case <-timeoutFinish: // Replace unresolved DNS records cache ds.cachedDNSRecords = recordsCache complete = true } } }() // Run the mDNS/DNS-SD query err := mdns.Query(params) if err != nil { log.Printf("Could not perform mDNS/DNS-SD query. %v", err) return } }