/
main.go
141 lines (128 loc) · 4.34 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package main
import (
"log/syslog"
"net/http"
"flag"
"net"
"fmt"
"encoding/binary"
"bytes"
"time"
wololo "github.com/FuzzyLogic/Wololo/internal"
)
var globalConfig wololo.WololoConfig
var globalLog *syslog.Writer
var globalVerbose bool
var finishedRequestWait chan bool
// HTTP handler function to handle requests.
// This handler will send the WOL packet to the configured destination.
// The response will contain information on whether the packet was transmitted or an error occurred.
func wolHandler(respWr http.ResponseWriter, req *http.Request) {
// Get WOL parameters from request or, alternatively, use default values from config
var macAddr wololo.MACAddress
paramMACAddr := req.URL.Query().Get("macaddr")
if paramMACAddr != "" {
err := wololo.CheckMACAddr(paramMACAddr)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
convertedMacAddr, err := wololo.ParseMAC(paramMACAddr)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
macAddr = *convertedMacAddr
} else {
macAddr = globalConfig.MacAddr
}
// Build the packet, consisting of indicator and target device's MAC address
wolPacket := wololo.BuildWolPacket(macAddr)
// WOL needs to be broadcasted, create UDPAddress from config or query parameters
var udpBcastAddr string
paramUdpBcastAddr := req.URL.Query().Get("udpbcastaddr")
if paramUdpBcastAddr != "" {
err := wololo.CheckBcastAddr(paramUdpBcastAddr)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
udpBcastAddr = paramUdpBcastAddr
} else {
udpBcastAddr = globalConfig.UdpBcastAddr
}
resolvedUdpBcastAddr, err := net.ResolveUDPAddr("udp", udpBcastAddr)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
// Get local IP address from specified interface
localUDPAddr, err := wololo.InterfaceToIp(globalConfig.Iface)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
// Open UDP connection to send WOL packet and start timer s.t. network flooding
// through too many requests is mitigated
<- finishedRequestWait
con, err := net.DialUDP("udp", localUDPAddr, resolvedUdpBcastAddr)
go func(finishedRequestWait chan bool) {
time.Sleep(3 * time.Second)
finishedRequestWait <- true
}(finishedRequestWait)
if err != nil {
wololo.WriteToLog(globalLog, "Error: " + err.Error())
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
return
}
defer con.Close()
// Broadcast the WOL packet
var packetBuf bytes.Buffer
binary.Write(&packetBuf, binary.BigEndian, wolPacket)
bytesWritten, err := con.Write(packetBuf.Bytes())
if err != nil {
wololo.WriteToLog(globalLog, "Error sending WOL packet")
fmt.Fprintf(respWr, "Error: " + err.Error() + "\n")
} else if bytesWritten != 102 {
// Not an error but something went wrong - inform user
wololo.WriteToLog(globalLog, "Warning: WOL packet transmission may have been incomplete")
fmt.Fprintf(respWr, "Warning: WOL packet transmission may have been incomplete\n")
} else {
// Notify user that WOL packet was sent
wololo.WriteToLog(globalLog, "WOL packet sent")
fmt.Fprintf(respWr, "Device is off...\nWOLOLO\nDevice is on!")
}
}
func main() {
// Command line arg parsing
configPathPtr := flag.String("config", "/etc/wololo/config.json", "Path to Wololo configuration file")
flag.Parse()
// Start logging and defer connection close to end
globalLog = wololo.SetupLog()
defer func() {
if err := globalLog.Close(); err != nil {
panic(err)
}
}()
// Read configuration into global variable
globalConfigPtr, err := wololo.ReadConfig(*configPathPtr)
if err != nil {
wololo.WriteToLog(globalLog, "Error reading configuration")
panic(err)
}
globalConfig = *globalConfigPtr
// Start HTTP handler
finishedRequestWait = make(chan bool, 1)
finishedRequestWait <- true
wololo.WriteToLog(globalLog, "Starting server")
http.HandleFunc("/", wolHandler)
if err := http.ListenAndServe(globalConfig.ListenAddr+":"+globalConfig.ListenPort, nil); err != nil {
wololo.WriteToLog(globalLog, "Unable to start server")
panic(err)
}
}