func (h *Handshake) handleAssign(r *xio.PacketReader) (rtmfp.ResponseMessage, uint32, error) { if req, err := parseAssignRequest(r); err != nil { return nil, 0, err } else { cookie := cookies.Find(string(req.cookie)) if cookie == nil { return nil, 0, errors.New("assign.cookie not found") } cookie.Lock() defer cookie.Unlock() if cookie.Xid == 0 { responder, encrypt, decrypt := rtmfp.ComputeSharedKeys(h, req.pubkey, req.initiator) cookie.Pid = req.pid cookie.Responder = responder if xid, err := session.Create(req.yid, cookie.Pid, cookie.Value(), encrypt, decrypt, h.lport, h.raddr); err != nil { counts.Count("handshake.session.error", 1) return nil, 0, errors.New(fmt.Sprintf("assign.create session = %v", err)) } else { cookie.Xid = xid counts.Count("handshake.assign", 1) xlog.SssLog.Printf("[join] %s [%s] xid = %d\n", xlog.StringToHex(cookie.Pid), h.raddr, xid) } xlog.OutLog.Printf("[handshake]: new session xid = %d from [%s]\n", cookie.Xid, h.raddr) } return &assignResponse{cookie.Xid, cookie.Responder}, req.yid, nil } }
func New() *Cookie { cookies.Lock() defer cookies.Unlock() now := time.Now().UnixNano() buf := make([]byte, CookieSize) for i, v := 0, now; i < 8; i, v = i+1, v>>8 { buf[i] = uint8(v) } rnd := xio.NewRandomReader(now) for i := 0; i < 4; i++ { rnd.ReadBytes(buf[8:]) value := string(buf) if c := cookies.values[value]; c != nil { continue } c := &Cookie{} c.value = value c.alloctime = now cookies.values[value] = c counts.Count("cookie.new", 1) return c } counts.Count("cookie.null", 1) return nil }
func Send(lport uint16, raddr *net.UDPAddr, data []byte) { if len(data) > 1400 { counts.Count("udp.toobig", 1) xlog.ErrLog.Printf("[udp]: udp-%d packet is too big, size = %d\n", lport, len(data)) } else if srv := servers[lport]; srv == nil { counts.Count("udp.notfound", 1) xlog.ErrLog.Printf("[udp]: udp-%d not found\n", lport) } else { srv.Send(raddr, data) } }
func Exit(xid uint32, raddr *net.UDPAddr) { if clt := tcp.GetClient(); clt == nil { return } else if bs, err := newXRequest(xid, raddr, "exit", 0, nil, true); err != nil { counts.Count("rpc.exit.error", 1) xlog.ErrLog.Printf("[rpc]: rpc exit error = '%v'\n", err) } else { counts.Count("rpc.exit", 1) async.Call(uint64(xid), func() { clt.Send(bs) }) } }
func (h *Handshake) handleHello(r *xio.PacketReader) (rtmfp.ResponseMessage, error) { if req, err := parseHelloRequest(r); err != nil { return nil, err } else { switch req.mode { default: return nil, errors.New(fmt.Sprintf("hello.unknown mode = 0x%02x", req.mode)) case 0x0f: if s := session.FindByPid(string(req.epd)); s == nil { counts.Count("p2p.session.notfound", 1) return nil, &handshakeError{"hello.handshake.session not found", req.epd, h.raddr} } else if addrs, ok := s.Handshake(req.tag, h.raddr); !ok { counts.Count("p2p.session.hasclosed", 1) return nil, &handshakeError{"hello.handshake.session has been closed", req.epd, h.raddr} } else { counts.Count("p2p.handshake", 1) return &handshakeResponse{req.tag, addrs}, nil } case 0x0a: if uri, err := url.ParseRequestURI(string(req.epd)); err != nil { return nil, errors.New("hello.parse uri") } else if app := uri.Path; len(app) == 0 { return nil, errors.New("hello.parse app") } else { if ss := strings.Split(app, "/"); len(ss) != 1 { app = "" for _, s := range ss { if len(s) != 0 { app = s break } } } if len(app) == 0 || !args.IsAuthorizedApp(app) { counts.Count("handshake.app.unauthorized", 1) return nil, errors.New(fmt.Sprintf("hello.unauthorized app = %s", app)) } } cookie := cookies.New() if cookie == nil { return nil, errors.New("hello.null cookie") } cookie.Lock() defer cookie.Unlock() counts.Count("handshake.hello", 1) xlog.OutLog.Printf("[handshake]: new cookie from [%s]\n", h.raddr) return &helloResponse{req.tag, cookie.Value()}, nil } } }
func Call(xid uint32, raddr *net.UDPAddr, callback float64, data []byte, reliable bool) { if clt := tcp.GetClient(); clt == nil { counts.Count("rpc.call.noclient", 1) xlog.ErrLog.Printf("[rpc]: rpc is disabled\n") } else if bs, err := newXRequest(xid, raddr, "call", callback, data, reliable); err != nil { counts.Count("rpc.call.error", 1) xlog.ErrLog.Printf("[rpc]: rpc call error = '%v'\n", err) } else { counts.Count("rpc.call", 1) async.Call(uint64(xid), func() { clt.Send(bs) }) } }
func init() { for i := 0; i < len(groups); i++ { g := &groups[i] g.cond = sync.NewCond(&g.lock) g.list = list.New() main := func() { defer func() { if x := recover(); x != nil { counts.Count("async.panic", 1) xlog.ErrLog.Printf("[async]: panic = %v\n%s\n", x, utils.Trace()) } }() for { var f func() g.lock.Lock() if e := g.list.Front(); e != nil { f = g.list.Remove(e).(func()) } else { g.cond.Wait() } g.lock.Unlock() if f != nil { f() } } } go func() { for { main() } }() } }
func flush(s *Session, msgs []rtmfp.ResponseMessage) { lport, raddr := s.lport, s.raddr if data, err := rtmfp.PacketToBytes(&packet{s.yid, s.manage.lasttime, s.stmptime, msgs}); err != nil { counts.Count("session.tobytes.error", 1) xlog.ErrLog.Printf("[session]: packet to bytes error = '%v'\n", err) return } else { xlog.OutLog.Printf("[session]: send addr = [%s], data.len = %d\n%s\n", raddr, len(data), utils.Formatted(data)) if data, err = rtmfp.EncodePacket(s, s.yid, data); err != nil { counts.Count("session.encode.error", 1) xlog.ErrLog.Printf("[session]: encode packet error = '%v'\n", err) return } udp.Send(lport, raddr, data) } }
func DecodeXMessage(bs []byte) *XMessage { x := &XMessage{} if err := proto.Unmarshal(bs, x); err != nil { counts.Count("rpc.xmessage.error", 1) xlog.ErrLog.Printf("[rpc]: rpc decode.xmessage error = '%v'\n", err) return nil } return x }
func Find(value string) *Cookie { cookies.Lock() c := cookies.values[value] cookies.Unlock() if c == nil { counts.Count("cookie.notfound", 1) } return c }
func newHandshake() *Handshake { h := &Handshake{} h.AESEngine = rtmfp.NewAESEngine() if err := h.SetKey(cryptkey, cryptkey); err != nil { utils.Panic(fmt.Sprintf("handshake init error = '%v'", err)) } h.DHEngine = rtmfp.NewDHEngine() counts.Count("handshake.new", 1) return h }
func HandlePacket(lport uint16, raddr *net.UDPAddr, data []byte) { h := getHandshake() if h == nil { return } defer putHandshake(h) var err error if data, err = rtmfp.DecodePacket(h, data); err != nil { counts.Count("handshake.decode.error", 1) xlog.ErrLog.Printf("[handshake]: decode error = '%v'\n", err) return } xlog.OutLog.Printf("[handshake]: recv addr = [%s], data.len = %d\n%s\n", raddr, len(data), utils.Formatted(data)) h.lport, h.raddr = lport, raddr var pkt *packet if pkt, err = h.handle(xio.NewPacketReader(data[6:])); err != nil { counts.Count("handshake.handle.error", 1) xlog.ErrLog.Printf("[handshake]: handle error = '%v'\n", err) return } else if pkt == nil { xlog.OutLog.Printf("[handshake]: response packet is empty\n") return } if data, err = rtmfp.PacketToBytes(pkt); err != nil { counts.Count("handshake.tobytes.error", 1) xlog.ErrLog.Printf("[handshake]: packet to bytes error = '%v'\n", err) return } xlog.OutLog.Printf("[handshake]: send addr = [%s], data.len = %d\n%s\n", raddr, len(data), utils.Formatted(data)) if data, err = rtmfp.EncodePacket(h, pkt.yid, data); err != nil { counts.Count("handshake.encode.error", 1) xlog.ErrLog.Printf("[handshake]: encode packet error = '%v'\n", err) return } udp.Send(lport, raddr, data) }
func (s *Session) handleFlowRequest(req *flowRequest) error { if fr, err := s.getFlowReader(req.fid, req.signature); err != nil { counts.Count("session.flow.error", 1) return errors.New("flow.create flow reader") } else if fr != nil { fr.AddFragments(req.stageack, req.Fragments()...) fr.CommitAck() return nil } else { xlog.OutLog.Printf("[session]: xid = %d, reader.fid = %d, flow not found\n", s.xid, req.fid) return nil } }
func (s *Session) Close() { if s.closed { return } s.closed = true for _, fw := range s.writers { fw.reader.handler.OnClose() } s.send(newErrorResponse()) counts.Count("session.close", 1) xlog.OutLog.Printf("[session]: xid = %d, session closed\n", s.xid) rpc.Exit(s.xid, s.raddr) }
func Create(yid uint32, pid string, cookie string, encrypt, decrypt []byte, lport uint16, raddr *net.UDPAddr) (uint32, error) { s := &Session{} s.xid = 0 s.yid = yid s.pid = pid s.lport, s.raddr = lport, raddr s.addrs = nil s.cookie = cookie s.closed = false s.manage.cnt, s.manage.lasttime = 0, time.Now().UnixNano() s.stmptime = 0 s.AESEngine = rtmfp.NewAESEngine() if err := s.SetKey(encrypt, decrypt); err != nil { return 0, err } s.lastfid = 0 s.lastsid = 0 s.mainfw = nil s.readers = make(map[uint64]*flowReader) s.writers = make(map[uint64]*flowWriter) s.rsplist.Init() sessions.Lock() defer sessions.Unlock() xid := sessions.lastxid for { xid++ if xid == 0 { continue } if xid == sessions.lastxid { return 0, errors.New("too many sessions") } if getSessionByXid(xid) == nil { break } } s.xid = xid sessions.lastxid = xid addSessionByXid(xid, s) addSessionByPid(pid, s) m := &sessions.manages[int(xid%uint32(len(sessions.manages)))] m.Lock() m.freshlist.PushBack(s) m.Unlock() counts.Count("session.new", 1) return xid, nil }
func (c *Client) main() { for { conn, err := net.DialTCP("tcp4", nil, &net.TCPAddr{IP: net.ParseIP(c.ip), Port: int(c.port)}) if err != nil { counts.Count("tcp.connect.error", 1) log.Printf("[tcp]: connect %s:%d failed '%v'\n", c.ip, c.port, err) } else { counts.Count("tcp.connect", 1) log.Printf("[tcp]: connect to %s\n", conn.RemoteAddr()) conn.SetWriteBuffer(MaxSendBufferSize) conn.SetReadBuffer(MaxRecvBufferSize) conn.SetNoDelay(true) var once sync.Once sig := make(chan int) raise := func() { once.Do(func() { conn.Close() close(sig) }) } go sender(conn, c.send, sig, raise) go recver(conn, c.recv, sig, raise) <-sig counts.Count("tcp.connect.close", 1) } for i := 0; i < 50; i++ { time.Sleep(time.Millisecond * 100) for { select { case <-c.send: continue default: } break } } } }
func HandlePacket(lport uint16, raddr *net.UDPAddr, xid uint32, data []byte) { s := FindByXid(xid) if s == nil { counts.Count("session.notfound", 1) return } s.Lock() defer s.Unlock() if s.closed { counts.Count("session.hasclosed", 1) return } defer s.flush() var err error if data, err = rtmfp.DecodePacket(s, data); err != nil { counts.Count("session.decode.error", 1) xlog.ErrLog.Printf("[session]: decode error = '%v'\n", err) return } xlog.OutLog.Printf("[session]: recv addr = [%s], data.len = %d\n%s\n", raddr, len(data), utils.Formatted(data)) s.lport, s.raddr = lport, raddr if len(s.cookie) != 0 { cookies.Commit(s.cookie) s.cookie = "" rpc.Join(s.xid, s.raddr) } s.manage.cnt, s.manage.lasttime = 0, time.Now().UnixNano() if err = s.handle(xio.NewPacketReader(data[6:])); err != nil { counts.Count("session.handle.error", 1) xlog.ErrLog.Printf("[session]: handle error = '%v'\n", err) } }
func (h *Handshake) handle(r *xio.PacketReader) (*packet, error) { if marker, err := r.Read8(); err != nil { return nil, errors.New("packet.read marker") } else { if _, err := r.Read16(); err != nil { return nil, errors.New("packet.read time") } if marker != 0x0b { counts.Count("handshake.marker.unknown", 1) return nil, errors.New(fmt.Sprintf("packet.unknown marker = 0x%02x", marker)) } } if msg, err := rtmfp.ParseRequestMessage(r); err != nil { return nil, err } else { switch msg.Code { default: counts.Count("handshake.code.unknown", 1) return nil, errors.New(fmt.Sprintf("message.unknown code = 0x%02x", msg.Code)) case 0x30: if rsp, err := h.handleHello(msg.PacketReader); err != nil { counts.Count("handshake.hello.error", 1) return nil, err } else { return &packet{0, rsp}, nil } case 0x38: if rsp, yid, err := h.handleAssign(msg.PacketReader); err != nil { counts.Count("handshake.assign.error", 1) return nil, err } else { return &packet{yid, rsp}, nil } } } }
func (s *Session) Handshake(tag []byte, raddr *net.UDPAddr) ([]*net.UDPAddr, bool) { s.Lock() defer s.Unlock() if s.closed { counts.Count("session.p2p.closed", 1) return nil, false } defer s.flush() xlog.OutLog.Printf("[session]: xid = %d, raddr = [%s], handshake to [%s]\n", s.xid, s.raddr, raddr) s.send(&handshakeResponse{s.pid, tag, raddr, true}) addrs := make([]*net.UDPAddr, 1+len(s.addrs)) addrs[0] = s.raddr copy(addrs[1:], s.addrs) return addrs, true }
func init() { sessions.lastxid = 0 for i := 0; i < len(sessions.buckets); i++ { sessions.buckets[i].xidmap = make(map[uint32]*Session, 8192) sessions.buckets[i].pidmap = make(map[string]*Session, 8192) } for i := 0; i < len(sessions.manages); i++ { m := &sessions.manages[i] m.freshlist = list.New() m.alivelist = list.New() go func() { manage := args.Manage() for { m.Lock() if m.freshlist.Len() != 0 { m.alivelist.PushBackList(m.freshlist) m.freshlist.Init() } m.Unlock() count := 0 if e := m.alivelist.Front(); e != nil { for e != nil { next := e.Next() if s := e.Value.(*Session); s.Manage() { delSessionByXid(s.xid) delSessionByPid(s.pid) m.alivelist.Remove(e) count++ xlog.SssLog.Printf("[exit] %s [%s] xid = %d cnt = %d\n", xlog.StringToHex(s.pid), s.raddr, s.xid, s.manage.cnt) } e = next } } if count != 0 { counts.Count("session.cleanup", count) } time.Sleep(time.Millisecond * time.Duration(manage)) } }() } }
func init() { cookies.values = make(map[string]*Cookie, 16384) go func() { for { limit := time.Now().UnixNano() - int64(time.Minute)*5 count := 0 cookies.Lock() for value, cookie := range cookies.values { if cookie.alloctime < limit { delete(cookies.values, value) count++ } } cookies.Unlock() if count != 0 { counts.Count("cookie.timeout", count) } time.Sleep(time.Second * 15) } }() }
func init() { handshakes.Init() go func() { for { handshakes.Lock() if e := handshakes.Back(); e != nil { handshakes.Remove(e) counts.Count("handshake.release", 1) } n := handshakes.Len() handshakes.Unlock() if n > 512 { time.Sleep(time.Second * 2) } else if n > 128 { time.Sleep(time.Second * 5) } else { time.Sleep(time.Second * 30) } } }() }
func Start() { shell := func(f func()) { s := func() { defer func() { if x := recover(); x != nil { counts.Count("server.panic", 1) xlog.ErrLog.Printf("[server]: panic = %v\n%s\n", x, utils.Trace()) } }() f() } for { s() } } for _, udpsrv := range udp.GetServers() { s := udpsrv f := func() { for { if lport, addr, data := s.Recv(); addr != nil && len(data) != 0 { if xid, err := rtmfp.PacketXid(data); err != nil { continue } else if xid == 0 { handshake.HandlePacket(lport, addr, data) } else { session.HandlePacket(lport, addr, xid, data) } } } } for i := 0; i < args.Parallel(); i++ { go shell(f) } } if s := tcp.GetServer(); s != nil { f := func() { for { if bs := s.Recv(); len(bs) != 0 { if x := rpc.DecodeXMessage(bs); x != nil { if b := x.Broadcast; b != nil { xids, data, reliable := b.Xids, b.Data, *b.Reliable if len(xids) == 0 || len(data) == 0 { continue } session.RecvPull(xids, data, reliable) } if c := x.Close; c != nil { xids := c.Xids if len(xids) == 0 { continue } session.CloseAll(xids) } } } } } go shell(f) } if c := tcp.GetClient(); c != nil { f := func() { for { if bs := c.Recv(); len(bs) != 0 { if x := rpc.DecodeXResponse(bs); x != nil { xid, data, callback, reliable := *x.Xid, x.Data, *x.Callback, *x.Reliable if xid == 0 || len(data) == 0 { continue } session.Callback(xid, data, callback, reliable) } } } } go shell(f) } for { time.Sleep(time.Minute) } }
func (s *Session) handle(r *xio.PacketReader) error { if marker, err := r.Read8(); err != nil { return errors.New("packet.read marker") } else { if s.stmptime, err = r.Read16(); err != nil { return errors.New("packet.read time") } switch marker | 0xf0 { default: counts.Count("session.marker.unknown", 1) return errors.New(fmt.Sprintf("packet.unknown marker = 0x%02x", marker)) case 0xfd: if _, err = r.Read16(); err != nil { return errors.New("packet.read ping time") } case 0xf9: } } msglist := list.New() for r.Len() != 0 { if msg, err := rtmfp.ParseRequestMessage(r); err != nil { if err != rtmfp.EOP { return err } break } else { msglist.PushBack(msg) } } var lastreq *flowRequest = nil for e := msglist.Front(); e != nil; e = e.Next() { msg := e.Value.(*rtmfp.RequestMessage) if msg.Code != 0x11 && lastreq != nil { if err := s.handleFlowRequest(lastreq); err != nil { return err } lastreq = nil } switch msg.Code { default: s.Close() counts.Count("session.code.unknown", 1) return errors.New(fmt.Sprintf("message.close code = 0x%02x", msg.Code)) case 0x4c: s.Close() counts.Count("session.code.close", 1) return nil case 0x01: s.send(newKeepAliveResponse(true)) case 0x41: case 0x5e: if req, err := parseFlowErrorRequest(msg.PacketReader); err != nil { counts.Count("session.parse5e.error", 1) return err } else if fw := s.writers[req.fid]; fw != nil { fw.reader.handler.OnClose() } else { xlog.OutLog.Printf("[session]: xid = %d, writer.fid = %d, flow not found 0x5e\n", s.xid, req.fid) } case 0x51: if req, err := parseFlowAckRequest(msg.PacketReader); err != nil { counts.Count("session.parse51.error", 1) return err } else if fw := s.writers[req.fid]; fw != nil { fw.CommitAck(req.cnt, req.ack) } else { xlog.OutLog.Printf("[session]: xid = %d, writer.fid = %d, flow not found 0x51\n", s.xid, req.fid) } case 0x10: if req, err := parseFlowRequest(msg.PacketReader); err != nil { counts.Count("session.parse10.error", 1) return err } else { lastreq = req } case 0x11: if req, err := parseFlowRequestSlice(msg.PacketReader); err != nil { counts.Count("session.parse11.error", 1) return err } else if lastreq != nil { lastreq.AddSlice(req) } else { xlog.OutLog.Printf("[session]: xid = %d, not following message\n", s.xid) } } } if lastreq != nil { return s.handleFlowRequest(lastreq) } return nil }
func Commit(value string) { cookies.Lock() delete(cookies.values, value) cookies.Unlock() counts.Count("cookie.commit", 1) }