-
Notifications
You must be signed in to change notification settings - Fork 2
/
main.go
216 lines (189 loc) · 5.09 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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package main
import (
"flag"
"fmt"
"log"
"net"
"net/http"
_ "net/http/pprof"
"os"
"strconv"
"strings"
"sync"
"time"
"github.com/mumax/3/httpfs"
"github.com/mumax/3/util"
)
var (
flag_addr = flag.String("l", ":35360", "Listen and serve at this network address")
flag_scan = flag.String("scan", "192.168.0.1-128", "Scan these IP address for other servers")
flag_ports = flag.String("ports", "35360-35361", "Scan these ports for other servers")
flag_timeout = flag.Duration("timeout", 2*time.Second, "Portscan timeout")
flag_mumax = flag.String("exec", "mumax3", "mumax3 executable")
flag_cachedir = flag.String("cache", "", "mumax3 kernel cache path")
flag_log = flag.Bool("log", true, "log debug output")
flag_halflife = flag.Duration("halflife", 24*time.Hour, "share decay half-life")
)
const (
MaxIPs = 1024 // maximum number of IP address to portscan
N_SCANNERS = 32 // number of parallel portscan goroutines
MAXGPU = 16 // maximum number of GPU's to check for
KeepaliveInterval = 10 * time.Second // signal process liveness every KeepaliveInterval
)
var (
thisAddr string // unique address of this node, e.g., name:1234
thisHost string // unique hostname of this node, e.g., name
IPs []string
MinPort, MaxPort int
global_lock sync.RWMutex
)
func RLock() { global_lock.RLock() }
func RUnlock() { global_lock.RUnlock() }
func WLock() { global_lock.Lock() }
func WUnlock() { global_lock.Unlock() }
const GUI_PORT = 35367 // base port number for GUI (to be incremented by GPU number)
func main() {
flag.Parse()
IPs = parseIPs()
MinPort, MaxPort = parsePorts()
thisAddr = canonicalAddr(*flag_addr, IPs)
var err error
thisHost, _, err = net.SplitHostPort(thisAddr)
util.FatalErr(err)
DetectMumax()
DetectGPUs()
LoadJobs()
http.HandleFunc("/do/", HandleRPC)
http.HandleFunc("/", HandleStatus)
httpfs.RegisterHandlers()
// Listen and serve on all interfaces
go func() {
log.Println("serving at", thisAddr)
// try to listen and serve on all interfaces other than thisAddr
// this is for convenience, errors are not fatal.
_, p, err := net.SplitHostPort(thisAddr)
Fatal(err)
ips := util.InterfaceAddrs()
for _, ip := range ips {
addr := net.JoinHostPort(ip, p)
if addr != thisAddr { // skip thisAddr, will start later and is fatal on error
go func() {
err := http.ListenAndServe(addr, nil)
if err != nil {
log.Println("info:", err, "(but still serving other interfaces)")
}
}()
}
}
// only on thisAddr, this server's unique address,
// we HAVE to be listening.
Fatal(http.ListenAndServe(thisAddr, nil))
}()
ProbePeer(thisAddr) // make sure we have ourself as peer
go FindPeers(IPs, MinPort, MaxPort)
go RunComputeService()
go LoopWatchdog()
go RunShareDecay()
// re-load jobs every hour so we don't stall on very exceptional circumstances
go func() {
for {
time.Sleep(1 * time.Hour)
LoadJobs()
}
}()
<-make(chan struct{}) // wait forever
}
// replace laddr by a canonical form, as it will serve as unique ID
func canonicalAddr(laddr string, IPs []string) string {
// safe initial guess: hostname:port
h, p, err := net.SplitHostPort(laddr)
Fatal(err)
if h == "" {
h, _ = os.Hostname()
}
name := net.JoinHostPort(h, p)
ips := util.InterfaceAddrs()
for _, ip := range ips {
if contains(IPs, ip) {
return net.JoinHostPort(ip, p)
}
}
return name
}
func contains(arr []string, x string) bool {
for _, s := range arr {
if x == s {
return true
}
}
return false
}
// Parse port range flag. E.g.:
// 1234-1237 -> 1234, 1237
func parsePorts() (minPort, maxPort int) {
p := *flag_ports
split := strings.Split(p, "-")
if len(split) > 2 {
log.Fatal("invalid port range:", p)
}
minPort, _ = strconv.Atoi(split[0])
if len(split) > 1 {
maxPort, _ = strconv.Atoi(split[1])
}
if maxPort == 0 {
maxPort = minPort
}
if minPort == 0 || maxPort == 0 || maxPort < minPort {
log.Fatal("invalid port range:", p)
}
return
}
// init IPs from flag
func parseIPs() []string {
var IPs []string
defer func() {
if err := recover(); err != nil {
log.Fatal("invalid IP range:", *flag_scan)
}
}()
p := *flag_scan
split := strings.Split(p, ",")
for _, s := range split {
split := strings.Split(s, ".")
if len(split) != 4 {
log.Fatal("invalid IP address range:", s)
}
var start, stop [4]byte
for i, s := range split {
split := strings.Split(s, "-")
first := atobyte(split[0])
start[i], stop[i] = first, first
if len(split) > 1 {
stop[i] = atobyte(split[1])
}
}
for A := start[0]; A <= stop[0]; A++ {
for B := start[1]; B <= stop[1]; B++ {
for C := start[2]; C <= stop[2]; C++ {
for D := start[3]; D <= stop[3]; D++ {
if len(IPs) > MaxIPs {
log.Fatal("too many IP addresses to scan in", p)
}
IPs = append(IPs, fmt.Sprintf("%v.%v.%v.%v", A, B, C, D))
}
}
}
}
}
return IPs
}
func atobyte(a string) byte {
i, err := strconv.Atoi(a)
if err != nil {
panic(err)
}
if int(byte(i)) != i {
panic("too large")
}
return byte(i)
}