mdns.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. package mdns
  2. import (
  3. "context"
  4. "log"
  5. "net"
  6. "strings"
  7. "time"
  8. "github.com/grandcat/zeroconf"
  9. )
  10. type MDNSHost struct {
  11. MDNS *zeroconf.Server
  12. Host *NetworkHost
  13. }
  14. type NetworkHost struct {
  15. HostName string
  16. Port int
  17. IPv4 []net.IP
  18. Domain string
  19. Model string
  20. UUID string
  21. Vendor string
  22. BuildVersion string
  23. MinorVersion string
  24. MacAddr []string
  25. Online bool
  26. }
  27. func NewMDNS(config NetworkHost) (*MDNSHost, error) {
  28. //Get host MAC Address
  29. macAddress, err := getMacAddr()
  30. macAddressBoardcast := ""
  31. if err == nil {
  32. macAddressBoardcast = strings.Join(macAddress, ",")
  33. } else {
  34. log.Println("[mDNS] Unable to get MAC Address: ", err.Error())
  35. }
  36. //Register the mds services
  37. server, err := zeroconf.Register(config.HostName, "_http._tcp", "local.", config.Port, []string{"version_build=" + config.BuildVersion, "version_minor=" + config.MinorVersion, "vendor=" + config.Vendor, "model=" + config.Model, "uuid=" + config.UUID, "domain=" + config.Domain, "mac_addr=" + macAddressBoardcast}, nil)
  38. if err != nil {
  39. log.Println("[mDNS] Error when registering zeroconf broadcast message", err.Error())
  40. return &MDNSHost{}, err
  41. }
  42. return &MDNSHost{
  43. MDNS: server,
  44. Host: &config,
  45. }, nil
  46. }
  47. func (m *MDNSHost) Close() {
  48. if m != nil {
  49. m.MDNS.Shutdown()
  50. }
  51. }
  52. //Scan with given timeout and domain filter. Use m.Host.Domain for scanning similar typed devices
  53. func (m *MDNSHost) Scan(timeout int, domainFilter string) []*NetworkHost {
  54. // Discover all services on the network (e.g. _workstation._tcp)
  55. resolver, err := zeroconf.NewResolver(nil)
  56. if err != nil {
  57. log.Fatalln("Failed to initialize resolver:", err.Error())
  58. }
  59. entries := make(chan *zeroconf.ServiceEntry)
  60. //Create go routine to wait for the resolver
  61. discoveredHost := []*NetworkHost{}
  62. go func(results <-chan *zeroconf.ServiceEntry) {
  63. for entry := range results {
  64. if domainFilter == "" {
  65. //This is a ArOZ Online Host
  66. //Split the required information out of the text element
  67. TEXT := entry.Text
  68. properties := map[string]string{}
  69. for _, v := range TEXT {
  70. kv := strings.Split(v, "=")
  71. if len(kv) == 2 {
  72. properties[kv[0]] = kv[1]
  73. }
  74. }
  75. var macAddrs []string
  76. val, ok := properties["mac_addr"]
  77. if !ok || val == "" {
  78. //No MacAddr found. Target node version too old
  79. macAddrs = []string{}
  80. } else {
  81. macAddrs = strings.Split(properties["mac_addr"], ",")
  82. }
  83. //log.Println(properties)
  84. discoveredHost = append(discoveredHost, &NetworkHost{
  85. HostName: entry.HostName,
  86. Port: entry.Port,
  87. IPv4: entry.AddrIPv4,
  88. Domain: properties["domain"],
  89. Model: properties["model"],
  90. UUID: properties["uuid"],
  91. Vendor: properties["vendor"],
  92. BuildVersion: properties["version_build"],
  93. MinorVersion: properties["version_minor"],
  94. MacAddr: macAddrs,
  95. Online: true,
  96. })
  97. } else {
  98. if stringInSlice("domain="+domainFilter, entry.Text) {
  99. //This is a ArOZ Online Host
  100. //Split the required information out of the text element
  101. TEXT := entry.Text
  102. properties := map[string]string{}
  103. for _, v := range TEXT {
  104. kv := strings.Split(v, "=")
  105. if len(kv) == 2 {
  106. properties[kv[0]] = kv[1]
  107. }
  108. }
  109. var macAddrs []string
  110. val, ok := properties["mac_addr"]
  111. if !ok || val == "" {
  112. //No MacAddr found. Target node version too old
  113. macAddrs = []string{}
  114. } else {
  115. macAddrs = strings.Split(properties["mac_addr"], ",")
  116. }
  117. //log.Println(properties)
  118. discoveredHost = append(discoveredHost, &NetworkHost{
  119. HostName: entry.HostName,
  120. Port: entry.Port,
  121. IPv4: entry.AddrIPv4,
  122. Domain: properties["domain"],
  123. Model: properties["model"],
  124. UUID: properties["uuid"],
  125. Vendor: properties["vendor"],
  126. BuildVersion: properties["version_build"],
  127. MinorVersion: properties["version_minor"],
  128. MacAddr: macAddrs,
  129. Online: true,
  130. })
  131. }
  132. }
  133. }
  134. }(entries)
  135. //Resolve each of the mDNS and pipe it back to the log functions
  136. ctx, cancel := context.WithTimeout(context.Background(), time.Second*time.Duration(timeout))
  137. defer cancel()
  138. err = resolver.Browse(ctx, "_http._tcp", "local.", entries)
  139. if err != nil {
  140. log.Fatalln("Failed to browse:", err.Error())
  141. }
  142. //Update the master scan record
  143. <-ctx.Done()
  144. return discoveredHost
  145. }