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 }
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 }
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 }