func pingRemote() { result := make(chan *time.Duration) go ping.Ping(*remoteIp, 1*time.Second, result) reachable := <-result != nil if reachable { state = waiting return } log.Printf("target unresponsive, sending magic packet to %s…\n", *remoteMac) if err := exec.Command(*wolCommand, *remoteMac).Run(); err != nil { log.Fatal(err) } for second := 0; second < *wakeTimeout; second++ { go ping.Ping(*remoteIp, 1*time.Second, result) if <-result != nil { log.Printf("target reachable after %d seconds\n", second) break } } state = waiting }
func wakeUp(host, mac string) (bool, error) { result := make(chan *time.Duration) go ping.Ping(host, 5*time.Second, result) if <-result != nil { log.Printf("Host %s responding to pings, not waking up.\n", host) return false, nil } // Parse MAC address parts := strings.Split(mac, ":") if len(parts) != 6 { log.Fatalf(`MAC address "%s" does not consist of 6 parts`, mac) } macParts := make([]uint8, 6) for idx, str := range parts { converted, err := strconv.ParseUint(str, 16, 8) if err != nil { log.Fatalf("Invalid MAC address part: %s: %v\n", str, err) } macParts[idx] = uint8(converted) } // Send magic Wake-On-LAN packet payload := make([]byte, 102) for idx := 0; idx < 6; idx++ { payload[idx] = 0xff } for n := 0; n < 16; n++ { for part := 0; part < 6; part++ { payload[6+(n*6)+part] = macParts[part] } } socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{ IP: net.IPv4(255, 255, 255, 255), // udp/9 is the discard protocol Port: 9, }) if err != nil { log.Fatalf("Cannot open UDP broadcast socket: %v\n", err) } socket.Write(payload) socket.Close() log.Printf("Sent magic packet to %02x:%02x:%02x:%02x:%02x:%02x\n", macParts[0], macParts[1], macParts[2], macParts[3], macParts[4], macParts[5]) timeout := 120 * time.Second packetSent := time.Now() for time.Since(packetSent) < timeout { go ping.Ping(host, 1*time.Second, result) if <-result != nil { log.Printf("Host %s woke up after waiting %v.\n", host, time.Since(packetSent)) return true, nil } time.Sleep(500 * time.Millisecond) } return true, fmt.Errorf("Host %s not responding to pings within %v after sending magic packet", host, timeout) }
func pingBeast() { for { result := make(chan *time.Duration) go ping.Ping("beast", 1*time.Second, result) latency := <-result stateMu.Lock() state.beastPowered = latency != nil if state.beastPowered { lastContact["beast"] = time.Now() } stateMu.Unlock() stateChanged.Broadcast() if latency != nil { time.Sleep(1*time.Second - *latency) } } }
// Runs infinitely as a goroutine, periodically pinging samba users. func pingUsers() { for { statusLock.Lock() hosts = getSessionHostnames() statusLock.Unlock() // This default will lead to a shutdown in case the machine gets booted // and nobody starts using it within 10 minutes, which is intentional. // The machine should only be booted when usage is imminent. reachable := false if len(hosts) > 0 { result := make(chan *time.Duration) for _, host := range hosts { go ping.Ping(host, 5*time.Second, result) } reachable = <-result != nil } statusLock.Lock() reachableUsers = reachable statusLock.Unlock() time.Sleep(10 * time.Second) } }