func (s *protoSession) recv(val interface{}) error { if s.status != connected { return e.New(ErrNoConn) } if s.connTimeout > 0 { err := s.conn.SetReadDeadline(time.Now().Add(s.connTimeout)) if err != nil { log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Send: deadline error: %v", err) s.status = reconnect return e.Forward(err) } } dec := msgpack.NewDecoder(s.conn) err := dec.Decode(val) if err != nil { s.status = reconnect log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Recv: connect error: %v", err) s.conn.SetReadDeadline(time.Time{}) return e.Forward(err) } err = s.conn.SetReadDeadline(time.Time{}) if err != nil { log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Send: deadline error: %v", err) s.status = reconnect return e.Forward(err) } return nil }
func (c *clone) Init(inst string) error { if c.Num <= 0 { return e.New("number of clones invalid") } if c.Session == nil { return e.New("nil Session") } if c.Num > c.MaxNum { return e.New("number of initial streams is greater than the maximun") } c.inst = inst c.once.Do(func() { c.conns = make([]connInst, 0, c.Num) log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Init clones.") for i := 0; i < c.Num; i++ { conn, err := c.Session.NamedInstance(c.inst) if err != nil { log.ProtoLevel().Tag("gormethods", "client", "clone").Printf("New instance failed: %v.", err) continue } c.conns = append(c.conns, conn) } }) return nil }
func (p *protoSession) sortIncoming() { go func() { defer func() { log.ProtoLevel().Tag("gormethods", "client", "proto").Println("Stopping sorting income data.") p.closed <- struct{}{} }() F: for { const SleepReconect = 10 * time.Second err := p.connect() if err != nil { log.Tag("gormethods", "client", "proto").Errorf("Connect error: %v", err) p.bufs.ErrorAll(e.Forward(err)) time.Sleep(SleepReconect) continue F } err = sortIncoming(p.reader, p.bufs, "client") if err != nil { p.lckConn.Lock() status := p.status p.lckConn.Unlock() log.ProtoLevel().Tag("gormethods", "client", "proto").Printf("Stopping income data. Status: %v", status) if status == dontreconnect || status == closed { break F } log.Tag("gormethods", "client", "proto").Errorf("Parsing incoming data from %v to %v failed: %v", p.conn.LocalAddr(), p.conn.RemoteAddr(), e.Trace(e.Forward(err))) p.invConn() p.bufs.ErrorAll(e.Forward(err)) time.Sleep(SleepReconect) continue F } time.Sleep(SleepReconect) } }() }
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 }
//Close the associated gorotine and all queued wait channels. func (b *Barrier) Close() { if b.isclosed { return } if <-b.chIsShutdown { log.ProtoLevel().Tag("gormethods", "barrier").Printf("barrier shutdown requested, ignore close.") return } ch := make(chan struct{}) b.chclose <- ch //close(b.chclose) <-ch log.ProtoLevel().Tag("gormethods", "barrier").Printf("barrier close ok, chan returned") }
func (c *clone) Return(conn connInst) error { c.lck.Lock() defer c.lck.Unlock() if len(c.conns) >= c.MaxNum { err := conn.Close() if err != nil { return e.Forward(err) } log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Pool is full, discart.") return nil } log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Put clone back in the pool.") c.conns = append(c.conns, conn) return nil }
func (c *Client) response() (*Response, error) { log.ProtoLevel().Tag("client", "discover").Printf("Waiting response...") buf := make([]byte, c.BufSize) err := c.conn.SetDeadline(time.Now().Add(c.Deadline)) if err != nil { return nil, e.New(err) } n, addr, err := c.conn.ReadFromUDP(buf) if err != nil { return nil, e.New(err) } log.ProtoLevel().Tag("client", "discover").Printf("Response from %v with size %v.", addr, n) err = c.conn.SetDeadline(time.Time{}) if err != nil { return nil, e.New(err) } dec := gob.NewDecoder(bytes.NewReader(buf[:n])) var msg Msg err = dec.Decode(&msg) if err != nil { return nil, e.Push(err, e.New("error decoding response")) } if msg.Err != nil { return nil, e.Forward(msg.Err) } if msg.From != c.ServerName { return nil, e.New("wrong server name") } if msg.To != c.Name { return nil, e.New("message isn't for me") } buf, err = msg.Message(c.ServerKey, c.PrivateKey) if err != nil { return nil, e.Push(err, e.New("error decrypting response")) } dec = gob.NewDecoder(bytes.NewReader(buf)) var resp Response err = dec.Decode(&resp) if err != nil { return nil, e.Push(err, e.New("error decoding response")) } return &resp, nil }
func (c *client) Init() error { var err error c.session, err = openSession(c.Proto, c.Addr, c.TlsConfig, c.SessionName, c.Auth, c.DialTimeout, c.ConnTimeout) if err != nil { return e.Forward(err) } c.clones = &clones{ Num: c.NumClones, MaxNum: c.MaxNumClones, } err = c.clones.Init() if err != nil { return e.Forward(err) } if c.KeepAlive == 0 { return nil } go func() { for { time.Sleep(c.KeepAlive) err := c.session.Keepalive() if err != nil { log.ProtoLevel().Tag("gormethods", "client", "keepalive").Printf("Keepalive failed: %v", err) } } }() return nil }
func writeError(s *servStreams, num uint32, err error) { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't write new stream reponse for %v: %v", s.conn.RemoteAddr(), err) if num != 0 && num != keepAliveStream { err = s.streams.Deactivate(num) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't deactivate stream %v: %v", num, err) } err = s.bufs.Delete(num) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't delete stream %v: %v", num, err) } } s.acceptFifo <- &newAccept{ err: e.New(ErrStreamClosed), } }
func (c *clone) Request() (connInst, error) { c.lck.Lock() defer c.lck.Unlock() if len(c.conns) <= 0 { conn, err := c.Session.NamedInstance(c.inst) if err != nil { return nil, e.Forward(err) } log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Pool is empty, creating another clone.") return conn, nil } clone := c.conns[len(c.conns)-1] c.conns = c.conns[:len(c.conns)-1] log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Get object from pool.", len(c.conns)) return clone, 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 newServStreams(conn net.Conn, session string, auth auth.Auth, p *protoServer) (*servStreams, error) { s := &servStreams{ p: p, conn: conn, bufs: newBuffers(numBuffers), streams: newActiveStreams(), acceptFifo: make(chan *newAccept, p.FifoLength), session: session, auth: auth, streamCount: 1, } reader := bufio.NewReader(s.conn) go func() { defer func() { s.acceptFifo <- &newAccept{ err: e.New(ErrStreamClosed), } log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Stop sort incoming.") }() for { err := sortIncoming(reader, s.bufs, "server") if e.Equal(err, ErrNetwork) || err == nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("sortIncoming stoped with isclose = %v and error: %v", s.isclose, err) s.lck.Lock() if s.isclose { s.lck.Unlock() return } s.isclose = true s.bufs.ErrorAll(e.New("conn close")) s.bufs.ReqShutdownAll() s.lck.Unlock() return } else if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("sortIncoming failed: %v", err) continue } } }() s.zero() s.keepalive() return s, nil }
func (s *Server) protocol(conn InstConn) error { dec := conn.Decoder() defer func() { num := conn.StreamNum() s.lck.Lock() if _, found := s.connections[num]; found { delete(s.connections, num) } s.lck.Unlock() conn.Close() log.DebugLevel().Tag("server", "gormethods", "protocol").Println("protocol close") }() for { s.lck.Lock() connection, found := s.connections[conn.StreamNum()] if !found { connection = &Connection{} s.connections[conn.StreamNum()] = connection } connection.ttl = time.Now().Add(s.Ttl) connection.conn = conn s.lck.Unlock() var req msgtypes.MessageType // se fechar a conn do outro lado deve acontecer um err aqui err := dec.Decode(&req) if e.Find(err, io.EOF) >= 0 { return e.Forward(err) } else if err != nil { log.DebugLevel().Tag("server", "gormethods").Printf("Decode %v -> %v (%v) error: %v", conn.RemoteAddr(), conn.LocalAddr(), conn.StreamNum(), e.Trace(e.Forward(err))) return e.Forward(err) } switch req { case msgtypes.Call: err = s.protoCall(conn) if e.Find(err, ErrWire) >= 0 { return e.Forward(err) } case msgtypes.Destroy: err = s.protoDestroy(conn) if e.Find(err, ErrWire) >= 0 { return e.Forward(err) } return nil case msgtypes.Channel: err = s.protoChannel(conn) if e.Find(err, ErrWire) >= 0 { return e.Forward(err) } return nil default: log.ProtoLevel().Tag("server", "gormethods").Printf("Protocol fail from %v -> %v (%v) sent: %v", conn.RemoteAddr(), conn.LocalAddr(), conn.StreamNum(), req) } } }
func finalizer(client ClientInt) { log.ProtoLevel().Tag("gormethods", "client").Printf("Finalize %v, %v", client.SessionName(), client.InstanceName()) err := client.Destroy() if err != nil { log.Error("Client finalizer failed:", err) } err = client.CloseClient() if err != nil { log.Error("Client finalizer failed:", err) } }
func (s *servStreams) keepalive() { go func() { defer func() { log.ProtoLevel().Tag("gormethods", "server", "proto").Println("Stop keepalive.") }() buf := make([]byte, payloadSize) for { n, err := s.bufs.Read(keepAliveStream, buf) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't read from stream %v: %v", keepAliveStream, err) break } if n != payloadSize { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Not enougth data from stream %v", keepAliveStream) continue } cmd, _, err := parseCmd(buf) if err != nil { continue } switch cmd { case keepAlive: buf := newStreamResponse(ok, keepAliveStream) for count := 0; count < len(buf); { n, err := s.write(keepAliveStream, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, keepAliveStream, e.Forward(err)) return } else if err != nil { writeError(s, keepAliveStream, e.Forward(err)) break } count += n } default: log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Protocol error on stream %v: %v", keepAliveStream, cmd) continue } } }() }
func (c *clone) Close() (err error) { c.lck.Lock() defer c.lck.Unlock() log.ProtoLevel().Tag("gormethods", "client", "clone").Println("Close clone.") for _, clone := range c.conns { er := clone.Close() if er != nil { err = e.Push(err, e.Forward(er)) } } return }
func (c *Client) encode(typ msgType, val interface{}, dst *net.UDPAddr) error { log.ProtoLevel().Tag("client", "discover").Printf("Send request (%v) to %v from %v.", typ, dst, c.conn.LocalAddr()) reqBuf := bytes.NewBuffer([]byte{}) buf := make([]byte, binary.MaxVarintLen16) binary.PutUvarint(buf, uint64(typ)) n, err := reqBuf.Write(buf) if err != nil { return e.Push(err, "error enconding message type") } if n != len(buf) { return e.Push(err, "error enconding message type") } enc := gob.NewEncoder(reqBuf) err = enc.Encode(val) if err != nil { return e.Push(err, e.New("error encoding")) } msg, err := NewMsg(c.Name, c.ServerName, c.PrivateKey, c.ServerKey, reqBuf.Bytes()) if err != nil { return e.Push(err, "erro cryptographing the value") } reqBuf = bytes.NewBuffer([]byte{}) enc = gob.NewEncoder(reqBuf) err = enc.Encode(msg) if err != nil { return e.Push(err, e.New("error encoding")) } if reqBuf.Len() > c.BufSize { return e.New("value to encode is too big %v", reqBuf.Len()) } err = c.conn.SetDeadline(time.Now().Add(c.Deadline)) if err != nil { return e.New(err) } _, _, err = c.conn.WriteMsgUDP(reqBuf.Bytes(), nil, dst) if err != nil { return e.New(err) } err = c.conn.SetDeadline(time.Time{}) if err != nil { return e.New(err) } return 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 (p *protoSession) Close() error { p.lckConn.Lock() p.status = closed err := p.conn.Close() if err != nil { p.lckConn.Unlock() return e.Forward(err) } p.lckConn.Unlock() //p.bufs.ErrorAll(e.New("conn close")) p.bufs.DeleteAll() //<-p.closed log.ProtoLevel().Tag("gormethods", "client", "proto").Print("Client conn close.") return 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 } }
// Watchdog setup the watchdog and start then. This functoin will // comunicate with systemd sending the pings to it, if this fails // to send the ping systemd will reatart this daemon. func Watchdog() (stop chan struct{}, err error) { // Check if systemd exist. if !util.IsRunningSystemd() { return nil, e.New(ErrNotRunning) } // Get the periode and check if watchdog is on for this daemon wPeriodeµsec := os.Getenv("WATCHDOG_USEC") if wPeriodeµsec == "" { return nil, e.New(ErrNoWatchdog) } wPerInt64, err := strconv.ParseInt(wPeriodeµsec, 10, 32) if err != nil { return nil, e.Push(err, ErrInvPeriode) } wPerHalf := time.Duration(int(wPerInt64)/2) * time.Microsecond if wPerHalf <= 0 { return nil, e.New(ErrInvInterval) } log.Tag("systemd", "watchdog").Printf("Starting the watchdog with interval of %v.", wPerHalf) stop = make(chan struct{}) // Start the periodic pings go func() { for { select { case <-stop: log.Tag("systemd", "watchdog").Println("By request watchdog is stoping.") return case <-time.After(wPerHalf): // Send the ping. log.ProtoLevel().Tag("systemd", "watchdog").Println("Ping.") daemon.SdNotify(sdState) } } }() return }
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") }
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 }
// NewBarrier creates a barrier that will be used to syncronize two events in // diferent functions or diferent goroutine, It return a handler that must be // closed. func NewBarrier() *Barrier { b := &Barrier{ fns: make([]func() error, 0), chreq: make(chan chan func() error), chclose: make(chan chan struct{}), first: make(chan func() error), last: make(chan func() error), queue: make([]chan func() error, 0), chShutdown: make(chan struct{}), chIsShutdown: make(chan bool), } go func() { shutdown := false defer func() { log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier goroutine is gone.") }() log.ProtoLevel().Tag("gormethods", "barrier").Println("New barrier") for { select { case ch := <-b.chclose: log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier close 1") for _, chq := range b.queue { close(chq) } log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier close 2") ch <- struct{}{} log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier close 3") b.isclosed = true return case fn := <-b.first: if len(b.queue) > 0 { b.dequeue(fn) continue } b.fns = append([]func() error{fn}, b.fns...) case fn := <-b.last: if len(b.queue) > 0 { b.dequeue(fn) continue } b.fns = append(b.fns, fn) case ch := <-b.chreq: if len(b.fns) == 0 { b.queue = append(b.queue, ch) continue } ch <- b.fns[0] if len(b.fns) > 1 { b.fns = b.fns[1:] } else { if shutdown { log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier shutdown") for _, ch := range b.queue { close(ch) } b.isclosed = true return } b.fns = b.fns[:0] } case <-b.chShutdown: shutdown = true if len(b.fns) == 0 { log.ProtoLevel().Tag("gormethods", "barrier").Println("Barrier shutdown") for _, ch := range b.queue { close(ch) } b.isclosed = true return } case b.chIsShutdown <- shutdown: } } }() return b }
func (p *protoServer) protocol(conn SessionConn) { dec := msgpack.NewDecoder(conn) enc := msgpack.NewEncoder(conn) log.ProtoLevel().Tag("server", "gormethods").Printf("Waiting decode %v %v %v", conn.SessionName(), conn.RemoteAddr(), conn.StreamNum()) var req ReqInst err := dec.Decode(&req) if err != nil { log.Tag("server", "gormethods").Errorf("Fail to decode instance request from %v: %v", conn.RemoteAddr(), err) conn.Close() return } inst := req.Inst if req.Inst != "" && req.Obj == "" { err = p.namedInst(conn.SessionName(), req.Inst) if err != nil { log.Tag("server", "gormethods").Errorf("Error open %v instance from %v: %v", req.Inst, conn.RemoteAddr(), err) er := enc.Encode(&RespInst{ Err: e.Forward(err), }) if err != nil { log.Tag("server", "gormethods").Errorf("Fail to encode instance reponse to %v: %v", conn.RemoteAddr(), er) } conn.Close() return } log.ProtoLevel().Tag("server", "gormethods").Printf("Session %v initiated by %v %v", conn.SessionName(), conn.RemoteAddr(), conn.StreamNum()) } else if req.Inst == "" && req.Obj != "" { inst, err = p.newInst(conn.SessionName(), conn.Auth(), req.Obj, req.Args...) if err != nil { log.Tag("server", "gormethods").Errorf("Error creating instance %v from %v: %v", req.Inst, conn.RemoteAddr(), err) er := enc.Encode(&RespInst{ Err: e.Forward(err), }) if err != nil { log.Tag("server", "gormethods").Errorf("Fail to encode instance reponse to %v: %v", conn.RemoteAddr(), er) } conn.Close() return } log.ProtoLevel().Tag("server", "gormethods").Printf("Object %v (%v) initiated by %v %v", req.Obj, inst, conn.RemoteAddr(), conn.StreamNum()) } else { log.Tag("server", "gormethods").Errorf("Invalid request from %v.", conn.RemoteAddr()) return } err = enc.Encode(&RespInst{ Inst: inst, Err: nil, }) if err != nil { log.Tag("server", "gormethods").Errorf("Fail to encode instance reponse to %v: %v", conn.RemoteAddr(), err) conn.Close() return } log.ProtoLevel().Tag("server", "gormethods").Printf("Instance %v initiated.", inst) go func() { err := p.FnInst(&instConn{ SessionConn: conn, inst: inst, enc: msgpack.NewEncoder(conn), dec: msgpack.NewDecoder(conn), }) if err != nil { conn.Close() log.ProtoLevel().Tag("server", "gormethods").Printf("Protocol close. %v %v", conn.RemoteAddr(), conn.StreamNum()) } }() }
func (c *client) Call(method string, args, retvals []reflect.Value) (err error) { start := time.Now() log.ProtoLevel().Tag("gormethods", "client", "call").Printf("Start call to %v %v %v", c.SessionName, c.InstanceName, method) defer func() { log.ProtoLevel().Tag("gormethods", "client", "call").Printf("Call to %v %v %v returned after %v with error: %v", c.SessionName, c.InstanceName, method, time.Since(start), err) }() conn, err := c.clones.Request(c.session, c.InstanceName) if err != nil { return e.Forward(err) } defer func() { if err != nil { log.ErrorLevel().Tag("client", "gormethods").Printf("Call to %v %v %v returned an error: %v", c.SessionName, c.InstanceName, method, err) conn.Close() return } er := c.clones.Return(c.SessionName, c.InstanceName, conn) if er != nil { log.DebugLevel().Tag("client", "gormethods").Println("Can't returns object:", e.Trace(e.Forward(er))) } }() conn.Mutex().Lock() defer conn.Mutex().Unlock() enc := conn.Encoder() dec := conn.Decoder() if c.ConnTimeout > 0 { err = conn.SetWriteDeadline(time.Now().Add(c.ConnTimeout)) if err != nil { return e.Forward(err) } } err = enc.Encode(msgtypes.Call) if err != nil { return e.Forward(err) } if c.ConnTimeout > 0 { err = conn.SetWriteDeadline(time.Now().Add(c.ConnTimeout)) if err != nil { return e.Forward(err) } } // Substituir os channels por uma representação destes chs := mkChClient(args) err = enc.Encode(&reqCall{ Method: method, Args: args, }) if err != nil { return e.Forward(err) } if len(chs) > 0 { err = recvInstance(dec, chs) if err != nil { return e.Forward(err) } // conn err = c.setupConn(chs) if err != nil { return e.Forward(err) } // gorotine c.startGorotineCh(chs) } // Olhar os args e descobrir quem é channel // Cada channel tem que corresponder a uma nova instancia // uma nova conn tem que ser pedida com isso: // conn, err := c.clones.Request(c.session, c.InstanceName) // Procurar por channels nos argumentos // Fazer setup de um ? e deixar uma gorotine fazendo esperando lá até o canal fechar if c.ConnTimeout > 0 { err = conn.SetWriteDeadline(time.Time{}) if err != nil { return e.Forward(err) } err = conn.SetReadDeadline(time.Now().Add(c.ConnTimeout)) if err != nil { return e.Forward(err) } } resp := respCall{} err = dec.Decode(&resp) if err != nil { return e.Forward(err) } if c.ConnTimeout > 0 { err = conn.SetReadDeadline(time.Time{}) if err != nil { return e.Forward(err) } } if resp.Err != nil { return e.Forward(resp.Err) } err = resp.Retvals(c, retvals) if err != nil { return e.Forward(err) } return }
func (s *servStreams) zero() { go func() { defer func() { s.termZero() log.ProtoLevel().Tag("gormethods", "server", "proto").Println("Stop zero.") // TODO: find a way to verify if zero is done before Close is end. // Now the leek test won't succed every time. //s.closedZero <- struct{}{} }() buf := make([]byte, payloadSize) F: for { n, err := s.bufs.Read(0, buf) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't read from stream 0: %v", err) break F } if n != payloadSize { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Not enougth data from stream 0") continue F } cmd, param, err := parseCmd(buf) if err != nil { continue F } switch cmd { case newStream: if s.streamCount >= 1<<32-1 { log.ProtoLevel().Tag("gormethods", "server", "proto").Print("Max num of open streams.") buf := newStreamResponse(fail, 0) for count := 0; count < len(buf[count:]); { n, err := s.write(0, buf) if e.Equal(err, ErrNetwork) { return } else if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't write new stream reponse for %v: %v", s.conn.RemoteAddr(), err) break } count += n } continue F } num := atomic.AddUint32(&s.streamCount, 1) err = s.streams.Activate(num) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't activate stream %v.", num) buf := newStreamResponse(fail, 0) for count := 0; count < len(buf); { n, err := s.write(0, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, num, e.Forward(err)) return } else if err != nil { writeError(s, num, e.Forward(err)) break } count += n } continue F } err = s.bufs.New(num) if err != nil { log.ProtoLevel().Tag("gormethods", "server", "proto").Errorf("Error creating buffer for stream %v: %v", num, err) continue F } buf := newStreamResponse(streamOk, num) for count := 0; count < len(buf); { n, err := s.write(0, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, num, e.Forward(err)) return } else if err != nil { writeError(s, num, e.Forward(err)) continue F } count += n } log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Request stream %v from %v", num, s.conn.RemoteAddr()) s.acceptFifo <- &newAccept{ stream: &servStream{ num: num, s: s, }, err: nil, } case closeStream: log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Close stream %v", param) err = s.streams.Deactivate(param) if err != nil && !e.Equal(err, ErrStreamNotFound) { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't deactivate stream %v: %v", param, err) buf := newStreamResponse(fail, 1) for count := 0; count < len(buf); { n, err := s.write(0, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, param, e.Forward(err)) return } else if err != nil { writeError(s, param, e.Forward(err)) break } count += n } continue F } err = s.bufs.Delete(param) if err != nil && !e.Equal(err, ErrStreamNotFound) { log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Can't deactivate stream %v: %v", param, err) buf := newStreamResponse(fail, 2) for count := 0; count < len(buf); { n, err := s.write(0, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, param, e.Forward(err)) return } else if err != nil { writeError(s, param, e.Forward(err)) break } count += n } continue F } buf := newStreamResponse(ok, 0) for count := 0; count < len(buf); { n, err := s.write(0, buf[count:]) if e.Equal(err, ErrNetwork) { writeError(s, param, e.Forward(err)) return } else if err != nil { writeError(s, param, e.Forward(err)) break } count += n } log.ProtoLevel().Tag("gormethods", "server", "proto").Printf("Close stream %v from %v", param, s.conn.RemoteAddr()) } } }() }
// 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 (p *protoServer) accept(conn net.Conn) { defer func() { conn.Close() log.ProtoLevel().Tag("server", "gormethods", "proto").Println("Accept close.") }() var err error enc := msgpack.NewEncoder(conn) dec := msgpack.NewDecoder(conn) if p.ConnTimeout > 0 { err = conn.SetReadDeadline(time.Now().Add(p.ConnTimeout)) if err != nil { log.Tag("server", "gormethods").Errorf("Read deadline for %v failed: %v", conn.RemoteAddr(), err) conn.Close() return } } var req ProtoAuth err = dec.Decode(&req) if err != nil { log.Tag("server", "gormethods").Errorf("Decode auth request for %v failed: %v", conn.RemoteAddr(), err) return } err = conn.SetReadDeadline(time.Time{}) if err != nil { log.Tag("server", "gormethods").Errorf("Read deadline for %v failed: %v", conn.RemoteAddr(), err) return } // Check the protocol version if req.ProtoVersion != ProtoVersion { log.Tag("server", "gormethods").Errorf("Wrong protocol version. Requered version is %v, current version is %v.", ProtoVersion, req.ProtoVersion) er := enc.Encode(&ErrResp{ Err: e.New("wrong protocol version"), }) if er != nil { log.Tag("server", "gormethods").Errorf("Encode auth response for %v failed: %v", conn.RemoteAddr(), er) return } return } // Authenticate err = p.Insts.AuthSession(req.Sess, req.Auth) if err != nil { er := enc.Encode(&ErrResp{ Err: e.Forward(err), }) if er != nil { log.Tag("server", "gormethods").Errorf("Encode auth response for %v failed: %v", conn.RemoteAddr(), er) return } return } // If everthing is ok send nil err = enc.Encode(&ErrResp{ Err: nil, }) if err != nil { log.Tag("server", "gormethods").Errorf("Encode auth response for %v failed: %v", conn.RemoteAddr(), err) return } income, err := newServStreams(conn, req.Sess, req.Auth, p) if err != nil { log.Tag("server", "gormethods").Errorf("Start new streams for %v failed: %v", conn.RemoteAddr(), err) return } for { c, err := income.Accept() if e.Equal(err, ErrStreamClosed) { income.Close() return } else if err != nil { log.Tag("server", "gormethods").Errorf("Accept stream for %v failed: %v", conn.RemoteAddr(), err) income.Close() return } log.ProtoLevel().Tag("server", "gormethods").Printf("Accept new stream %v for %v.", c.StreamNum(), c.RemoteAddr()) go p.protocol(c) } }
// ReqShutdown waits until the read queue is empty and than shutdowns // the Barrier control goroutine. The barrier will be useless after this. func (b *Barrier) ReqShutdown() { log.ProtoLevel().Tag("gormethods", "barrier").Println("Request shutdown") b.chShutdown <- struct{}{} }