func sshClientActivity(index int) { sc := sshConns[index] s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) // generate a random byte slice l := r.Intn(128) b := make([]byte, l) for i, _ := range b { b[i] = byte(r.Int()) } data := base64.StdEncoding.EncodeToString(b) log.Debug("ssh activity to %v with %v", sc.Host, data) start := time.Now().UnixNano() sc.Stdin.Write([]byte(data)) sc.Stdin.Write([]byte{'\r', '\n'}) sshReportChan <- uint64(len(data)) expected := fmt.Sprintf("> %v\r\n%v\r\n> ", data, data) for i := 0; i < 10 && sc.StdoutBuf.String() != expected; i++ { time.Sleep(100 * time.Millisecond) } stop := time.Now().UnixNano() log.Info("ssh %v %vns", sc.Host, uint64(stop-start)) log.Debugln("ssh: ", sc.StdoutBuf.String()) sc.StdoutBuf.Reset() }
func smtpServer(p string) { log.Debugln("smtpServer") certfile, keyfile := generateCerts() cert, err := tls.LoadX509KeyPair(certfile, keyfile) if err != nil { log.Fatalln("couldn't get cert: ", err) } TLSconfig = &tls.Config{Certificates: []tls.Certificate{cert}, ClientAuth: tls.VerifyClientCertIfGiven, ServerName: myFQDN} listener, err := net.Listen(p, "0.0.0.0"+smtpPort) if err != nil { log.Fatalln(err) } for { conn, err := listener.Accept() if err != nil { log.Debugln(err) continue } client := NewSMTPClientSession(conn) go client.Handler() smtpReportChan <- 1 } }
// incoming message mux. Routes messages to the correct handlers based on // message type func (s *Server) mux() { for { m := <-s.in switch m.Type { case MESSAGE_CLIENT: // handle a client response log.Debugln("ron MESSAGE_CLIENT") s.responses <- m.Client case MESSAGE_TUNNEL: // handle a tunnel message log.Debugln("ron MESSAGE_TUNNEL") s.routeTunnel(m) case MESSAGE_COMMAND: // route a command to one or all clients log.Debugln("ron MESSAGE_COMMAND") s.route(m) case MESSAGE_FILE: // send a file if it exists s.sendFile(m) default: log.Error("unknown message type: %v", m.Type) return } } }
func hostStatsMemory() (int, int, error) { memory, err := os.Open("/proc/meminfo") if err != nil { return 0, 0, err } defer memory.Close() scanner := bufio.NewScanner(memory) var memTotal int var memFree int var memCached int var memBuffers int for scanner.Scan() { d := strings.Fields(scanner.Text()) switch d[0] { case "MemTotal:": m, err := strconv.Atoi(d[1]) if err != nil { return 0, 0, fmt.Errorf("cannot parse meminfo MemTotal: %v", err) } memTotal = m log.Debugln("got memTotal %v", memTotal) case "MemFree:": m, err := strconv.Atoi(d[1]) if err != nil { return 0, 0, fmt.Errorf("cannot parse meminfo MemFree: %v", err) } memFree = m log.Debugln("got memFree %v", memFree) case "Buffers:": m, err := strconv.Atoi(d[1]) if err != nil { return 0, 0, fmt.Errorf("cannot parse meminfo Buffers: %v", err) } memBuffers = m log.Debugln("got memBuffers %v", memBuffers) case "Cached:": m, err := strconv.Atoi(d[1]) if err != nil { return 0, 0, fmt.Errorf("cannot parse meminfo Cached: %v", err) } memCached = m log.Debugln("got memCached %v", memCached) } } if err := scanner.Err(); err != nil { log.Error("reading meminfo:", err) } outputMemUsed := (memTotal - (memFree + memBuffers + memCached)) / 1024 outputMemTotal := memTotal / 1024 return outputMemTotal, outputMemUsed, nil }
// MSA issues a Meshage State Annoucement, which contains a list of all the nodes connected to the broadcaster func (n *Node) MSA() { log.Debugln("MSA") // rate limit MSA spam to once per MSA timeout / 2 n.msaLock.Lock() defer n.msaLock.Unlock() if time.Now().Sub(n.lastMSA) < (n.msaTimeout / 2) { return } n.lastMSA = time.Now() n.clientLock.Lock() var clients []string for k, _ := range n.clients { clients = append(clients, k) } n.clientLock.Unlock() sort.Strings(clients) n.meshLock.Lock() diff := false if len(n.network[n.name]) != len(clients) { diff = true } else { for i, v := range n.network[n.name] { if clients[i] != v { diff = true break } } } if diff { log.Debugln("client list changed, recalculating topology") n.network[n.name] = clients n.updateNetwork = true } n.meshLock.Unlock() if log.WillLog(log.DEBUG) { log.Debug("client list: %v", clients) } if len(clients) == 0 { log.Debugln("not issuing MSA, no connected clients") return } m := &Message{ Source: n.name, CurrentRoute: []string{n.name}, ID: n.sequence(), Command: MSA, Body: clients, } n.flood(m) }
// enumerate bytes/second on all interfaces owned by minimega func bandwidthCollector() { var err error for { time.Sleep(BANDWIDTH_INTERVAL * time.Second) stats := make(map[string]*TapStat) // get a list of every tap we own for _, v := range vms { for _, net := range v.Config().Networks { stats[net.Tap] = &TapStat{ Bridge: net.Bridge, } } } // for each tap, get rx/tx bytes for k, v := range stats { v.RxStart, err = readNetStats(k, "rx") if err != nil { log.Debugln(err) continue } v.TxStart, err = readNetStats(k, "tx") if err != nil { log.Debugln(err) continue } v.Start = time.Now() } time.Sleep(1 * time.Second) // and again for k, v := range stats { v.RxStop, err = readNetStats(k, "rx") if err != nil { log.Debugln(err) continue } v.TxStop, err = readNetStats(k, "tx") if err != nil { log.Debugln(err) continue } v.Stop = time.Now() } bandwidthLock.Lock() bandwidthStats = stats bandwidthLock.Unlock() } }
// Transfer a single filepart to a temporary transfer directory. func (iom *IOMeshage) Xfer(filename string, part int64, from string) error { TID := genTID() c := make(chan *IOMMessage) err := iom.registerTID(TID, c) defer iom.unregisterTID(TID) if err != nil { // a collision in int64, we should tell someone about this log.Fatalln(err) } m := &IOMMessage{ From: iom.node.Name(), Type: TYPE_XFER, Filename: filename, TID: TID, Part: part, } _, err = iom.node.Set([]string{from}, m) if err != nil { return err } // wait for a response, or a timeout select { case resp := <-c: if log.WillLog(log.DEBUG) { log.Debugln("got part: ", resp.Part) } if resp.ACK { if log.WillLog(log.DEBUG) { log.Debugln("got part from: ", resp.From) } // write the part out to disk iom.transferLock.RLock() defer iom.transferLock.RUnlock() if t, ok := iom.transfers[filename]; ok { outfile := fmt.Sprintf("%v/%v.part_%v", t.Dir, filepath.Base(filename), part) err := ioutil.WriteFile(outfile, resp.Data, 0664) if err != nil { return err } } else { return fmt.Errorf("no transfer temporary directory to write to!") } } else { return fmt.Errorf("received NACK from xfer node") } case <-time.After(timeout): return fmt.Errorf("timeout") } return nil }
func httpClientRequest(h string, client *http.Client) (elapsed uint64) { httpSiteCache = append(httpSiteCache, h) if len(httpSiteCache) > MAX_CACHE { httpSiteCache = httpSiteCache[len(httpSiteCache)-MAX_CACHE:] } s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) url := httpSiteCache[r.Int31()%int32(len(httpSiteCache))] log.Debugln("http using url: ", url) // url notation requires leading and trailing [] on ipv6 addresses if isIPv6(url) { url = "[" + url + "]" } if !strings.HasPrefix(url, "http://") { url = "http://" + url } start := time.Now().UnixNano() resp, err := client.Get(url) if err != nil { log.Errorln(err) return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) stop := time.Now().UnixNano() elapsed = uint64(stop - start) log.Info("http %v %v %vns", h, url, elapsed) // make sure to grab any images, javascript, css extraFiles := parseBody(string(body)) for _, v := range extraFiles { log.Debugln("grabbing extra file: ", v) httpGet(url, v, false, client) } links := parseLinks(string(body)) if len(links) > 0 { httpSiteCache = append(httpSiteCache, links...) if len(httpSiteCache) > MAX_CACHE { httpSiteCache = httpSiteCache[len(httpSiteCache)-MAX_CACHE:] } } return }
// broadcastListener listens for broadcast connection solicitations and connects to // soliciting nodes. func (n *Node) broadcastListener() { listenAddr := net.UDPAddr{ IP: net.IPv4(0, 0, 0, 0), Port: n.port, } ln, err := net.ListenUDP("udp4", &listenAddr) if err != nil { log.Fatal("broadcastListener: %v", err) } for { d := make([]byte, 1024) read, _, err := ln.ReadFromUDP(d) if err != nil { log.Error("broadcastListener ReadFromUDP: %v", err) continue } data := strings.Split(string(d[:read]), ":") if len(data) != 3 { log.Warn("got malformed udp data: %v", data) continue } if data[0] != "meshage" { log.Warn("got malformed udp data: %v", data) continue } namespace := data[1] host := data[2] if namespace != n.namespace { log.Debug("got solicitation from namespace %v, dropping", namespace) continue } if host == n.name { log.Debugln("got solicitation from myself, dropping") continue } log.Debug("got solicitation from %v", host) // to avoid spamming the node with connections, only 1/8 of the // nodes should try to connect. If there are < 16 nodes, then // always try. if len(n.clients) > SOLICIT_LIMIT { s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) n := r.Intn(SOLICIT_RATIO) if n != 0 { log.Debugln("randomly skipping this solicitation") continue } } go n.dial(host, true) } }
// runCommand runs a command through a JSON pipe. func runCommand(cmd Command) chan *localResponse { conn, err := net.Dial("unix", path.Join(*f_minimega, "minimega")) if err != nil { log.Errorln(err) return nil } enc := json.NewEncoder(conn) dec := json.NewDecoder(conn) log.Debug("encoding command: %v", cmd) err = enc.Encode(cmd) if err != nil { log.Errorln("local command json encode: %v", err) return nil } log.Debugln("encoded command:", cmd) respChan := make(chan *localResponse) go func() { defer close(respChan) for { var r localResponse err = dec.Decode(&r) if err != nil { if err == io.EOF { log.Infoln("server disconnected") return } log.Errorln("local command json decode: %v", err) return } respChan <- &r if !r.More { log.Debugln("got last message") break } else { log.Debugln("expecting more data") } } }() return respChan }
// findRemoteVM attempts to find the VM ID of a VM by name or ID on a remote // minimega node. It returns the ID of the VM on the remote host or an error, // which may also be an error communicating with the remote node. func findRemoteVM(host, vm string) (int, string, error) { log.Debug("findRemoteVM: %v %v", host, vm) // check for our own host if host == hostname || host == Localhost { log.Debugln("host is local node") vm := vms.findVm(vm) if vm != nil { log.Debug("got vm: %v %v %v", host, vm.ID, vm.Name) return vm.ID, vm.Name, nil } } else { log.Debugln("remote host") var cmdStr string v, err := strconv.Atoi(vm) if err == nil { cmdStr = fmt.Sprintf(".filter id=%v .columns name,id vm info", v) } else { cmdStr = fmt.Sprintf(".filter name=%v .columns name,id vm info", v) } cmd := minicli.MustCompile(cmdStr) remoteRespChan := make(chan minicli.Responses) go func() { meshageSend(cmd, host, remoteRespChan) close(remoteRespChan) }() for resps := range remoteRespChan { // Find a response that is not an error for _, resp := range resps { if resp.Error == "" && len(resp.Tabular) > 0 { // Found it! row := resp.Tabular[0] // should be name,id name := row[0] id, err := strconv.Atoi(row[1]) if err != nil { log.Debug("malformed response: %#v", resp) } else { return id, name, nil } } } } } return 0, "", vmNotFound(vm) }
// Overlays copies any overlay directories indicated in c into the build // directory build_path. Overlays are copied in depth-first order, so that // the oldest parent overlay data is copied in first. This allows a child // to overwrite any overlay data created by a parent. func Overlays(buildPath string, c vmconfig.Config) error { // copy the overlays in order for i, o := range c.Overlays { log.Infoln("copying overlay:", o) var sourcePath string // check if overlay exists as absolute path or relative to cwd if _, err := os.Stat(o); os.IsNotExist(err) { // it doesn't, so we'll check relative to config file log.Debugln("overlay directory '%v' does not exist as an absolute path or relative to the current working directory.", o) var path string base := filepath.Base(o) // get base path of overlay directory if i == len(c.Overlays)-1 { // if this is the last overlay, we'll check relative to c.Path log.Debugln("non-parent overlay") path = filepath.Join(filepath.Dir(c.Path), base) } else { // if not, it's a parent overlay and we'll check relative to c.Parents[i] log.Debugln("parent overlay") path = filepath.Join(filepath.Dir(c.Parents[i]), base) } log.Debugln("checking path relative to config location: '%v'", path) if _, err := os.Stat(path); os.IsNotExist(err) { // check if we can find overlay relative to config file return err // nope } else { // yep sourcePath = path } } else { sourcePath = o } p := process("cp") cmd := exec.Command(p, "-r", "-v", sourcePath+"/.", buildPath) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } log.LogAll(stdout, log.INFO, "cp") log.LogAll(stderr, log.ERROR, "cp") err = cmd.Run() if err != nil { return err } } return nil }
func matchCIDR(cidr string, ip string) bool { if !strings.Contains(cidr, "/") { return false } d := strings.Split(cidr, "/") log.Debugln("subnet ", d) if len(d) != 2 { return false } if !isIPv4(d[0]) { return false } netmask, err := strconv.Atoi(d[1]) if err != nil { return false } network := toInt32(d[0]) ipmask := toInt32(ip) & ^((1 << uint32(32-netmask)) - 1) log.Debug("got network %v and ipmask %v", network, ipmask) if ipmask == network { return true } return false }
func (n *Node) handleMSA(m *Message) { log.Debug("handleMSA: %v", m) n.meshLock.Lock() defer n.meshLock.Unlock() if len(n.network[m.Source]) == len(m.Body.([]string)) { diff := false for i, v := range n.network[m.Source] { if m.Body.([]string)[i] != v { diff = true break } } if !diff { log.Debugln("MSA discarded, client data hasn't changed") return } } n.network[m.Source] = m.Body.([]string) if log.WillLog(log.DEBUG) { log.Debug("new network is: %v", n.network) } n.updateNetwork = true }
func httpClient(protocol string) { log.Debugln("httpClient") t := NewEventTicker(*f_mean, *f_stddev, *f_min, *f_max) transport := &http.Transport{ Proxy: http.ProxyFromEnvironment, Dial: func(network, addr string) (net.Conn, error) { dialer := &net.Dialer{ Timeout: 30 * time.Second, KeepAlive: 30 * time.Second, } return dialer.Dial(protocol, addr) }, } client := &http.Client{ Transport: transport, // TODO: max client read timeouts configurable? //Timeout: 30 * time.Second, } for { t.Tick() h, o := randomHost() log.Debug("http host %v from %v", h, o) httpClientRequest(h, client) httpReportChan <- 1 } }
func DecodeTightEncoding(buf io.Reader, rect *Rectangle) (err error) { // Read the reset control var control byte if err = binary.Read(buf, binary.BigEndian, &control); err != nil { err = errors.New("unable to decode reset control") return } // Figure out whether we need to reset any streams or not for i := 0; i < 4; i++ { if control&byte(i) != 0 { log.Debugln("reset stream", i) resetStream(i) } } if control&0x80 == 0 { err = DecodeBasicCompression(buf, control, rect) } else if control&0xf0 == 0x80 { err = DecodeFillCompression(buf, rect) } else if control&0xf0 == 0x90 { // TODO: Implement err = errors.New("unimplemented: jpeg compression") } else { err = errors.New("unknown pixel compression") } return }
// checkDegree broadcasts connection solicitations with exponential backoff until // the degree is met, then returns. checkDegree locks and will cause the caller to block // until the degree is met. It should only be run as a goroutine. func (n *Node) checkDegree() { // check degree only if we're not already running n.degreeLock.Lock() defer n.degreeLock.Unlock() var backoff uint = 1 s := rand.NewSource(time.Now().UnixNano()) r := rand.New(s) for n.numClients() < n.degree { log.Debugln("soliciting connections") b := net.IPv4(255, 255, 255, 255) addr := net.UDPAddr{ IP: b, Port: n.port, } socket, err := net.DialUDP("udp4", nil, &addr) if err != nil { log.Error("checkDegree: %v", err) break } message := fmt.Sprintf("meshage:%s:%s", n.namespace, n.name) _, err = socket.Write([]byte(message)) socket.Close() if err != nil { log.Error("checkDegree: %v", err) break } wait := r.Intn(1 << backoff) time.Sleep(time.Duration(wait) * time.Second) if backoff < 7 { // maximum wait won't exceed 128 seconds backoff++ } } }
// return names of bridges as shown in f_base/bridges. Optionally include // bridges that existed before minimega was launched func nukeBridgeNames(preExist bool) []string { var ret []string b, err := os.Open(filepath.Join(*f_base, "bridges")) if os.IsNotExist(err) { return nil } else if err != nil { log.Errorln(err) return nil } scanner := bufio.NewScanner(b) // skip the first line scanner.Scan() for scanner.Scan() { f := strings.Fields(scanner.Text()) log.Debugln(f) if len(f) <= 2 { continue } if (f[1] == "true" && preExist) || f[1] == "false" { ret = append(ret, f[0]) } } log.Debug("nukeBridgeNames got: %v", ret) return ret }
// PostBuildCommands invokes any commands listed in the postbuild variable // of a config file. It does so by copying the entire string of the postbuild // variable into a bash script under /tmp of the build directory, and then // executing it with bash inside of a chroot. Post build commands are executed // in depth-first order. func PostBuildCommands(buildPath string, c vmconfig.Config) error { for _, pb := range c.Postbuilds { log.Debugln("postbuild:", pb) tmpfile := buildPath + "/tmp/postbuild.bash" ioutil.WriteFile(tmpfile, []byte(pb), 0770) p := process("chroot") cmd := exec.Command(p, buildPath, "/bin/bash", "/tmp/postbuild.bash") stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } log.LogAll(stdout, log.INFO, "postbuild") log.LogAll(stderr, log.ERROR, "postbuild") err = cmd.Run() if err != nil { return err } os.Remove(tmpfile) } return nil }
// Get file info and return the number of parts in the file. If the filename is // a directory or glob, return the list of files the directory/glob contains. func (iom *IOMeshage) fileInfo(filename string) ([]string, int64, error) { glob, err := filepath.Glob(filename) if err != nil { return nil, 0, err } if len(glob) > 1 { // globs are recursive, figure out any directories var globsRet []string for _, v := range glob { rGlob, _, err := iom.fileInfo(v) if err != nil { return nil, 0, err } globsRet = append(globsRet, rGlob...) } return globsRet, 0, nil } f, err := os.Open(filename) if err != nil { return nil, 0, err } defer f.Close() // is this a directory fi, err := f.Stat() if err != nil { if log.WillLog(log.DEBUG) { log.Debugln("fileInfo error stat: ", err) } return nil, 0, err } if fi.IsDir() { // walk the directory and populate glob glob = []string{} err := filepath.Walk(filename, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } rel, err := filepath.Rel(iom.base, path) if err != nil { return err } glob = append(glob, rel) return nil }) if err != nil { return nil, 0, err } return glob, 0, nil } // we do have the file, calculate the number of parts parts := (fi.Size() + PART_SIZE - 1) / PART_SIZE // integer divide with ceiling instead of floor rel, err := filepath.Rel(iom.base, filename) return []string{rel}, parts, nil }
func httpTLSClient(protocol string) { log.Debugln("httpTLSClient") t := NewEventTicker(*f_mean, *f_stddev, *f_min, *f_max) transport := &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, Proxy: http.ProxyFromEnvironment, Dial: func(network, addr string) (net.Conn, error) { return net.Dial(protocol, addr) }, } client := &http.Client{ Transport: transport, } for { t.Tick() h, o := randomHost() log.Debug("https host %v from %v", h, o) elapsed := httpTLSClientRequest(h, client) if elapsed != 0 { log.Info("https %v %vns", client, elapsed) } httpTLSReportChan <- 1 } }
func httpTLSServer(p string) { log.Debugln("httpTLSServer") httpSetup() hitTLSChan = make(chan uint64, 1024) go hitTLSCounter() cert, key := generateCerts() //log.Fatalln(http.ListenAndServeTLS(":https", cert, key, nil)) server := &http.Server{ Addr: ":https", Handler: nil, } config := &tls.Config{} if config.NextProtos == nil { config.NextProtos = []string{"http/1.1"} } var err error config.Certificates = make([]tls.Certificate, 1) config.Certificates[0], err = tls.LoadX509KeyPair(cert, key) if err != nil { log.Fatalln(err) } conn, err := net.Listen(p, ":https") if err != nil { log.Fatalln(err) } tlsListener := tls.NewListener(conn, config) log.Fatalln(server.Serve(tlsListener)) }
// Debootstrap will invoke the debootstrap tool with a target build directory // in build_path, using configuration from c. func Debootstrap(buildPath string, c vmconfig.Config) error { p := process("debootstrap") // build debootstrap parameters var args []string args = append(args, "--variant=minbase") args = append(args, fmt.Sprintf("--include=%v", strings.Join(c.Packages, ","))) args = append(args, *f_branch) args = append(args, buildPath) args = append(args, *f_debian_mirror) log.Debugln("args:", args) cmd := exec.Command(p, args...) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } log.LogAll(stdout, log.INFO, "debootstrap") log.LogAll(stderr, log.ERROR, "debootstrap") err = cmd.Run() if err != nil { return err } return nil }
// BuildRootFS generates simple rootfs a from the stage 1 directory. func BuildRootFS(buildPath string, c vmconfig.Config) error { targetName := strings.Split(filepath.Base(c.Path), ".")[0] + "_rootfs" log.Debugln("using target name:", targetName) err := os.Mkdir(targetName, 0666) if err != nil { return err } p := process("cp") cmd := exec.Command(p, "-r", "-v", buildPath+"/.", targetName) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } log.LogAll(stdout, log.INFO, "cp") log.LogAll(stderr, log.ERROR, "cp") err = cmd.Run() if err != nil { return err } return nil }
// Handle incoming "get file info" messages by looking up if we have the file // and responding with the number of parts or a NACK. Also process directories // and globs, populating the Glob field of the IOMMessage if needed. func (iom *IOMeshage) handleInfo(m *IOMMessage) { // do we have this file, rooted at iom.base? resp := IOMMessage{ From: iom.node.Name(), Type: TYPE_RESPONSE, Filename: m.Filename, TID: m.TID, } glob, parts, err := iom.fileInfo(filepath.Join(iom.base, m.Filename)) if err != nil { resp.ACK = false } else if len(glob) == 1 && glob[0] == m.Filename { resp.ACK = true resp.Part = parts fi, err := os.Stat(filepath.Join(iom.base, m.Filename)) if err != nil { resp.ACK = false } else { resp.Perm = fi.Mode() & os.ModePerm } if log.WillLog(log.DEBUG) { log.Debugln("handleInfo found file with parts: ", resp.Part) } } else { // populate Glob resp.ACK = true resp.Glob = glob } _, err = iom.node.Set([]string{m.From}, resp) if err != nil { log.Errorln("handleInfo: sending message: ", err) } }
// client heartbeat sent periodically be periodic(). heartbeat() sends the // client info and any queued responses. func (c *Client) heartbeat() { log.Debugln("heartbeat") hostname, err := os.Hostname() if err != nil { log.Fatalln(err) } cin := &Client{ UUID: c.UUID, Arch: runtime.GOARCH, OS: runtime.GOOS, Hostname: hostname, } macs, ips := getNetworkInfo() cin.MAC = macs cin.IP = ips c.responseLock.Lock() cin.Responses = c.Responses c.Responses = []*Response{} c.responseLock.Unlock() m := &Message{ Type: MESSAGE_CLIENT, UUID: c.UUID, Client: cin, } log.Debug("heartbeat %v", cin) c.out <- m c.lastHeartbeat = time.Now() }
func (nf *Netflow) NewSocketWriter(network string, server string, mode int) error { log.Debugln("NewSocketWriter") if _, ok := nf.writers[server]; ok { return fmt.Errorf("netflow writer %v already exists", server) } conn, err := net.Dial(network, server) if err != nil { return err } c := make(chan *Packet, BUFFER_DEPTH) go func() { for { d := <-c if d == nil { break } if mode == ASCII { conn.Write([]byte(d.GoString())) } else { conn.Write(d.Raw) } } conn.Close() }() name := fmt.Sprintf("%v:%v", network, server) nf.registerWriter(name, c) return nil }
// NewNetflow returns a netflow object listening on port Netflow.Port func NewNetflow() (*Netflow, int, error) { log.Debugln("NewNetflow") nf := &Netflow{ writers: make(map[string]chan *Packet), } conn, err := net.ListenUDP("udp", &net.UDPAddr{}) if err != nil { return nil, -1, err } nf.conn = conn addr := nf.conn.LocalAddr() f := strings.SplitAfter(addr.String(), ":") if len(f) < 2 { return nil, -1, fmt.Errorf("invalid LocalAddr %v", addr) } p, err := strconv.Atoi(f[len(f)-1]) if err != nil { return nil, -1, err } go nf.reader() nf.port = p return nf, p, nil }
// stop and exit the reader goroutine for this object func (nf *Netflow) Stop() { log.Debugln("Stop") for k, _ := range nf.writers { nf.unregisterWriter(k) } nf.conn.Close() }
func transcode(in, out string) error { p := "ffmpeg" var args []string args = append(args, "-f") args = append(args, "mjpeg") args = append(args, "-r") args = append(args, "10") // minimega uses 10 frames per second args = append(args, "-i") args = append(args, fmt.Sprintf("http://localhost:%v/%v", *f_port, in)) args = append(args, out) log.Debugln("args:", args) cmd := exec.Command(p, args...) stdout, err := cmd.StdoutPipe() if err != nil { return err } stderr, err := cmd.StderrPipe() if err != nil { return err } log.LogAll(stdout, log.INFO, "ffmpeg") log.LogAll(stderr, log.INFO, "ffmpeg") err = cmd.Run() if err != nil { return err } return nil }