Example #1
0
func parseIP(k []byte) (string, error) {
	if len(k) != 6 {
		return "", logger.LogSteamErrorf("Invalid IP byte size. Got: %d, expected 6",
			len(k))
	}
	port := int16(k[5]) | int16(k[4])<<8
	return fmt.Sprintf("%d.%d.%d.%d:%d", int(k[0]), int(k[1]), int(k[2]),
		int(k[3]), port), nil
}
Example #2
0
func retrieve(filter filters.Filter) (*models.APIServerList, error) {
	var mq MasterQuery
	var err error
	if config.Config.SteamConfig.UseWebServerList {
		mq, err = NewMasterWebQuery(filter)
	} else {
		mq, err = NewMasterQuery(filter)
	}

	if err != nil {
		return nil, logger.LogSteamErrorf("Master server error: %s", err)
	}

	if filter.Game.IgnoreInfo && filter.Game.IgnorePlayers && filter.Game.IgnoreRules {
		return nil, logger.LogAppErrorf("Cannot ignore all three AS2 requests!")
	}

	data := a2sData{}
	hg := make(map[string]filters.Game, len(mq.Servers))
	for _, h := range mq.Servers {
		hg[h] = filter.Game
	}
	data.HostsGames = hg

	// Order of retrieval is by amount of work that must be done (generally 1, 2, 3)
	// 1. rules (request chal #, recv chal #, req rules, recv rules)
	// games with multi-packet A2S_RULES replies do the most work; otherwise 1 = 2, 3
	// 2. players (request chal #, recv chal #, req players, recv players)
	// 3. info: just request info & receive info
	// Note: some servers (i.e. new beta games) don't have all 3 of AS2_RULES/PLAYER/INFO
	if !filter.Game.IgnoreRules {
		data.Rules = batchRuleQuery(mq.Servers)
	}
	if !filter.Game.IgnorePlayers {
		data.Players = batchPlayerQuery(mq.Servers)
	}
	if !filter.Game.IgnoreInfo {
		data.Info = batchInfoQuery(mq.Servers)
	}

	serverlist, err := buildServerList(data, true)
	if err != nil {
		return nil, logger.LogAppError(err)
	}

	if config.Config.DebugConfig.EnableServerDump {
		if err := dumpServersToDisk(filter.Game.Name, serverlist); err != nil {
			logger.LogAppError(err)
		}
	}

	return serverlist, nil
}
Example #3
0
func parseServerInfo(serverinfo []byte) (models.SteamServerInfo, error) {
	if !bytes.HasPrefix(serverinfo, expectedInfoRespHeader) {
		logger.LogSteamError(ErrPacketHeader)
		return models.SteamServerInfo{}, ErrPacketHeader
	}

	serverinfo = bytes.TrimLeft(serverinfo, headerStr)

	// no info (should usually not happen)
	if len(serverinfo) <= 1 {
		logger.LogSteamError(ErrNoInfo)
		return models.SteamServerInfo{}, ErrNoInfo
	}

	serverinfo = serverinfo[1:] // 0x49
	protocol := int(serverinfo[0])
	serverinfo = serverinfo[1:]

	name := util.ReadTillNul(serverinfo)
	serverinfo = serverinfo[len(name)+1:]
	mapname := util.ReadTillNul(serverinfo)
	serverinfo = serverinfo[len(mapname)+1:]
	folder := util.ReadTillNul(serverinfo)
	serverinfo = serverinfo[len(folder)+1:]
	game := util.ReadTillNul(serverinfo)
	serverinfo = serverinfo[len(game)+1:]
	id := int16(binary.LittleEndian.Uint16(serverinfo[:2]))
	serverinfo = serverinfo[2:]
	if id >= 2400 && id <= 2412 {
		return models.SteamServerInfo{},
			logger.LogSteamErrorf("The Ship servers are not supported")
	}
	players := int16(serverinfo[0])
	serverinfo = serverinfo[1:]
	maxplayers := int16(serverinfo[0])
	serverinfo = serverinfo[1:]
	bots := int16(serverinfo[0])
	serverinfo = serverinfo[1:]
	servertype := string(serverinfo[0])
	serverinfo = serverinfo[1:]
	environment := string(serverinfo[0])
	serverinfo = serverinfo[1:]
	visibility := int16(serverinfo[0])
	serverinfo = serverinfo[1:]
	vac := int16(serverinfo[0])
	serverinfo = serverinfo[1:]
	version := util.ReadTillNul(serverinfo)
	serverinfo = serverinfo[len(version)+1:]

	// extra data flags
	var port int16
	var steamid uint64
	var sourcetvport int16
	var sourcetvname string
	var keywords string
	var gameid uint64
	edf := serverinfo[0]
	serverinfo = serverinfo[1:]
	if edf != 0x00 {
		if edf&0x80 > 0 {
			port = int16(binary.LittleEndian.Uint16(serverinfo[:2]))
			serverinfo = serverinfo[2:]
		}
		if edf&0x10 > 0 {
			steamid = binary.LittleEndian.Uint64(serverinfo[:8])
			serverinfo = serverinfo[8:]
		}
		if edf&0x40 > 0 {
			sourcetvport = int16(binary.LittleEndian.Uint16(serverinfo[:2]))
			serverinfo = serverinfo[2:]
			sourcetvname = util.ReadTillNul(serverinfo)
			serverinfo = serverinfo[len(sourcetvname)+1:]
		}
		if edf&0x20 > 0 {
			keywords = util.ReadTillNul(serverinfo)
			serverinfo = serverinfo[len(keywords)+1:]
		}
		if edf&0x01 > 0 {
			gameid = binary.LittleEndian.Uint64(serverinfo[:8])
			serverinfo = serverinfo[len(serverinfo):]
		}
	}

	// format a few ambiguous values
	if environment == "l" {
		environment = "Linux"
	}
	if environment == "w" {
		environment = "Windows"
	}
	if environment == "m" || environment == "o" {
		environment = "Mac"
	}
	if servertype == "d" {
		servertype = "dedicated"
	}
	if servertype == "l" {
		servertype = "listen"
	}
	if servertype == "p" {
		servertype = "sourcetv"
	}

	return models.SteamServerInfo{
		Protocol:    protocol,
		Name:        name,
		Map:         mapname,
		Folder:      folder,
		Game:        game,
		ID:          id,
		Players:     players,
		MaxPlayers:  maxplayers,
		Bots:        bots,
		ServerType:  servertype,
		Environment: environment,
		Visibility:  visibility,
		VAC:         vac,
		Version:     version,
		ExtraData: models.SteamExtraData{
			Port:         port,
			SteamID:      steamid,
			SourceTVPort: sourcetvport,
			SourceTVName: sourcetvname,
			Keywords:     keywords,
			GameID:       gameid,
		},
	}, nil
}