func Add(Type int16, user_id int32, timeout int64, params []byte) int32 { defer _event_err() req := event.ADD_EVENT{} req.F_type = Type req.F_user_id = user_id req.F_timeout = timeout req.F_params = params ret := _call(packet.Pack(event.Code["add_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := event.PKT_INT(reader) return tbl.F_v }
//------------------------------------------------ Forward to Hub/Group func GroupForward(req *IPCObject) bool { defer _hub_err() msg := hub.FORWARDIPC{F_IPC: req.Json()} ret := _call(packet.Pack(hub.Code["forwardgroup_req"], &msg, nil)) reader := packet.Reader(ret) tbl, err := hub.PKT_INT(reader) if err != nil || tbl.F_v == 0 { return false } return true }
func Ping() bool { defer _event_err() req := event.INT{} req.F_v = 1 ret := _call(packet.Pack(event.Code["ping_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := event.PKT_INT(reader) if tbl.F_v != req.F_v { return false } return true }
func AddUser(id int32) bool { defer _hub_err() req := hub.ID{} req.F_id = id ret := _call(packet.Pack(hub.Code["adduser_req"], &req, nil)) reader := packet.Reader(ret) tbl, err := hub.PKT_INT(reader) if err != nil || tbl.F_v == 0 { return false } return true }
func Login(id int32) bool { defer _hub_err() req := hub.LOGIN_REQ{} req.F_id = id ret := _call(packet.Pack(hub.Code["login_req"], &req, nil)) reader := packet.Reader(ret) tbl, err := hub.PKT_LOGIN_ACK(reader) if err != nil || !tbl.F_success { return false } return true }
func Logout(id int32) bool { defer _hub_err() req := protos.ID{} req.F_id = id ret := _call(packet.Pack(protos.Code["logout_req"], req, nil)) reader := packet.Reader(ret) tbl, err := protos.PKT_INT(reader) if err != nil || tbl.F_v == 0 { return false } return true }
func AddUser(id int32) bool { defer _hub_err() req := ID{} req.F_id = id ret := _call(packet.Pack(Code["adduser_req"], &req, nil)) reader := packet.Reader(ret) tbl, err := PKT_INT(reader) if err != nil || tbl.F_v == 0 { NOTICE("HUB AddUser return", false, "param", id) return false } return true }
//---------------------------------------------------------- Forward IPCObject func Forward(req *IPCObject) bool { defer _hub_err() // HUB protocol forwarding msg := FORWARDIPC{F_IPC: req.Json()} ret := _call(packet.Pack(Code["forward_req"], &msg, nil)) reader := packet.Reader(ret) tbl, err := PKT_INT(reader) if err != nil || tbl.F_v == 0 { ERR("HUB Forward return false", "param", req) return false } return true }
func Logout(id int32) bool { defer _hub_err() req := ID{} req.F_id = id ret := _call(packet.Pack(Code["logout_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := PKT_INT(reader) if tbl.F_v == 0 { NOTICE("HUB Logout return ", false, "param", id) return false } return true }
func Protect(id int32, until time.Time) bool { defer _hub_err() req := hub.ID{} req.F_id = id ret := _call(packet.Pack(hub.Code["protect_req"], &req, nil)) reader := packet.Reader(ret) tbl, err := hub.PKT_INT(reader) if err != nil || tbl.F_v == 0 { return false } return true }
//------------------------------------------------ Stats Server Agent func StatsAgent(incoming chan []byte, conn net.Conn) { queue_timer := make(chan int32, 1) queue_timer <- 1 for { select { case sample := <-incoming: reader := packet.Reader(sample) HandleRequest(reader) case <-queue_timer: log.Println("============== STATS QUEUE SIZE:", len(incoming), "===================") timer.Add(1, time.Now().Unix()+PRINT_INTERVAL, queue_timer) } } }
func Login(id int32) bool { defer _hub_err() req := LOGIN_REQ{} req.F_id = id ret := _call(packet.Pack(Code["login_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := PKT_LOGIN_ACK(reader) if tbl.F_success == 0 { NOTICE("HUB Login return ", false, "param", id) return false } return true }
func Protect(id int32, until int64) bool { defer _hub_err() req := PROTECT{} req.F_id = id req.F_protecttime = until ret := _call(packet.Pack(Code["protect_req"], &req, nil)) reader := packet.Reader(ret) tbl, _ := PKT_INT(reader) if tbl.F_v == 0 { NOTICE("HUB Protect return", false, "param", id, until) return false } return true }
//---------------------------------------------------------- Hub processing func HubAgent(incoming chan []byte, conn net.Conn) { config := cfg.Get() if config["profile"] == "true" { helper.SetMemProfileRate(1) defer func() { helper.GC() helper.DumpHeap() helper.PrintGCSummary() }() } hostid := atomic.AddInt32(&_host_genid, 1) // forward buffer forward := make(chan []byte, MAXCHAN) // output buffer output := make(chan []byte, MAXCHAN) protos.AddServer(hostid, forward) log.Printf("game server [id:%v] connected\n", hostid) go _write_routine(output, conn) defer func() { protos.RemoveServer(hostid) core.LogoutServer(hostid) close(forward) close(output) log.Printf("game server [id:%v] disconnected\n", hostid) }() for { select { case msg, ok := <-incoming: // from hub if !ok { return } reader := packet.Reader(msg) protos.HandleRequest(hostid, reader, output) case msg := <-forward: // send forward packet helper.SendChan(0, msg, output) } } }
func GetInfo(id int32) (info Info, err error) { defer _hub_err() req := protos.ID{} req.F_id = id ret := _call(packet.Pack(protos.Code["getinfo_req"], req, nil)) reader := packet.Reader(ret) tbl, _err := protos.PKT_INFO(reader) info.Id = tbl.F_id info.State = tbl.F_state info.Score = tbl.F_score info.Clan = tbl.F_clan info.ProtectTime = tbl.F_protecttime info.Name = tbl.F_name return info, _err }
func GetList(A, B int32) (ids, scores []int32, err error) { defer _hub_err() req := protos.GETLIST{} req.F_A = A req.F_B = B ret := _call(packet.Pack(protos.Code["getlist_req"], req, nil)) reader := packet.Reader(ret) tbl, _err := protos.PKT_LIST(reader) ids = make([]int32, len(ids)) scores = make([]int32, len(scores)) for k := range tbl.F_items { ids[k] = tbl.F_items[k].F_id scores[k] = tbl.F_items[k].F_score } return ids, scores, _err }
func send_proto(conn net.Conn, p int16, info interface{}) (reader *packet.Packet) { seqid++ payload := packet.Packet(p, info, nil) writer := packet.Writer() writer.WriteU16(uint16(len(payload)) + 4) w := packet.Writer() w.WriteU32(seqid) w.WriteRawBytes(payload) data := w.Data() if KEY_EXCHANGE { encoder.XORKeyStream(data, data) } writer.WriteRawBytes(data) conn.Write(writer.Data()) log.Printf("send : %#v", writer.Data()) time.Sleep(time.Second) //read header := make([]byte, 2) io.ReadFull(conn, header) size := binary.BigEndian.Uint16(header) log.Printf("read header: %v \n", size) r := make([]byte, size) _, err := io.ReadFull(conn, r) if err != nil { log.Println(err) } if KEY_EXCHANGE { decoder.XORKeyStream(r, r) } reader = packet.Reader(r) b, err := reader.ReadS16() if err != nil { log.Println(err) } if _, ok := RCode[b]; !ok { log.Println("unknown proto ", b) } return }
//---------------------------------------------------------- HUB SERVICE func StartAgent(incoming chan []byte, conn net.Conn) { hostid := atomic.AddInt32(&_host_genid, 1) log.Printf("game server [id:%v] connected\n", hostid) // forward queue (IPCObject) forward := make(chan IPCObject, 100000) protos.AddServer(hostid, forward) // closing defer func() { protos.RemoveServer(hostid) core.LogoutServer(hostid) close(forward) log.Printf("game server [id:%v] disconnected\n", hostid) }() for { select { case msg, ok := <-incoming: // request from game server if !ok { return } // read seqid reader := packet.Reader(msg) seqid, err := reader.ReadU32() if err != nil { log.Println("read SEQID failed.", err) return } // handle request ret := GSProxy(hostid, reader) // send result if len(ret) != 0 { _send(seqid, ret, conn) } case obj := <-forward: // forwarding packets(ie. seqid == 0) _send(0, obj.Json(), conn) } } }
func parseRawMsg(data *[]byte, session *Session) *RawNetMsg { defer func() { if err := recover(); err != nil { fmt.Printf("DECODE RAW MSG ERR: %p %v %v", session, data, err) } }() reader := packet.Reader(*data) api, err := reader.ReadS16() if err != nil { fmt.Printf("Get header fail: %v", data) return nil } return &RawNetMsg{ Api: api, Data: *data, Session: session, } }
func GetInfo(id int32) (info Info, flag bool) { defer _hub_err() req := hub.ID{} req.F_id = id ret := _call(packet.Pack(hub.Code["getinfo_req"], &req, nil)) reader := packet.Reader(ret) tbl, _err := hub.PKT_INFO(reader) if _err == nil && tbl.F_flag { info.Id = tbl.F_id info.State = tbl.F_state info.Score = tbl.F_score info.ProtectTime = tbl.F_protecttime flag = true return } flag = false return }
//------------------------------------------------ Hub processing func HubAgent(incoming chan []byte, conn net.Conn) { hostid := atomic.AddInt32(&_host_genid, 1) forward := make(chan []byte) _server_lock.Lock() _servers[hostid] = forward // message chan for forwarding to client _server_lock.Unlock() log.Printf("server id:%v connected\n", hostid) defer func() { _server_lock.Lock() delete(_servers, hostid) _server_lock.Unlock() log.Printf("server id:%v disconnected\n", hostid) }() for { select { case msg, ok := <-incoming: if !ok { return } reader := packet.Reader(msg) seqid, err := reader.ReadU64() // read seqid if err != nil { log.Printf("Read Sequence Id failed.") continue } if result := HandleRequest(hostid, reader); result != nil { _send(seqid, result, conn) } case msg := <-forward: _send(0, msg, conn) } } }
//----------------------------------------------------------- Event Server Agent func EventAgent(incoming chan []byte, conn net.Conn) { // output buffer output := make(chan []byte, MAXCHAN) go _write_routine(output, conn) defer func() { close(output) }() for { select { case msg, ok := <-incoming: if !ok { return } reader := packet.Reader(msg) protos.HandleRequest(reader, output) } } }
//----------------------------------------------- client protocol handle proxy func UserRequestProxy(sess *Session, p []byte) []byte { defer _ProxyError() reader := packet.Reader(p) b, err := reader.ReadU16() if err != nil { log.Println("read protocol error") } proto_logger.Printf("code:%v,user:%v\n", b, sess.User.Id) handle := protos.ProtoHandler[b] if handle != nil { ret, err := handle(sess, reader) fmt.Println(ret) if err == nil { return ret } } return nil }
//----------------------------------------------- client protocol handle proxy func UserRequestProxy(sess *Session, p []byte) []byte { defer PrintPanicStack() now := time.Now() reader := packet.Reader(p) // read client_elapsed in milli-second since startup time-sync client_elapsed, err := reader.ReadU32() if err != nil { log.Println("Read timestamp failed.", err) return nil } // sampling latencies for cheat detection if sess.LoggedIn { server_elapsed := now.Sub(sess.ConnectTime).Nanoseconds() / 1000 diff := int(server_elapsed - int64(client_elapsed)) sess.LatencySamples.G.Add(diff) } // read protocol id b, err := reader.ReadU16() if err != nil { log.Println("read protocol error") } //log.Printf("code:%v\n", b) handle := ipc.ProtoHandler[b] if handle != nil { ret := handle(sess, reader) if len(ret) != 0 { return ret } } return nil }
// client protocol handle proxy func proxy_user_request(sess *Session, p []byte) []byte { start := time.Now() defer utils.PrintPanicStack(sess, p) // 解密 if sess.Flag&SESS_ENCRYPT != 0 { sess.Decoder.XORKeyStream(p, p) } // 封装为reader reader := packet.Reader(p) // 读客户端数据包序列号(1,2,3...) // 客户端发送的数据包必须包含一个自增的序号,必须严格递增 // 加密后,可避免重放攻击-REPLAY-ATTACK seq_id, err := reader.ReadU32() if err != nil { log.Error("read client timestamp failed:", err) sess.Flag |= SESS_KICKED_OUT return nil } // 数据包序列号验证 if seq_id != sess.PacketCount { log.Errorf("illegal packet sequence id:%v should be:%v size:%v", seq_id, sess.PacketCount, len(p)-6) sess.Flag |= SESS_KICKED_OUT return nil } // 读协议号 b, err := reader.ReadS16() if err != nil { log.Error("read protocol number failed.") sess.Flag |= SESS_KICKED_OUT return nil } // 根据协议号断做服务划分 // 协议号的划分采用分割协议区间, 用户可以自定义多个区间,用于转发到不同的后端服务 var ret []byte if b > MAX_PROTO_NUM { if err := forward(sess, p[4:]); err != nil { log.Errorf("service id:%v execute failed, error:%v", b, err) sess.Flag |= SESS_KICKED_OUT return nil } } else { if h := client_handler.Handlers[b]; h != nil { ret = h(sess, reader) } else { log.Errorf("service id:%v not bind", b) sess.Flag |= SESS_KICKED_OUT return nil } } // 监控协议处理时间 // 监控数值会发送到statsd,格式为: // API.XXX_REQ = 10ms elasped := time.Now().Sub(start) if b != 0 { // 排除心跳包日志 log.Trace("[REQ]", client_handler.RCode[b]) _statter.Timing(1.0, fmt.Sprintf("%v%v", STATSD_PREFIX, client_handler.RCode[b]), elasped) } return ret }
// stream server func (s *server) Stream(stream GameService_StreamServer) error { var sess Session ch_agent := s.recv(stream) ch_ipc := make(chan *Game_Frame, DEFAULT_CH_IPC_SIZE) defer func() { if sess.Flag&SESS_REGISTERED != 0 { // TODO: destroy session sess.Flag &^= SESS_REGISTERED registry.Unregister(sess.UserId) } log.Trace("stream end:", sess.UserId) }() // >> main message loop << for { select { case frame, ok := <-ch_agent: // frames from agent if !ok { // EOF return nil } switch frame.Type { case Game_Message: // validation if sess.Flag&SESS_REGISTERED == 0 { log.Critical("user not registered") return ERROR_USER_NOT_REGISTERED } // locate handler by proto number reader := packet.Reader(frame.Message) c, err := reader.ReadS16() if err != nil { log.Critical(err) return err } handle := client_handler.Handlers[c] if handle == nil { log.Criticalf("service not bind: %v", c) return ERROR_SERVICE_NOT_BIND } // serialized processing, no future locks needed. // multiple agents can connect simutaneously to games var ret []byte wrap := func() { ret = handle(&sess, reader) } s.latch(wrap) // construct frame & return message from logic if ret != nil { if err := stream.Send(&Game_Frame{Type: Game_Message, Message: ret}); err != nil { log.Critical(err) return err } } // session control by logic if sess.Flag&SESS_KICKED_OUT != 0 { // logic kick out if err := stream.Send(&Game_Frame{Type: Game_Kick}); err != nil { log.Critical(err) return err } return nil } case Game_Register: if sess.Flag&SESS_REGISTERED == 0 { // TODO: create session sess.Flag |= SESS_REGISTERED sess.UserId = frame.UserId registry.Register(frame.UserId, ch_ipc) log.Trace("user registered") } else { log.Critical("user already registered") } case Game_Unregister: if sess.Flag&SESS_REGISTERED != 0 { // TODO: destroy session sess.Flag &^= SESS_REGISTERED registry.Unregister(sess.UserId) log.Trace("user unregistered") } else { log.Critical("user not registered") } case Game_Ping: if err := stream.Send(&Game_Frame{Type: Game_Ping, Message: frame.Message}); err != nil { log.Critical(err) return err } log.Trace("pinged") default: log.Criticalf("incorrect frame type: %v", frame.Type) return ERROR_INCORRECT_FRAME_TYPE } case frame := <-ch_ipc: // forward async messages from interprocess(goroutines) communication if err := stream.Send(frame); err != nil { log.Critical(err) return err } } } }
// client protocol handle proxy func proxy_user_request(sess *Session, p []byte) []byte { start := time.Now() defer utils.PrintPanicStack() //解密 if sess.Flag&SESS_ENCRYPT != 0 { //使用2组密钥匙, 增加破解难度 sess.Decoder.XORKeyStream(p, p) } //封装成reader reader := packet.Reader(p) // 读客户端数据包序列号(1,2,3...) // 可避免重放攻击-REPLAY-ATTACK //数据包的前4个字节存放的是客户端的发包数量 //客户端每次发包要包含第几次发包信息 seq_id, err := reader.ReadU32() if err != nil { log.Error("read client timestamp failed:", err) sess.Flag |= SESS_KICKED_OUT return nil } // 数据包个数验证 if seq_id != sess.PacketCount { //数据包真实长度是,总长度-4个字节的包个数长度-2个字节的协议号长度 log.Errorf("illegal packet sequeue id:%v should be:%v size:%v", seq_id, sess.PacketCount, len(p)-6) sess.Flag |= SESS_KICKED_OUT return nil } // 读协议号 b, err := reader.ReadS16() if err != nil { log.Error("read protocol number failed.") sess.Flag |= SESS_KICKED_OUT return nil } //根据协议号段 做服务划分 var ret []byte if b > MAX_PROTO_NUM { //去除4字节发包个数,将其余的向前传递 if err := forward(sess, p[4:]); err != nil { log.Errorf("service id:%v execute failed, error:%v", b, err) sess.Flag |= SESS_KICKED_OUT return nil } } else { if h := client_handler.Handlers[b]; h != nil { ret = h(sess, reader) } else { log.Errorf("service id:%v not bind", b) sess.Flag |= SESS_KICKED_OUT return nil } } // 统计处理时间 elasped := time.Now().Sub(start) if b != 0 { //排除心跳包日志 log.Trace("[REQ]", client_handler.RCode[b]) _statter.Timing(1.0, fmt.Sprintf("%v%v", STATSD_PREFIX, client_handler.RCode[b]), elasped) } return ret }
// client protocol handle proxy func proxy_user_request(sess *Session, p []byte) []byte { start := time.Now() defer utils.PrintPanicStack(sess, p) // 解密 if sess.Flag&SESS_ENCRYPT != 0 { sess.Decoder.Codec(p) } // 封装为reader reader := packet.Reader(p) // 读客户端数据包序列号(1,2,3...) // 可避免重放攻击-REPLAY-ATTACK seq_id, err := reader.ReadU32() if err != nil { log.Error("read client timestamp failed:", err) sess.Flag |= SESS_KICKED_OUT return nil } // 读协议号 b, err := reader.ReadS16() if err != nil { log.Error("read protocol number failed.") sess.Flag |= SESS_KICKED_OUT return nil } // 数据包序列号验证 if seq_id != sess.PacketCount { log.Errorf("illegal packet sequence id:%v should be:%v proto:%v size:%v", seq_id, sess.PacketCount, b, len(p)-6) sess.Flag |= SESS_KICKED_OUT return nil } var ret []byte if b > MAX_PROTO_NUM { // game协议 // 透传 ret, err = forward(sess, p) if err != nil { log.Errorf("service id:%v execute failed", b) sess.Flag |= SESS_KICKED_OUT return nil } } else { // agent保留协议段 [0, MAX_PROTO_NUM] // handle有效性检查 h := client_handler.Handlers[b] if h == nil { log.Errorf("service id:%v not bind", b) sess.Flag |= SESS_KICKED_OUT return nil } // 执行 ret = h(sess, reader) } // 统计处理时间 elasped := time.Now().Sub(start) if b != 0 { // 排除心跳包日志 log.Trace("[REQ]", b) _statter.Timing(1.0, fmt.Sprintf("%v%v", STATSD_PREFIX, b), elasped) } return ret }
//----------------------------------------------- client protocol handle proxy func UserRequestProxy(sess *Session, p []byte) []byte { defer PrintPanicStack() // decrypt if sess.Flag&SESS_ENCRYPT != 0 { sess.Decoder.Codec(p) } // encapsulate into reader reader := packet.Reader(p) // client timestamp check // mainly for REPLAY-ATTACK client_elapsed, err := reader.ReadU32() if err != nil { ERR("read client timestamp failed.", err) sess.Flag |= SESS_KICKED_OUT return nil } client_time := sess.ConnectTime.Unix() + int64(client_elapsed)/1000 now := time.Now().Unix() if client_time > now+PACKET_ERROR || client_time < now-PACKET_EXPIRE { ERR("client timestamp is illegal.", client_elapsed, client_time, now) sess.Flag |= SESS_KICKED_OUT return nil } // read protocol number b, err := reader.ReadS16() if err != nil { ERR("read protocol number failed.") sess.Flag |= SESS_KICKED_OUT return nil } // handle validation handle := net.ProtoHandler[b] if handle == nil { ERR("service id", b, "not bind") sess.Flag |= SESS_KICKED_OUT return nil } // before HOOK if !_before_hook(sess, b) { ERR("before hook failed, code", b) sess.Flag |= SESS_KICKED_OUT return nil } // handle packet start := time.Now() ret := handle(sess, reader) end := time.Now() uid := int32(-1) name := "" if sess.Flag&SESS_LOGGED_IN != 0 { uid = sess.User.Id name = sess.User.Name } log.Printf("\033[0;36m[REQ] %v\tbytes[in:%v out:%v seq:%v]\tusr:[%v %v]\ttime:%v\033[0m\n", net.RCode[b], len(p)-6, len(ret), sess.PacketCount, uid, name, end.Sub(start)) // after HOOK _after_hook(sess, net.RCode[b]) sess.MarkDirty() return ret }
//----------------------------------------------- receive message from hub func HubReceiver(conn net.Conn) { defer conn.Close() header := make([]byte, 2) seq_id := make([]byte, 8) for { // header n, err := io.ReadFull(conn, header) if n == 0 && err == io.EOF { break } else if err != nil { log.Println("error receving header:", err) break } // packet seq_id uint32 n, err = io.ReadFull(conn, seq_id) if n == 0 && err == io.EOF { break } else if err != nil { log.Println("error receving seq_id:", err) break } seqval := uint64(0) for k, v := range seq_id { seqval |= uint64(v) << uint((7-k)*8) } // data size := int(header[0])<<8 | int(header[1]) - 8 data := make([]byte, size) n, err = io.ReadFull(conn, data) if err != nil { log.Println("error receving msg:", err) break } if seqval == 0 { // packet forwarding, deliver to MQ reader := packet.Reader(data) forward_id, err := reader.ReadS32() if err != nil { log.Println("packet forwarding error") goto L } sess := Query(forward_id) if sess == nil { log.Println("forward failed, maybe user is offline?") } else { func() { defer func() { if x := recover(); x != nil { log.Println("forward to MQ failed, the user is so lucky") } }() sess.MQ <- data[reader.Pos():] // the payload is the message }() } } else { _wait_ack_lock.Lock() if ack, ok := _wait_ack[seqval]; ok { ack <- data delete(_wait_ack, seqval) } else { log.Println("Illegal packet sequence number from HUB") } _wait_ack_lock.Unlock() } L: } }