func (s *servStreams) write(stream uint32, b []byte) (int, error) { s.lckSend.Lock() defer s.lckSend.Unlock() buf := make([]byte, sepsize+binary.MaxVarintLen32*2) header(buf, stream, len(b)) n, err := s.conn.Write(append(buf, b...)) if e.Contains(err, "use of closed network connection") || e.Contains(err, "EOF") || e.Contains(err, "i/o timeout") { return n, e.Push(err, ErrNetwork) } return n, nil }
func (vs *VirtualServer) forceRestart() error { vs.status.Log(status.Verbose, "Forcing kill server %v.", vs.VirtualServerName) pid, err := util.ReadPidInt(vs.PidFile) if e.Contains(err, ErrNoSuchFile) { vs.status.Log(status.Verbose, "Server %v is about to restart. Pid file not found.", vs.VirtualServerName) err := vs.forceKill() if err != nil { msg := "Forcekill script failed in " + vs.VirtualServerName + " with error: " + err.Error() + ". Giving up restart server." msg += " Trace: " + e.Trace(e.Forward(err)) vs.status.Log(status.Verbose, msg) return nil } goto restart } else if err != nil { return e.Forward(err) } err = syscall.Kill(pid, 9) if err != nil { return e.Forward(err) } restart: err = vs.beforeStart() if err != nil { return e.Forward(err) } err = vs.restart() if err != nil { return e.Forward(err) } return nil }
func (d *Daemon) exec(cmd string, args ...string) error { done := make(chan error, 1) c := exec.Command(cmd, args...) c.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} err := c.Start() if err != nil { return e.Forward(err) } go func() { done <- c.Wait() }() select { case <-time.After(d.ExecTimeout): <-done // allow goroutine to exit err := c.Process.Kill() if err != nil { d.status.Log(status.Debug, "Failed to kill command %v for %v.", cmd, d.DaemonName) return e.Forward(err) } d.status.Log(status.Debug, "Command %v exec for %v was killed, timeout.", cmd, d.DaemonName) case err := <-done: if e.Contains(err, "exit status") { msg := "Command %v exec for %v exited with this error: %v" d.status.Log(status.Debug, msg, cmd, d.DaemonName, e.Trace(e.Forward(err))) return e.Forward(err) } else if err != nil { return e.Forward(err) } } return nil }
func (vs *VirtualServer) exec(cmd string, args ...string) error { done := make(chan error, 1) c := exec.Command(cmd, args...) err := c.Start() if err != nil { return e.Forward(err) } go func() { done <- c.Wait() }() select { case <-time.After(vs.ExecTimeout): <-done // allow goroutine to exit err := c.Process.Kill() if err != nil { vs.status.Log(status.Verbose, "Failed to kill command %v for %v.", cmd, vs.VirtualServerName) return e.Forward(err) } vs.status.Log(status.Verbose, "Command %v exec for %v was killed, timeout.", cmd, vs.VirtualServerName) return e.New("execution timeout") case err := <-done: if e.Contains(err, "exit status") { msg := "Command %v exec for %v existed with this error: %v" vs.status.Log(status.Verbose, msg, cmd, vs.VirtualServerName, e.Trace(e.Forward(err))) return e.Forward(err) } else if err != nil { return e.Forward(err) } } return nil }
// PingHttp connect a http or https server and try to // receive something. If the server return a code different // of 2xx, it will fail. Ignores insecure certificates. func PingHttp(url *url.URL) error { resp, err := httpClient.Get(url.String()) if e.Contains(err, "connection refused") { return e.Push(e.New(err), "get failed: connection refused") } else if err != nil { return e.Push(e.New(err), "get failed") } defer resp.Body.Close() buf := make([]byte, 4096) if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { n, err := resp.Body.Read(buf) if err != nil && err != io.EOF { return e.Forward(err) } buf = buf[:n] //status.Log(status.Protocol, "PingHttp status code is %v and received it from server: %v", resp.StatusCode, string(buf)) log.ProtoLevel().Printf("PingHttp status code is %v and received it from server: %v", resp.StatusCode, string(buf)) return e.New("returned status code %v, expected 2xx", resp.StatusCode) } _, err = resp.Body.Read(buf) if err != nil && err != io.EOF { return e.Forward(err) } return nil }
func (p *protoServer) Start() error { var err error if p.FnInst == nil { log.Tag("server", "gormethods").Errorf("FnInst function is nil!") return e.New("failed to init server") } if p.TlsConfig != nil { p.listener, err = tls.Listen(p.Proto, p.Addr, p.TlsConfig) } else { p.listener, err = reuse.Listen(p.Proto, p.Addr) } if err != nil { log.Tag("server", "gormethods").Errorf("Can't listen on interface %v proto %v: %v", p.Addr, p.Proto, e.Forward(err)) return e.Forward(err) } err = p.chmodSocket(0660) if err != nil { log.Tag("server", "gormethods", "proto").Errorf("Fail to chmod socket %v: %v", p.listener.Addr(), e.Forward(err)) return e.Forward(err) } p.closedListener = make(chan struct{}) go func() { defer func() { log.Tag("server", "gormethods", "proto").Println("Listener accept close.") p.closedListener <- struct{}{} }() for { // Ok1 conn, err := p.listener.Accept() if e.Contains(err, "use of closed network connection") { p.listener.Close() return } else if e.Contains(err, "too many open files") { p.listener.Close() log.Tag("server", "gormethods").Error(err) return } else if err != nil { p.listener.Close() log.Tag("server", "gormethods", "proto").Errorf("Accept for %v failed: %v", p.listener.Addr(), e.Forward(err)) return } go p.accept(conn) } }() return nil }
func (s *stream) Write(b []byte) (n int, err error) { s.lckSend.Lock() defer s.lckSend.Unlock() buf := make([]byte, offset3+len(b)) err = header(buf, s.num, len(b)) if err != nil { return 0, e.Forward(err) } copy(buf[offset3:], b) err = s.connect() if err != nil { return 0, e.Forward(err) } if s.connTimeout > 0 { err = s.conn.SetWriteDeadline(time.Now().Add(s.connTimeout)) if err != nil { return 0, e.Forward(err) } } n, err = s.conn.Write(buf) if err == io.EOF || e.Contains(err, "i/o timeout") || e.Contains(err, "closed") { s.lckSend.Unlock() s.invConn() s.lckSend.Lock() return 0, e.Forward(err) } else if err != nil { s.lckSend.Unlock() s.invConn() s.lckSend.Lock() return 0, e.Forward(err) } err = s.conn.SetWriteDeadline(time.Time{}) if err != nil { return 0, e.Forward(err) } n = n - offset3 return }
// PingUDP try to send something to UDP port // and receive some thing. If connections is refused // the host is considered down. If some other error, // besides timeout, the host is down. If timeoutr // I can't determine if the host is there or not. func PingUDP(url *url.URL) error { conn, err := net.DialTimeout("udp", url.Host, DialTimeout) if err != nil { return e.New(err) } defer conn.Close() err = conn.SetDeadline(time.Now().Add(Deadline)) _, err = conn.Write([]byte("Hi!")) if err != nil { return e.New(err) } buf := make([]byte, 100) _, err = conn.Read(buf) if e.Contains(err, "connection refused") { return e.Push(err, ErrNotAnwsered) } else if err != nil && !e.Contains(err, "i/o timeout") { return e.New(err) } return nil }
func (s *protoSession) connect() error { s.lckConn.Lock() defer s.lckConn.Unlock() var err error if s.status == connected { return nil } if s.status == dontreconnect { return e.New("can't reconect any more") } s.status = reconnect op := func() (bool, error) { var err error if s.tlsConfig == nil { s.conn, err = net.DialTimeout(s.proto, s.addr, s.dialTimeout) } else { s.conn, err = tls.DialWithDialer((&net.Dialer{Timeout: s.dialTimeout}), s.proto, s.addr, s.tlsConfig) } if e.Contains(err, "too many open files") { log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Dial error: %v", err) s.status = dontreconnect return false, e.Forward(err) } else if err != nil { log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Dial error: %v", err) return true, e.Forward(err) } return false, nil } exp := backoff.NewExponentialBackOff() err = backoff.Retry(op, exp) if err != nil { return e.Forward(err) } s.status = connected err = s.send(&ProtoAuth{ Auth: s.auth, Sess: s.sess, ProtoVersion: ProtoVersion, }) var resp ErrResp err = s.recv(&resp) if err != nil { return e.Forward(err) } if resp.Err != nil { return e.Forward(resp.Err) } //log.Tag("gormethods", "client", "proto").Printf("Connected to %v.", s.conn.RemoteAddr()) s.reader = bufio.NewReader(s.conn) return nil }
func (t *txMongoDb) Get(key string) (interface{}, error) { val := types.Make(t.tentry) inter := val.Interface() err := t.c.Find(bson.M{"key": key}).One(inter) if _, ok := err.(*mgo.QueryError); ok { return nil, e.New(ErrKeyNotFound) } else if e.Contains(err, "not found") { return nil, e.New(ErrKeyNotFound) } else if err != nil { return nil, e.New(err) } return inter, nil }
func (a *Server) sendResp(resp *Response, to string, tokey *rsa.PublicKey, addr *net.UDPAddr) { log.ProtoLevel().Tag("server", "discover").Printf("Send response from %v to %v", a.conn.LocalAddr(), addr) respBuf := bytes.NewBuffer([]byte{}) enc := gob.NewEncoder(respBuf) err := enc.Encode(resp) if err != nil { log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err))) a.sendErr(addr, e.Push(err, e.New("error enconding response"))) return } msg, err := NewMsg(a.Name, to, a.PrivateKey, tokey, respBuf.Bytes()) if err != nil { log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err))) a.sendErr(addr, e.Push(err, e.New("error creating new response message"))) return } respBuf = bytes.NewBuffer([]byte{}) enc = gob.NewEncoder(respBuf) err = enc.Encode(msg) if err != nil { log.Tag("discover", "server").Printf("Server - Protocol fail for %v with error: %v", addr, e.Trace(e.New(err))) a.sendErr(addr, e.Push(err, e.New("error enconding response"))) return } if respBuf.Len() > a.BufSize { log.Tag("discover", "server").Printf("Server - Protocol fail for %v message is too big (%v).", addr, respBuf.Len()) a.sendErr(addr, e.Push(err, e.New("response is too long %v", respBuf.Len()))) return } n, oob, err := a.conn.WriteMsgUDP(respBuf.Bytes(), nil, addr) if e.Contains(err, "use of closed network connection") { return } else if err != nil { log.Tag("discover", "server").Printf("Server - WriteMsgUDP (%v) failed: %v", addr, e.Trace(e.New(err))) return } if oob != 0 { log.Tag("discover", "server").Printf("Server - WriteMsgUDP to %v failed: %v, %v", addr, n, oob) return } if n != respBuf.Len() { log.Tag("discover", "server").Printf("Server - WriteMsgUDP to %v failed: %v, %v", addr, n, oob) return } }
func (vs *VirtualServer) beforeStart() error { vs.status.Log(status.Verbose, "Starting command %v.", vs.BeforeStartCmd) c := exec.Command(vs.BeforeStartCmd, vs.BeforeStartArgs...) buf, err := c.CombinedOutput() if e.Contains(err, "exit status") { msg := "Command " + vs.BeforeStartCmd + " exec for " + vs.VirtualServerName + " existed with this error: " + err.Error() msg += "\nBefore start output is:\n\n" msg += string(buf) vs.status.Log(status.Verbose, "Command "+vs.BeforeStartCmd+" exec failed.", msg) return e.Forward(err) } else if err != nil { return e.Forward(err) } vs.status.Log(status.Verbose, "Command %v done.", vs.BeforeStartCmd) return nil }
func (t *txBoltDb) Put(key string, data interface{}) error { buf, err := t.enc.Encode(data) if err != nil { return e.Forward(err) } defer func() { t.bufs = append(t.bufs, buf) }() err = t.b.Put([]byte(key), buf) if e.Contains(err, "tx not writable") { return e.New(ErrReadOnly) } else if err != nil { return e.New(err) } return nil }
func (d *Daemon) restartProcess() error { d.status.Log(status.Verbose, "Process %v is about to restart.", d.DaemonName) err := d.exec(d.RestartCmd, d.RestartArgs...) if e.Contains(err, "exit status") { d.status.Log(status.Verbose, "Restart command %v failed for %v with error: %v.", d.RestartCmd, d.DaemonName, e.Trace(e.Forward(err))) if d.ForceKillCmd != "" { err := d.forceKill() if err != nil { return e.Push(err, ErrGiveUpRestart) } } else { err := d.kill(syscall.SIGTERM) if e.Equal(err, ErrNoPid) { d.status.Log(status.Verbose, "Starting force kill for %v.", d.DaemonName) err := d.forceKill() if err != nil { return e.Push(err, ErrGiveUpRestart) } } else if err != nil { err := d.kill(syscall.SIGKILL) if err != nil { d.status.Log(status.Verbose, "Starting force kill for %v.", d.DaemonName) err := d.forceKill() if err != nil { return e.Push(err, ErrGiveUpRestart) } } } } d.status.Log(status.Verbose, "Process %v is about to restart.", d.DaemonName) err = d.exec(d.RestartCmd, d.RestartArgs...) if err != nil { err := d.forceKill() if err != nil { return e.Push(err, ErrGiveUpRestart) } d.status.Log(status.Verbose, "Process %v is about to restart, for the last time.", d.DaemonName) err = d.exec(d.RestartCmd, d.RestartArgs...) if err != nil { return e.Push(err, ErrGiveUpRestart) } } } else if err != nil { return e.Forward(err) } return nil }
// InfoDB reports the status of the database. // url is the url for the database and dbname is the name of the new database. func InfoDB(url *url.URL, dbname string) (*DatabaseInfo, error) { c := &client{url} code, data, err := c.get(dbname, "", nil) if e.Contains(err, Err404) { return nil, e.Push(err, ErrDbNotFound) } else if err != nil { return nil, e.Push(err, "can't get database information") } if code != http.StatusOK { return nil, e.New("can't get database information, wrong response code: %v", code) } di := new(DatabaseInfo) err = json.Unmarshal(data, di) if err != nil { return nil, e.Push(err, "can't get database information") } return di, nil }
func (d *Daemon) ping() error { for _, u := range d.Urls { if u == nil { return e.New(ErrUrlIsEmpty) } resolved, err := dns.ResolveUrl(u) if e.Contains(err, "invalid domain name") { resolved = u } else if err != nil { return e.Forward(err) } err = ping.Ping(resolved) if err != nil { d.status.LogAndEmail(status.Verbose, "", "Monitor ping failed for %v with error: %v", d.DaemonName, e.Trace(e.Forward(err))) return e.Push(err, ErrPingFailed) } } return nil }
func TestLevels(t *testing.T) { buf := bytes.NewBuffer([]byte{}) l := golog.New(buf, "", golog.LstdFlags) multi := NewMulti(NewSendToLogger(nil), DefFormatter, NewSendToLogger(l), DefFormatter) Log = New(multi, false).Domain("test") Log.SetLevel("all", DebugPrio) Println("oi") test(t, buf, "oi") ProtoLevel().Println("blá") err := testerr(buf, "blá") if err != nil && !e.Contains(err, "log didn't log") { t.Fatal(e.Trace(e.Forward(err))) } else if err == nil { t.Fatal("nil error") } }
// DeleteDB removes the database. url is the url for the database and dbname is the name of // the new database. func DeleteDB(url *url.URL, dbname string) error { c := &client{url} code, resp, err := c.delete(dbname, "", nil) if e.Contains(err, Err404) { return e.Push(err, ErrDbNotFound) } else if err != nil { return e.Push(err, "can't delete the database") } if code != http.StatusOK { return e.New("can't delete the database, wrong response code: %v", code) } ok := new(Ok) err = json.Unmarshal(resp, ok) if err != nil { return e.Push(err, e.New("can't unserialize the response: %v", string(resp))) } if !ok.Ok { return e.New("can't delete the database: wrong response") } return nil }
func TestPtr(t *testing.T) { host, err := LookupIp("200.149.119.183") if err != nil { t.Fatal(err) } if host != "183.119.149.200.in-addr.arpa.telemar.net.br" { t.Fatal("wrong host") } host, err = LookupIp("2800:3f0:4004:800::1013") if err != nil && !e.Contains(err, "can't resolve") { t.Fatal(err) } host, err = LookupIp("127.0.0.1") if err != nil { t.Fatal(err) } if host != "localhost" { t.Fatal("wrong host") } }
func (c *cursorBoltDb) Del() (err error) { defer func() { if r := recover(); r != nil { er, ok := r.(error) if !ok { return } if e.Contains(er, "runtime error: index out of range") { err = e.New(ErrKeyNotFound) return } } }() if !c.b.Writable() { return e.New(ErrReadOnly) } err = c.c.Delete() if err != nil { return e.New(err) } return }
func Put(tx *bolt.Tx, bucket []byte, keys [][]byte, data []byte) error { var err error var buf []byte var b *bolt.Bucket b, err = tx.CreateBucketIfNotExists(bucket) if err != nil { return e.Forward(err) } if len(keys) == 0 { return e.New("no keys") } if len(keys) >= 2 { for i := 0; i < len(keys)-1; i++ { buf = b.Get(keys[i]) if buf == nil { id, err := rand.Uuid() if err != nil { return e.Forward(err) } buf = []byte(id) err = b.Put(keys[i], buf) if err != nil { return e.Forward(err) } } b, err = tx.CreateBucket(buf) if e.Contains(err, "bucket already exists") { b = tx.Bucket(buf) } else if err != nil { return e.Forward(err) } } } err = b.Put(keys[len(keys)-1], data) if err != nil { return e.Forward(err) } return nil }
func NewCacheDisk(filename string, perm os.FileMode, opt *bolt.Options, images int) (*CacheDisk, error) { var err error cd := &CacheDisk{ images: images, } cd.db, err = bolt.Open(filename, perm, opt) if err != nil { return nil, e.Forward(err) } err = cd.db.Update(func(tx *bolt.Tx) error { for _, b := range buckets { _, err := tx.CreateBucket([]byte(b)) if err != nil && !e.Contains(err, "bucket already exists") { return e.New(err) } } return nil }) if err != nil { return nil, e.Forward(err) } return cd, nil }
func (s *Server) protoDestroy(conn InstConn) (err error) { defer func() { if err != nil { err = conn.Encoder().Encode(&respErr{Err: err}) if err != nil { log.ProtoLevel().Tag("server", "gormethods").Printf("Encode %v -> %v (%v) error: %v", conn.RemoteAddr(), conn.LocalAddr(), conn.StreamNum(), err) err = e.Push(err, ErrWire) } } }() err = s.Insts.Delete(conn.SessionName(), conn.InstanceName()) if err != nil && !e.Contains(err, "instance not found") { log.Tag("server", "gormethods").Errorf("Can't remove the instance %v/%v: %v", conn.SessionName(), conn.InstanceName(), e.Forward(err)) err = e.Forward(err) return } err = conn.Encoder().Encode(&respErr{Err: nil}) if err != nil { log.ProtoLevel().Tag("server", "gormethods").Printf("Encode %v -> %v (%v) error: %v", conn.RemoteAddr(), conn.LocalAddr(), conn.StreamNum(), e.Forward(err)) err = e.Push(err, ErrWire) } return }
func (t *txMongoDb) Put(key string, data interface{}) error { if !t.writeble { return e.New(ErrReadOnly) } n, err := t.c.Find(bson.M{"key": key}).Count() if err != nil { return e.New(err) } if n >= 1 { err := t.c.Update(bson.M{"key": key}, data) if e.Contains(err, "not found") { return e.New(ErrKeyNotFound) } else if err != nil { return e.New(err) } return nil } err = t.c.Insert(data) if err != nil { return e.New(err) } return nil }
func TestFilter(t *testing.T) { Log = New( Filter( NewWriter(buf), Not(Op(Cnts, "msg", "not log")), ).F(DefFormatter), false, ).Domain("test") Println("log") test(t, buf, "log") Println("not log") err := testerr(buf, "not log") if err != nil && !e.Contains(err, "EOF") { t.Fatal(e.Trace(e.Forward(err))) } else if err == nil { t.Fatal("nil") } Println("log2") test(t, buf, "log2") }
func sortIncoming(reader *bufio.Reader, bufs *buffers, domain string) error { scanner := scan.NewScanner(reader, 1e9) split := func(buf []byte, atEOF bool) (advance int, token []byte, err error) { status := 0 start := -1 end := -1 for i, b := range buf { switch { case status == 0: if b == 0xAA { start = i status++ continue } status = 0 case status >= 1 && status <= sepsize-2: if b == 0xAA { status++ continue } status = 0 case status == sepsize-1: if b == 0xAA { end = i status++ break } status = 0 } } if start == -1 || end == -1 { if atEOF { return 0, nil, io.EOF } return 0, nil, nil } end++ if end > 1 && len(buf) == end { if atEOF { return 0, nil, io.EOF } return 0, nil, nil } _, size, err := parsePkg(buf[start:]) if e.Equal(err, ErrMissData) { // Buffer is too small to parser, wait more data return 0, nil, nil } else if err != nil { if atEOF { return 0, nil, io.EOF } return 0, nil, nil } adv := start + offset3 + int(size) if adv > len(buf[start:]) { if atEOF { return 0, nil, io.EOF } return 0, nil, nil } return adv, buf[start:adv], nil } scanner.Split(split) for scanner.Scan() { buf := scanner.Bytes() stream, size, err := parsePkg(buf) if err != nil { log.ProtoLevel().Tag("gormethods", "proto", domain).Printf("Invalid stream: %v", err) bufs.ErrorAll(e.Forward(err)) continue } log.ProtoLevel().Tag("gormethods", "proto", domain).Printf("Read (%v): %v", stream, pkg(buf)) end := offset3 + int(size) if end != len(buf) { log.Tag("gormethods", "proto", domain).Error("Parser error!") return e.New("parser error") } b := buf[offset3:end] err = bufs.Write(uint32(stream), b) if err != nil { log.ProtoLevel().Tag("gormethods", "proto", domain).Printf("Can't store the data for stream %v: %v", stream, err) bufs.Error(uint32(stream), e.Forward(err)) continue } log.ProtoLevel().Tag("gormethods", "proto", domain).Printf("Data write to buffer. Stream: %v", stream) } log.ProtoLevel().Tag("gormethods", "proto", domain).Printf("Scanner quit.") err := scanner.Err() if e.Contains(err, "use of closed network connection") || err == io.EOF || e.Contains(err, "i/o timeout") { return e.Push(err, ErrNetwork) } else if err != nil { log.Tag("gormethods", "proto", domain).Errorf("Error scaning the data. Err: %v", err) return e.Forward(err) } return nil }
func Init(d *Daemon) (monitors.Monitor, error) { pid, err := util.ReadPidInt(d.PidFile) if err != nil && !e.Contains(err, "no such file or directory") { return nil, e.Forward(err) } if d.DaemonName == "" { return nil, e.New("empty daemon name") } if d.RestartCmd == "" { return nil, e.New("empty restart command") } if d.RestartArgs == nil { return nil, e.New("restart arguments is invalid") } if d.PidFile == "" { return nil, e.New("empty pid file") } if d.Sleep <= 0 { return nil, e.New("sleep is equal or less than zero") } if d.Tries < 0 { return nil, e.New("tries is equal or less than zero") } if d.Prio < 0 { return nil, e.New("prio have to be greater or equal to zero") } if d.Queue == nil { return nil, e.New("invalid queue") } if d.ExecTimeout <= 0 { return nil, e.New("exectution timeout is greater than zero") } d.MonitorBase = base.New() d.pid = pid d.killMonitor = make(chan bool) d.running = true d.status = status.NewStatuses(d.DaemonName, d.Email, definitions.LengthStatusHistory, status.NewStatus, d.SendEvent, nil) d.fswatcher, err = fsnotify.NewWatcher() if err != nil { return nil, e.Forward(err) } go func() { F: for { select { case ev := <-d.fswatcher.Event: if ev == nil { //watcher closed return } if ev.Name != d.PidFile { continue F } if ev.IsDelete() { d.pid = -1 } else if !(ev.IsCreate() && ev.IsModify()) { continue F } d.changePid() case err := <-d.fswatcher.Error: if err != nil { d.status.Log(status.Verbose, "Pid file %v watcher error: %v", d.PidFile, e.Trace(e.Forward(err))) } } } }() err = d.fswatcher.Watch(filepath.Dir(d.PidFile)) if err != nil { return nil, e.Push(err, e.New("invalid pid file %v", d.PidFile)) } d.monitor() return d, nil }
func (a *Alive) Connect() error { if a.events == nil { a.events = make(chan event.Event) } a.closePing = make(chan bool) resolved, err := dns.ResolveUrl(a.Url) if e.Contains(err, "invalid domain name") { resolved = a.Url } else if err != nil { a.setConnected(false) return e.Forward(err) } for i := 0; i < a.Tries; i++ { a.conn, err = net.Dial(resolved.Scheme, resolved.Host) if e.Contains(err, definitions.NetErrorConnectionRefused) || e.Contains(err, definitions.NetErrorTimeOut) || e.Contains(err, definitions.ErrCheckIsAliveNoRoute) || e.Contains(err, definitions.ErrCheckIsAliveNoAnswerFromResolver) { time.Sleep(a.Wait) continue } else if err != nil { a.setConnected(false) return e.Forward(err) } break } if a.conn == nil { a.setConnected(false) if err != nil { return e.Push(e.New(err), definitions.ErrCheckIsAliveCantConnect) } return e.New(definitions.ErrCheckIsAliveCantConnect) } a.setConnected(true) dec := gob.NewDecoder(a.conn) enc := gob.NewEncoder(a.conn) go func() { defer func() { if a.conn != nil { a.conn.Close() } a.setConnected(false) }() for { select { case <-time.After(a.Wait): err := a.conn.SetWriteDeadline(time.Now().Add(5 * time.Second)) if err != nil { return } err = enc.Encode("ping") if err != nil { a.Statuses.Log(status.Verbose, "Alive: Ping encode error: %v", err) return } case <-a.closePing: return } } }() go func() { defer func() { if a.conn != nil { a.conn.Close() } a.setConnected(false) }() for { var typ string err := dec.Decode(&typ) if err != nil { a.Statuses.Log(status.Verbose, "Alive: Decode error: %v", err) return } t, err := types.GetType(typ) if err != nil { a.Statuses.Log(status.Verbose, "Alive: GetType error: %v", err) return } ptr := types.Make(reflect.PtrTo(t)) err = dec.DecodeValue(ptr) if err != nil { a.Statuses.Log(status.Verbose, "Alive: DecodeValue error: %v", err) return } val := reflect.Indirect(ptr) if val.IsValid() { a.events <- val.Interface().(event.Event) } } }() return nil }
// Do method starts a goroutine that waites for the clients, and make responses with the // Protocol function. func (a *Server) Do() error { if a.Port == "" { a.Port = "0" } if a.BufSize <= 0 { a.BufSize = 1024 } if a.Duration == 0 { a.Duration = 24 * time.Hour } if a.Name == "" { a.Name = "master" } a.seq = make([]*net.UDPAddr, 0) a.ctxs = newContexts(a.Duration, 300*time.Second) a.InitMCast() err := a.getInt() if err != nil { return e.Forward(err) } a.conn, err = a.bind() if err != nil { return e.Forward(err) } go func() { for { buf := make([]byte, a.BufSize) n, addr, err := a.conn.ReadFromUDP(buf) if e.Contains(err, "use of closed network connection") { return } else if err != nil { log.Tag("discover", "server").Printf("Server - ReadFromUDP (%v) failed: %v", addr, e.Trace(e.New(err))) continue } dec := gob.NewDecoder(bytes.NewReader(buf[:n])) var msg Msg err = dec.Decode(&msg) if err != nil { log.Tag("discover", "server").Printf("Can't decode data from %v.", addr) continue } pubkey, err := a.PubKeys.Get(msg.From) if err != nil { log.Tag("discover", "server").Printf("Invalid %v sender from %v.", msg.From, addr) continue } buf, err = msg.Message(pubkey, a.PrivateKey) if err != nil { log.Tag("discover", "server").Printf("Invalid message from %v: %v.", addr, err) continue } if len(buf) < binary.MaxVarintLen16 { log.Tag("discover", "server").Printf("Read insulficient data from %v.", addr) continue } typ, b := binary.Uvarint(buf[:binary.MaxVarintLen16]) if b <= 0 { log.Tag("discover", "server").Print("Invalid package type from %v.", addr) continue } t := msgType(typ) log.ProtoLevel().Tag("server", "discover").Printf("Received %v request from %v.", t, addr) switch t { case protoConfirm: go a.confirm(addr, msg.From, pubkey, buf[binary.MaxVarintLen16:]) case protoReq: go a.request(addr, msg.From, pubkey, buf[binary.MaxVarintLen16:]) case protoKeepAlive: go a.keepalive(addr, msg.From, pubkey, buf[binary.MaxVarintLen16:]) default: log.Tag("discover", "server").Errorf("Protocol error. (%v)", typ) } } }() return nil }
func (c *Client) client(addr string) (*Response, error) { ip, err := ipport(c.Interface, addr, "0") if err != nil { return nil, e.Push(err, ErrCantFindInt) } client, err := net.ResolveUDPAddr("udp", ip) if err != nil { return nil, e.Push(err, ErrCantFindInt) } c.conn, err = net.ListenUDP("udp", client) if err != nil { return nil, e.Push(err, ErrCantFindInt) } var dst *net.UDPAddr if c.iface.Flags&net.FlagLoopback == net.FlagLoopback { ip, err := ipport(c.Interface, addr, c.Port) if err != nil { return nil, e.Push(err, ErrCantFindInt) } dst, err = net.ResolveUDPAddr("udp", ip) if err != nil { return nil, e.Push(err, ErrCantFindInt) } } else if !c.NotMulticast && c.iface.Flags&net.FlagMulticast == net.FlagMulticast { dst, err = c.multicast(c.conn.LocalAddr()) if err != nil { return nil, e.Push(err, ErrCantFindInt) } } else if c.iface.Flags&net.FlagBroadcast == net.FlagBroadcast { dst, err = broadcast(c.conn.LocalAddr(), c.Port) if err != nil { return nil, e.Push(err, ErrCantFindInt) } } else { return nil, e.Push(e.New("interface isn't suported: %v", c.iface.Flags), ErrCantFindInt) } log.ProtoLevel().Tag("discover", "client").Printf("Local ip %v.", c.conn.LocalAddr()) log.ProtoLevel().Tag("discover", "client").Printf("Try to contact server in %v.", dst) now := time.Now() end := now.Add(c.Timeout) for d := now; d.Before(end) || d.Equal(end); d = time.Now() { req, err := c.Request(dst) if err != nil { return nil, e.Forward(err) } req.Id = c.Id req.Ip = c.conn.LocalAddr().String() err = c.encode(protoReq, req, dst) if e.Contains(err, "i/o timeout") { log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err) continue } else if err != nil { return nil, e.Forward(err) } resp, err := c.response() if e.Contains(err, "i/o timeout") { log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err) continue } else if err != nil { return nil, e.Forward(err) } c.Id = resp.Id err = c.encode(protoConfirm, resp.Id, dst) if e.Contains(err, "i/o timeout") { log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err) continue } else if err != nil { return nil, e.Forward(err) } rp, err := c.response() if e.Contains(err, "i/o timeout") { log.Errorf("Error %v -> %v: %v", c.conn.LocalAddr(), dst, err) continue } else if err != nil { return nil, e.Forward(err) } if rp.Id != resp.Id { return nil, e.New("protocol fail wrong response") } go func(dst *net.UDPAddr) { for { select { case <-time.After(c.Keepalive): log.ProtoLevel().Tag("client", "discover").Printf("Send keep alive to %v", dst) err := c.keepalive(dst) if err != nil { log.Tag("client", "discover").Errorf("Keep alive to %v failed: %v", dst, err) return } case ch := <-c.stopKa: ch <- struct{}{} return } } }(dst) return resp, nil } return nil, e.New("can't find the server") }