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 *ServiceStatus) Init() error { var err error if s.Name == "" { return e.New(ErrInvServName) } s.conn, err = sd.NewSystemdConnection() if err != nil { return e.Forward(err) } err = s.conn.Subscribe() if err != nil { return e.Forward(err) } ch, cherr := s.conn.SubscribeUnits(s.Interval) go func() { for { select { case status := <-ch: if status == nil { continue } st, found := status[s.Name] if !found { log.Tag("systemd").Printf("Status of %v is unknow.", s.Name) s.setStatus(Unknow) continue } if s == nil { s.setStatus(Deleted) continue } if st.LoadState == "loaded" && st.ActiveState == "active" && st.SubState == "running" { s.setStatus(Running) } else if st.LoadState == "loaded" && st.ActiveState == "active" && st.SubState == "active" { s.setStatus(Running) } else if st.LoadState == "not-found" && st.ActiveState == "active" && st.SubState == "exited" { s.setStatus(Stopped) } else if st.LoadState == "loaded" && st.ActiveState == "inactive" && st.SubState == "dead" { s.setStatus(Stopped) } else { //ActiveState: deactivating, LoadState: loaded, SubState: stop-sigterm log.Tag("systemd").Printf("ActiveState: %v, LoadState: %v, SubState: %v", st.ActiveState, st.LoadState, st.SubState) s.setStatus(Other) } case err := <-cherr: log.Tag("systemd", "service", "status").Fatalln("SubscribeUnits error:", err) } } }() return nil }
func (s *Server) cleanUpChannelInstance(inst Valuer, conn InstConn) { if !inst.Instance().IsNil() { inst.Instance().Close() inst.NilInstance() } err := s.Insts.Delete(conn.SessionName(), conn.InstanceName()) if err != nil && e.FindStr(err, "instance not found") == -1 { log.Tag("gormethods", "server", "channel").Errorf("Can't remove the instance %v/%v. %v", conn.SessionName(), conn.InstanceName(), err) } }
func (a *Server) sendErr(addr *net.UDPAddr, er error) { respBuf := bytes.NewBuffer([]byte{}) enc := gob.NewEncoder(respBuf) msg := &Msg{ Err: er, } err := enc.Encode(msg) if err != nil { log.Tag("discover", "server").Error("Error encoding erro response:", err) return } if respBuf.Len() > a.BufSize { log.Tag("discover", "server").Error("Error encoding erro response: error response is too long", respBuf.Len()) return } _, _, err = a.conn.WriteMsgUDP(respBuf.Bytes(), nil, addr) if err != nil { log.Tag("discover", "server").Error("Error sending erro response:", err) } }
func (a *Server) keepalive(addr *net.UDPAddr, to string, tokey *rsa.PublicKey, buf []byte) { dec := gob.NewDecoder(bytes.NewReader(buf)) var id string err := dec.Decode(&id) 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 decoding id"))) return } ctx, err := a.ctxs.Get(id) 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("id is invalid"))) return } a.sendResp(&Response{ Id: ctx.Id, Ip: ctx.Addr.String(), Seq: ctx.Seq, }, to, tokey, addr) }
func (a *Server) request(addr *net.UDPAddr, to string, tokey *rsa.PublicKey, buf []byte) { dec := gob.NewDecoder(bytes.NewReader(buf)) var req Request err := dec.Decode(&req) 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 decoding request"))) return } resp, err := a.Protocol(addr, &req) 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("protocol error"))) return } ctx, err := a.ctxs.Get(req.Id) if err != nil { resp.Id = req.Id resp.Ip = addr.String() a.lckSeq.Lock() resp.Seq = uint16(len(a.seq)) a.lckSeq.Unlock() err = a.ctxs.Register(&context{ Id: req.Id, Seq: resp.Seq, Addr: addr, }) 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("protocol error"))) return } } else { resp.Id = ctx.Id resp.Ip = ctx.Addr.String() resp.Seq = ctx.Seq } a.sendResp(resp, to, tokey, addr) }
// 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 (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 (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 *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 (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 }
func (s *Server) protoChannel(conn InstConn) error { chRetSend := make(chan struct{}) chRetRecv := make(chan struct{}) defer func() { select { case <-chRetSend: return case <-chRetRecv: return } }() inst, err := s.Insts.Get(conn.SessionName(), conn.InstanceName()) if err != nil { log.Tag("gormethods", "server", "channel").Errorf("Error getting the instance %v/%v: %v", conn.SessionName(), conn.InstanceName(), e.Forward(err)) return e.Forward(err) } if inst.Type() != WithChannel { log.Tag("gormethods", "server", "channel").Errorf("Instance %v/%v is of wrong type", conn.SessionName(), conn.InstanceName()) return e.New("instance is of wrong type") } log.ProtoLevel().Tag("gormethods", "server", "channel").Printf("Start channel for %v/%v", conn.SessionName(), conn.InstanceName()) switch inst.ChDir() { case reflect.RecvDir: go func(inst Valuer, conn InstConn) { defer func() { chRetRecv <- struct{}{} }() var err error dec := conn.Decoder() elem := reflect.New(inst.Instance().Type().Elem()) for { var typ ChMsgType err = dec.Decode(&typ) if err != nil { s.cleanUpChannelInstance(inst, conn) break } switch typ { case ChMsgErr: er := &e.Error{} err = dec.Decode(er) if err != nil { s.cleanUpChannelInstance(inst, conn) break } if !e.Equal(er, ErrChClosed) { log.Tag("server", "gormethods").Errorln(er) } s.cleanUpChannelInstance(inst, conn) break case ChMsgValue: err = dec.DecodeValue(elem) if err != nil { s.cleanUpChannelInstance(inst, conn) break } inst.Instance().Send(elem.Elem()) default: s.cleanUpChannelInstance(inst, conn) break } } }(inst, conn) case reflect.SendDir: go func(inst Valuer, conn InstConn) { defer func() { chRetSend <- struct{}{} }() var err error enc := conn.Encoder() for { val, ok := inst.Instance().Recv() if !ok { inst.NilInstance() err = enc.Encode(ChMsgErr) if err != nil { s.cleanUpChannelInstance(inst, conn) break } enc.Encode(e.New(ErrRecvChFail)) s.cleanUpChannelInstance(inst, conn) break } err = enc.Encode(ChMsgValue) if err != nil { s.cleanUpChannelInstance(inst, conn) break } err = enc.EncodeValue(val) if err != nil { s.cleanUpChannelInstance(inst, conn) break } } }(inst, conn) default: log.Tag("gormethods", "server", "channel").Errorf("Instance %v/%v channel is of wrong direction", conn.SessionName(), conn.InstanceName()) return e.New("wrong channel direction") } return nil }
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 (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) } }
// 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) startGorotineCh(channels []*ChannelInstance) { for _, ci := range channels { go func(ci *ChannelInstance) { defer func() { r := recover() if r == nil { return } err, ok := r.(error) if !ok { panic(r) } if err.Error() == "close of closed channel" { return } panic(r) }() defer ci.Conn.Close() ci.Conn.Mutex().Lock() defer ci.Conn.Mutex().Unlock() enc := ci.Conn.Encoder() dec := ci.Conn.Decoder() if c.ConnTimeout > 0 { err := ci.Conn.SetWriteDeadline(time.Now().Add(c.ConnTimeout)) if err != nil { log.Tag("client", "gormethods").Errorln("Fail to set write deadline:", e.Trace(e.Forward(err))) return } } err := enc.Encode(msgtypes.Channel) if err != nil { log.Tag("client", "gormethods").Errorln("Request channel instance failed:", e.Trace(e.Forward(err))) return } if c.ConnTimeout > 0 { err = ci.Conn.SetReadDeadline(time.Time{}) if err != nil { log.Tag("client", "gormethods").Errorln("Fail to set write deadline:", e.Trace(e.Forward(err))) return } } elem := ci.MakeNewPtrElem() switch ci.Ch.Type().ChanDir() { case reflect.RecvDir: for { // Channel have a min buffer length of 1 val, ok := ci.Ch.Recv() if !ok { err = enc.Encode(ChMsgErr) if err != nil { break } err = enc.Encode(e.New(ErrChClosed)) break } err = enc.Encode(ChMsgValue) if err != nil { break } err = enc.EncodeValue(val) if err != nil { break } } case reflect.SendDir: for { var typ ChMsgType err = dec.Decode(&typ) if err != nil { // TODO: Como detectar se o canal foi fechado? ci.Ch.Close() break } switch typ { case ChMsgErr: er := &e.Error{} err = dec.Decode(er) if err != nil { ci.Ch.Close() break } if !e.Equal(er, ErrRecvChFail) { log.Tag("client", "gormethods").Errorln(er) } ci.Ch.Close() break case ChMsgValue: err = dec.Decode(elem.Interface()) if err != nil { ci.Ch.Close() break } ci.Ch.Send(elem.Elem()) default: break } } default: log.Tag("client", "gormethods").Errorln("Channel direction not supported") break } }(ci) } }
func (s *Server) protoCall(conn InstConn) (err error) { enc := conn.Encoder() dec := conn.Decoder() defer func() { if err != nil { err = enc.Encode(&respCall{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) } } }() inst, err := s.Insts.Get(conn.SessionName(), conn.InstanceName()) if err != nil { log.Tag("server", "gormethods").Errorf("Error getting the instance %v/%v: %v", conn.SessionName(), conn.InstanceName(), e.Forward(err)) err = e.Forward(err) return } if inst.Type() != WithValue { log.Tag("server", "gormethods").Errorf("Instance %v/%v is of wrong type", conn.SessionName(), conn.InstanceName()) return e.New("instance is of wrong type") } log.ProtoLevel().Tag("gormethods", "server", "call").Printf("Call %v %v %v", conn.SessionName(), conn.InstanceName(), types.NameOf(inst.Instance().Type())) var req reqCall err = dec.Decode(&req) if e.Find(err, io.EOF) >= 0 { return e.Push(err, ErrWire) } else if err != nil { log.ProtoLevel().Tag("server", "gormethods").Printf("Decode %v -> %v (%v) error: %v", conn.RemoteAddr(), conn.LocalAddr(), conn.StreamNum(), err) err = e.Push(err, ErrWire) return } // Tratar argumentos (req.Args) com channel // criar channel // recebe do channel envia pelo conn // recebe do conn envia para channel // (faz isso até fechar o channel em um dos lados) // substutui em req.Args os channels // Se existem channels enviar instancias err = s.mkChServer(conn, req.Args, enc) if err != nil { err = e.Forward(err) log.Tag("server", "gormethods").Errorf("Channel arguments setup failed: %v", err) return } method := inst.Instance().MethodByName(req.Method) if !method.IsValid() { err = e.Push(e.New(ErrMethodNotFound), e.New("method %v not found", req.Method)) log.Tag("server", "gormethods").Errorf("Error in call %v/%v: %v", conn.SessionName(), conn.InstanceName(), err) return } log.ProtoLevel().Tag("server", "gormethods").Printf("Call %v/%v %v %v", conn.SessionName(), conn.InstanceName(), types.NameOf(inst.Instance().Type()), req.Method) var retvals []reflect.Value if method.Type().IsVariadic() { retvals = method.CallSlice(req.Args) } else { retvals = method.Call(req.Args) } log.ProtoLevel().Tag("server", "gormethods").Printf("Call returned %v/%v %v %v", conn.SessionName(), conn.InstanceName(), types.NameOf(inst.Instance().Type()), req.Method) for i := range retvals { var exp *Export exp, err = s.Insts.ExportGet(conn.SessionName(), conn.InstanceName(), req.Method, i) if err != nil { continue } var instname string instname, err = rand.Chars(16, rand.NumberLetters, "go") if err != nil { err = e.Push(err, "can't create the instance name for exported retval") log.Tag("server", "gormethods").Errorf("Error in call %v/%v: %v", conn.SessionName(), conn.InstanceName(), err) return } owners := auth.NewPlainTextCredentials() err = owners.Add(conn.Auth()) if err != nil { err = e.Push(err, "can't authorize the exported retval") log.Tag("server", "gormethods").Errorf("Error in call %v/%v: %v", conn.SessionName(), conn.InstanceName(), err) return } err = s.Insts.New(conn.SessionName(), instname, retvals[i], owners) if err != nil { err = e.Push(err, "can't crete the instance for the exported retval") log.Tag("server", "gormethods").Errorf("Error in call %v/%v: %v", conn.SessionName(), instname, err) return } for _, to := range exp.ToExport { err = s.Insts.Export(conn.SessionName(), instname, to) if err != nil { err = e.Push(err, e.New("can't export %v/%v %v %v %v to %v", conn.SessionName(), instname, to.Method, to.RetvalPos, types.Name(retvals[i].Interface()), types.Name(exp.Client))) log.Tag("server", "gormethods").Errorf("Error in call %v/%v: %v", conn.SessionName(), conn.InstanceName(), err) return } } exp.Client.Associate(conn.SessionName(), instname, conn.Auth()) retvals[i] = reflect.ValueOf(exp.Client) continue } log.ProtoLevel().Tag("server", "gormethods").Printf("Send returned values %v/%v %v %v", conn.SessionName(), conn.InstanceName(), types.NameOf(inst.Instance().Type()), req.Method) err = enc.Encode(&respCall{ Vals: retvals, Err: nil, }) 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) return } log.ProtoLevel().Tag("server", "gormethods").Printf("Send returned values done %v/%v %v %v", conn.SessionName(), conn.InstanceName(), types.NameOf(inst.Instance().Type()), req.Method) return }