Пример #1
0
// Parses messages from the client
func (p *MessageParser) CsParse(reader io.Reader, logger *log.Logger) {
	p.logger = logger

	// If we return, we should consume all input to avoid blocking the pipe
	// we're listening on. TODO Maybe we could just close it?
	defer p.consumeUnrecognizedInput(reader)

	defer func() {
		if err := recover(); err != nil {
			p.printf("Parsing failed: %v", err)
		}
	}()

	username, err := proto.ServerReadHandshake(reader)
	if err != nil {
		p.printf("ServerReadHandshake error: %v", err)
		return
	}
	p.printf("ServerReadHandshake(username=%v)", username)

	loginUsername, err := proto.ServerReadLogin(reader)
	if err != nil {
		p.printf("ServerReadLogin error: %v", err)
		return
	}
	p.printf("ServerReadLogin(username=%v)", loginUsername)

	for {
		err := proto.ServerReadPacket(reader, p)
		if err != nil {
			if err != os.EOF {
				p.printf("ReceiveLoop failed: %v", err)
			} else {
				p.printf("ReceiveLoop hit EOF")
			}
			return
		}
	}
}
Пример #2
0
// Negotiate a new player client login. This function runs in a new goroutine
// for each player connection and therefore should not attempt to alter the
// game structure without enqueue().
func (game *Game) login(conn net.Conn) {
	// TODO: This function should access game in a thread-safe way for reading
	var err, clientErr os.Error

	defer func() {
		if err != nil {
			log.Print(err.String())
			if clientErr == nil {
				clientErr = os.NewError("Server error.")
			}
			proto.WriteDisconnect(conn, clientErr.String())
			conn.Close()
		}
	}()

	var username string
	if username, err = proto.ServerReadHandshake(conn); err != nil {
		clientErr = os.NewError("Handshake error.")
		return
	}

	if !validPlayerUsername.MatchString(username) {
		err = os.NewError("Bad username")
		clientErr = err
		return
	}

	log.Print("Client ", conn.RemoteAddr(), " connected as ", username)

	if game.UnderMaintenanceMsg != "" {
		err = fmt.Errorf("Server under maintenance, kicking player: %q", username)
		clientErr = os.NewError(game.UnderMaintenanceMsg)
		return
	}

	// Load player permissions.
	permissions := gamerules.Permissions.UserPermissions(username)
	if !permissions.Has("login") {
		err = fmt.Errorf("Player %q does not have login permission", username)
		clientErr = os.NewError("You do not have access to this server.")
		return
	}

	if err = proto.ServerWriteHandshake(conn, game.serverId); err != nil {
		clientErr = os.NewError("Handshake error.")
		return
	}

	if game.serverId != "-" {
		var authenticated bool
		authserver := &server_auth.ServerAuth{"http://www.minecraft.net/game/checkserver.jsp"}
		authenticated, err = authserver.Authenticate(game.serverId, username)
		if !authenticated || err != nil {
			var reason string
			if err != nil {
				reason = "Authentication check failed: " + err.String()
			} else {
				reason = "Failed authentication"
			}
			err = fmt.Errorf("Client %v: %s", conn.RemoteAddr(), reason)
			clientErr = os.NewError(reason)
			return
		}
		log.Print("Client ", conn.RemoteAddr(), " passed minecraft.net authentication")
	}

	if _, err = proto.ServerReadLogin(conn); err != nil {
		clientErr = os.NewError("Login error.")
		return
	}

	entityId := game.entityManager.NewEntity()

	var playerData nbt.ITag
	if playerData, err = game.worldStore.PlayerData(username); err != nil {
		clientErr = os.NewError("Error reading user data. Please contact the server administrator.")
		return
	}

	player := player.NewPlayer(entityId, game.shardManager, conn, username, game.worldStore.SpawnPosition, game.playerDisconnect, game)
	if playerData != nil {
		if err = player.ReadNbt(playerData); err != nil {
			// Don't let the player log in, as they will only have default inventory
			// etc., which could lose items from them. Better for an administrator to
			// sort this out.
			err = fmt.Errorf("Error parsing player data for %q: %v", username, err)
			clientErr = os.NewError("Error reading user data. Please contact the server administrator.")
			return
		}
	}

	game.playerConnect <- player
	player.Start()
}