예제 #1
0
// connect to all services
func (p *service_pool) connect_all(directory string) {
	client := p.client_pool.Get().(*etcd.Client)
	defer func() {
		p.client_pool.Put(client)
	}()

	// get the keys under directory
	log.Info("connecting services under:", directory)
	resp, err := client.Get(directory, true, true)
	if err != nil {
		log.Error(err)
		return
	}

	// validation check
	if !resp.Node.Dir {
		log.Error("not a directory")
		return
	}

	for _, node := range resp.Node.Nodes {
		if node.Dir { // service directory
			for _, service := range node.Nodes {
				p.add_service(service.Key, service.Value)
			}
		} else {
			log.Warning("malformed service directory:", node.Key)
		}
	}
	log.Info("services add complete")
}
예제 #2
0
//------------------------------------------------------- user login
func (s *server) Login(ctx context.Context, in *pb.User_LoginInfo) (*pb.User_LoginResp, error) {
	uuid := strings.ToUpper(in.Uuid)
	login_type := in.LoginType
	if uuid == "" {
		return nil, errors.New("require uuid")
	}
	cert := ""
	// TODO 根据登录类型进行第三方验证
	switch login_type {
	case LOGIN_TYPE_UUID: // 不需要验证
		// md5(uuid) -> cert
		cert = string(h.Sum([]byte(uuid)))
	// TODO
	case LOGIN_TYPE_FACEBOOK: // facebook
	default:
		log.Error("login type error", "logintype:", login_type, "uuid:", uuid)
		return nil, errors.New("login_type error")
	}
	new_user := false
	id, exist := db.IsExist(cert, login_type)
	if !exist {
		new_user = true
		id = s.next_uid()
		db.New(id, uuid, cert, in.Host, login_type)
	}

	return &pb.User_LoginResp{Uid: id, NewUser: new_user}, nil
}
예제 #3
0
파일: mongo.go 프로젝트: tenywen/login-srv
func init() {
	sess, err := mgo.Dial(URL)
	if err != nil {
		log.Error("mgo dial error", err, URL)
		os.Exit(-1)
	}
	_sess = sess
}
예제 #4
0
파일: mutex.go 프로젝트: tenywen/login-srv
// unlock a key on etcd, returns false if the key cannot be successfully unlocked
func (m *Mutex) Unlock() bool {
	client := _client_pool.Get().(*etcd.Client)
	_, err := client.CompareAndDelete(LOCK_PATH+m.key, VALUE, m.prevIndex)
	if err != nil {
		log.Error(SERVICE, err)
		return false
	}
	return true
}
예제 #5
0
// 玩家1分钟定时器
func timer_work(sess *Session, out *Buffer) {
	// 发包频率控制,太高的RPS直接踢掉
	interval := time.Now().Sub(sess.ConnectTime).Minutes()
	if interval >= 1 { // 登录时长超过1分钟才开始统计rpm。防脉冲
		rpm := float64(sess.PacketCount) / interval

		if rpm > RPM_LIMIT {
			sess.Flag |= SESS_KICKED_OUT
			log.Error("玩家RPM太高 RPM:", rpm)
			return
		}
	}
}
예제 #6
0
파일: stack.go 프로젝트: gameogre/agent
func PrintPanicStack(extras ...interface{}) {
	if x := recover(); x != nil {
		log.Error(x)
		i := 0
		funcName, file, line, ok := runtime.Caller(i)
		for ok {
			log.Errorf("frame %v:[func:%v,file:%v,line:%v]\n", i, runtime.FuncForPC(funcName).Name(), file, line)
			i++
			funcName, file, line, ok = runtime.Caller(i)
		}

		for k := range extras {
			log.Errorf("EXRAS#%v DATA:%v\n", k, spew.Sdump(extras[k]))
		}
	}
}
예제 #7
0
파일: mongo.go 프로젝트: tenywen/login-srv
//--------------------------------------------------------- create new user
func New(id int32, uuid, cert, host string, logintype int32) {
	ms, c := C(collection_name)
	defer ms.Close()

	auth := &types.Auth{
		Id:         id,
		Uuid:       uuid,
		Cert:       cert,
		Host:       host,
		LoginType:  logintype,
		CreateTime: time.Now().Unix(),
	}

	err := c.Insert(auth)
	if err != nil {
		log.Error("create user auth error", err, auth)
	}
}
예제 #8
0
파일: mutex.go 프로젝트: tenywen/login-srv
// lock a key on etcd and return mutex,returns nil if cannot lock the key
func Lock(key string) *Mutex {
	m := &Mutex{}
	m.key = key
	client := _client_pool.Get().(*etcd.Client)
	defer func() {
		_client_pool.Put(client)
	}()

	for i := 0; i < RETRY_MAX; i++ {
		// create a key with ttl
		resp, err := client.Create(LOCK_PATH+key, VALUE, TTL)
		if err != nil {
			log.Error(SERVICE, err)
			<-time.After(RETRY_WAIT)
			continue
		}
		// remember index
		m.prevIndex = resp.Node.ModifiedIndex
		return m
	}
	return nil
}
예제 #9
0
파일: handle.go 프로젝트: gameogre/agent
func checkErr(err error) {
	if err != nil {
		log.Error(err)
		panic("error occured in protocol module")
	}
}
예제 #10
0
파일: proxy.go 프로젝트: gameogre/agent
// 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
}
예제 #11
0
파일: main.go 프로젝트: gameogre/agent
// start a goroutine when a new connection is accepted
func handleClient(conn *net.TCPConn) {
	defer utils.PrintPanicStack()
	// set per-connection socket buffer
	conn.SetReadBuffer(SO_RCVBUF)

	// set initial socket buffer
	conn.SetWriteBuffer(SO_SNDBUF)

	// initial network control struct
	header := make([]byte, 2)
	in := make(chan []byte)
	defer func() {
		close(in) // session will close
	}()

	// create a new session object for the connection
	var sess Session
	host, port, err := net.SplitHostPort(conn.RemoteAddr().String())
	if err != nil {
		log.Error("cannot get remote address:", err)
		return
	}
	sess.IP = net.ParseIP(host)
	log.Infof("new connection from:%v port:%v", host, port)

	// session die signal
	sess_die := make(chan bool)

	// create a write buffer
	out := new_buffer(conn, sess_die)
	go out.start()

	// start one agent for handling packet
	wg.Add(1)
	go agent(&sess, in, out, sess_die)

	// network loop
	for {
		// solve dead link problem
		conn.SetReadDeadline(time.Now().Add(TCP_READ_DEADLINE * time.Second))
		n, err := io.ReadFull(conn, header)
		if err != nil {
			log.Warningf("read header failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}
		size := binary.BigEndian.Uint16(header)

		// alloc a byte slice for reading
		payload := make([]byte, size)
		// read msg
		n, err = io.ReadFull(conn, payload)
		if err != nil {
			log.Warningf("read payload failed, ip:%v reason:%v size:%v", sess.IP, err, n)
			return
		}

		select {
		case in <- payload: // payload queued
		case <-sess_die:
			log.Warningf("connection closed by logic, flag:%v ip:%v", sess.Flag, sess.IP)
			return
		}
	}
}