Files
weave/weaver/main.go
T
2015-03-06 11:15:24 +00:00

194 lines
5.2 KiB
Go

package main
import (
"code.google.com/p/gopacket/layers"
"crypto/sha256"
"flag"
"fmt"
"github.com/davecheney/profile"
weavenet "github.com/zettio/weave/net"
weave "github.com/zettio/weave/router"
"io"
"log"
"net"
"net/http"
"os"
"os/signal"
"runtime"
"syscall"
)
var version = "(unreleased version)"
func main() {
log.SetPrefix(weave.Protocol + " ")
log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds)
procs := runtime.NumCPU()
// packet sniffing can block an OS thread, so we need one thread
// for that plus at least one more.
if procs < 2 {
procs = 2
}
runtime.GOMAXPROCS(procs)
var (
justVersion bool
ifaceName string
routerName string
nickName string
password string
wait int
debug bool
prof string
peers []string
connLimit int
bufSz int
)
flag.BoolVar(&justVersion, "version", false, "print version and exit")
flag.StringVar(&ifaceName, "iface", "", "name of interface to read from")
flag.StringVar(&routerName, "name", "", "name of router (defaults to MAC)")
flag.StringVar(&nickName, "nickname", "", "nickname of peer (defaults to hostname)")
flag.StringVar(&password, "password", "", "network password")
flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (defaults to 0, i.e. don't wait)")
flag.BoolVar(&debug, "debug", false, "enable debug logging")
flag.StringVar(&prof, "profile", "", "enable profiling and write profiles to given path")
flag.IntVar(&connLimit, "connlimit", 10, "connection limit (defaults to 10, set to 0 for unlimited)")
flag.IntVar(&bufSz, "bufsz", 8, "capture buffer size in MB (defaults to 8MB)")
flag.Parse()
peers = flag.Args()
if justVersion {
fmt.Printf("weave router %s\n", version)
os.Exit(0)
}
options := make(map[string]string)
flag.Visit(func(f *flag.Flag) {
value := f.Value.String()
if f.Name == "password" {
value = "<elided>"
}
options[f.Name] = value
})
log.Println("Command line options:", options)
log.Println("Command line peers:", peers)
if ifaceName == "" {
fmt.Println("Missing required parameter 'iface'")
os.Exit(1)
}
iface, err := weavenet.EnsureInterface(ifaceName, wait)
if err != nil {
log.Fatal(err)
}
if routerName == "" {
routerName = iface.HardwareAddr.String()
}
if nickName == "" {
nickName, err = os.Hostname()
if err != nil {
log.Fatal(err)
}
}
ourName, err := weave.PeerNameFromUserInput(routerName)
if err != nil {
log.Fatal(err)
}
if password == "" {
password = os.Getenv("WEAVE_PASSWORD")
}
var pwSlice []byte
if password == "" {
log.Println("Communication between peers is unencrypted.")
} else {
pwSlice = []byte(password)
log.Println("Communication between peers is encrypted.")
}
var logFrame func(string, []byte, *layers.Ethernet)
if debug {
logFrame = func(prefix string, frame []byte, eth *layers.Ethernet) {
h := fmt.Sprintf("%x", sha256.Sum256(frame))
if eth == nil {
log.Println(prefix, len(frame), "bytes (", h, ")")
} else {
log.Println(prefix, len(frame), "bytes (", h, "):", eth.SrcMAC, "->", eth.DstMAC)
}
}
} else {
logFrame = func(prefix string, frame []byte, eth *layers.Ethernet) {}
}
if prof != "" {
p := *profile.CPUProfile
p.ProfilePath = prof
defer profile.Start(&p).Stop()
}
router := weave.NewRouter(iface, ourName, nickName, pwSlice, connLimit, bufSz*1024*1024, logFrame)
log.Println("Our name is", router.Ourself.Name, "("+router.Ourself.NickName+")")
router.Start()
for _, peer := range peers {
if addr, err := net.ResolveTCPAddr("tcp4", weave.NormalisePeerAddr(peer)); err == nil {
router.ConnectionMaker.InitiateConnection(addr.String())
} else {
log.Fatal(err)
}
}
go handleHttp(router)
handleSignals(router)
}
func handleHttp(router *weave.Router) {
encryption := "off"
if router.UsingPassword() {
encryption = "on"
}
http.HandleFunc("/status", func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, fmt.Sprintln("weave router", version))
io.WriteString(w, fmt.Sprintln("Encryption", encryption))
io.WriteString(w, router.Status())
})
http.HandleFunc("/status-json", func(w http.ResponseWriter, r *http.Request) {
json, _ := router.GenerateStatusJSON(version, encryption)
w.Write(json)
})
http.HandleFunc("/connect", func(w http.ResponseWriter, r *http.Request) {
peer := r.FormValue("peer")
if addr, err := net.ResolveTCPAddr("tcp4", weave.NormalisePeerAddr(peer)); err == nil {
router.ConnectionMaker.InitiateConnection(addr.String())
} else {
http.Error(w, fmt.Sprint("invalid peer address: ", err), http.StatusBadRequest)
}
})
address := fmt.Sprintf(":%d", weave.HttpPort)
err := http.ListenAndServe(address, nil)
if err != nil {
log.Fatal("Unable to create http listener: ", err)
}
}
func handleSignals(router *weave.Router) {
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGQUIT, syscall.SIGUSR1)
buf := make([]byte, 1<<20)
for {
sig := <-sigs
switch sig {
case syscall.SIGQUIT:
stacklen := runtime.Stack(buf, true)
log.Printf("=== received SIGQUIT ===\n*** goroutine dump...\n%s\n*** end\n", buf[:stacklen])
case syscall.SIGUSR1:
log.Printf("=== received SIGUSR1 ===\n*** status...\n%s\n*** end\n", router.Status())
}
}
}