/* * Cross platform lobby client / server lister, by jrgp - 2/14/2011 * * Compile me for windows with: i586-mingw32msvc-c++ client.cpp -lws2_32 */ // Legacy C shit #include #include #include #include #include #include // Lovely C++ stuff #include #include #include #ifdef WIN32 // Weird fucking windows networking shit #define _WIN32_WINNT 0x501 #include #include #else // Unix networking stuff #include #include #include #endif // Lobby location #define LOBBY_HOST "rr.soldat.pl" #define LOBBY_PORT "13073" // Because using std:: everywhere pisses off people, apparently using namespace std; // Simple explode implementation std::vector c_explode(const std::string &string, const char &sep) { // Result stored here vector result; // Temp buffer stored here std::string curr = ""; // Characater by character for (unsigned int i = 0, len = string.length(); i < len; i++) { // This match? if (string[i] == sep) { // Save buffer if it isn't shit if (curr.length() > 0) result.push_back(curr); // No use in getting redundant, now curr = ""; } // No; add this to current buffer else curr += string[i]; } // Save a trailing one if it's useful if (curr.length() > 0) result.push_back(curr); // Give return result; } // Server record struct server_entry { unsigned short int port; unsigned short int version; string name; string map; string ip; unsigned short int gametype; unsigned short int bonus_freq; unsigned short int connection_type; unsigned short int num_bots; unsigned short int respawn; bool is_linux; // "linux" is apparently a reserved word of some sort bool survival; bool advanced; bool realistic; unsigned short int num_players; unsigned short int max_players; bool be; bool dedicated; bool passworded; string country; }; // Lobby interface class class lobby_client { private: // Weird fucking windows shit #ifdef WIN32 WSADATA wsadata; #endif // Store actual servers here vector servers; public: // Constructor lobby_client() { // More weird fucking windows shit #ifdef WIN32 if (WSAStartup(MAKEWORD(2, 0), &wsadata) != 0) cerr << "Error initializing winsock " << endl; #endif } // Destructor ~lobby_client() { // End the weird fucking windows shit #ifdef WIN32 WSACleanup(); #endif } // Number of server's we've got unsigned int num_servers() { return servers.size(); } // Load the servers bool load_servers() { // Request char req[100]; sprintf(req, "e%c0%c0%c0%c0%c0%c0%c0%c0%c0%c0%c0%c-1%c0%c0\n", 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169, 169); // Address of where we're connecting struct addrinfo hints, *res; // Socket handle int sockfd; // Initiate hints to nothing memset(&hints, 0, sizeof hints); // We only want ipv4 hints.ai_family = AF_INET; // TCP, not UDP hints.ai_socktype = SOCK_STREAM; // Address we're connecting to int ar; if ((ar = getaddrinfo(LOBBY_HOST, LOBBY_PORT, &hints, &res)) != 0) { cerr << "Error resolving: " << gai_strerror(ar) << endl; return false; } // Create socket sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); // Connect if(connect(sockfd, res->ai_addr, res->ai_addrlen) == -1) { cerr << "Error: " << strerror(errno) << endl; return false; } // Kill ram that used freeaddrinfo(res); // Debugging output cout << "Connected" << endl; // Send our request (may fail) send(sockfd, req, strlen(req), 0); int rst = 0; // recv result int i = 0; // buff iterator int j = 0; // line pos counter int len; char buff[100]; // sock buff char line[500]; // current line holder // Parts of each split go here vector parts; // Temporary struct for each current server server_entry curr_server; // Go forever until we decide not to while (1) { // Get rst = recv(sockfd, buff, sizeof buff, 0); // Motherfucker if (rst < 1) break; // terminate it. very important buff[rst] = '\0'; // go through each character in buff for (i = 0, len = strlen(buff); i < len; i++) { // a newline? use line, empty it, reset counter if (buff[i] == '\n') { // Split that by the copyrihgt symbols parts = c_explode(line, 169); // Does this look like a valid server entry? if (parts[0][0] == 'g' && parts.size() == 20) { // Pack that temp struct curr_server.version = atoi(parts[1].c_str()); curr_server.ip = parts[2]; curr_server.port = atoi(parts[3].c_str()); curr_server.gametype = atoi(parts[4].c_str()); curr_server.num_players = atoi(parts[5].c_str()); curr_server.max_players = atoi(parts[6].c_str()); curr_server.map = parts[7]; curr_server.name = parts[8]; curr_server.num_bots = atoi(parts[9].c_str()); curr_server.bonus_freq = atoi(parts[10].c_str()); curr_server.respawn = atoi(parts[11].c_str()); curr_server.connection_type = atoi(parts[12].c_str()); curr_server.survival = parts[13].compare("1") == 0; curr_server.realistic = parts[14].compare("1") == 0; curr_server.dedicated = parts[15].compare("1") == 0; curr_server.is_linux = parts[16].compare("1") == 0; curr_server.passworded = parts[17].compare("1") == 0; curr_server.be = parts[18].compare("1") == 0; curr_server.country = parts[19].substr(0, 2); // pack that servers.push_back(curr_server); } // End of line; clear buffers j = 0; memset(line, '\0', sizeof line); } // no; char in current line. else { line[j] = buff[i]; // save char in line buff line[j+1] = '\0'; // terminate it j++; // increase counter } } } // Kill socket #ifdef WIN32 closesocket(sockfd); #else close(sockfd); #endif // Apparent success return true; } // Return result vector get_servers() { return servers; } }; int main() { // Usage // Load class lobby_client *lc = new lobby_client(); // Fetch lc->load_servers(); // Maybe see how many we got cout << "Found " << lc->num_servers() << " servers" << endl; // Get them vector servers = lc->get_servers(); // Show them for (int num = servers.size(), i = 0; i < num; i++) { // (refer to any of the fields mentioned by struct near beginning of file) cout << servers[i].name << " " << servers[i].ip << ":" << servers[i].port << endl; } // Great Success! return 0; }