/*-------------------------------------------------------------------------*\ * Error translation functions \*-------------------------------------------------------------------------*/ const char *socket_hoststrerror(int err) { if (err <= 0) return io_strerror(err); switch (err) { case WSAHOST_NOT_FOUND: return PIE_HOST_NOT_FOUND; default: return wstrerror(err); } }
const char *socket_strerror(int err) { if (err <= 0) return io_strerror(err); switch (err) { case WSAEADDRINUSE: return PIE_ADDRINUSE; case WSAECONNREFUSED : return PIE_CONNREFUSED; case WSAEISCONN: return PIE_ISCONN; case WSAEACCES: return PIE_ACCESS; case WSAECONNABORTED: return PIE_CONNABORTED; case WSAECONNRESET: return PIE_CONNRESET; case WSAETIMEDOUT: return PIE_TIMEDOUT; default: return wstrerror(err); } }
const char *socket_strerror(int err) { if (err <= 0) return io_strerror(err); switch (err) { case WSAEADDRINUSE: return "address already in use"; case WSAECONNREFUSED: return "connection refused"; case WSAEISCONN: return "already connected"; case WSAEACCES: return "permission denied"; case WSAECONNABORTED: return "closed"; case WSAECONNRESET: return "closed"; case WSAETIMEDOUT: return "timeout"; default: return wstrerror(err); } }
int WINAPI wWinMain (HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPWSTR /*lpCmdLine*/, int nCmdShow) { INITCOMMONCONTROLSEX icc = INITCOMMONCONTROLSEX (); icc.dwSize = sizeof icc; icc.dwICC = ICC_STANDARD_CLASSES | ICC_PROGRESS_CLASS; InitCommonControlsEx (&icc); winsock_wrapper winsock; if (winsock.error ()) { explain (L"WSAStartup failed", winsock.error ()); return 1; } WNDCLASSEX wcex = WNDCLASSEX (); wcex.cbSize = sizeof wcex; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = main_window_wndproc; wcex.hInstance = hInstance; //wcex.hIcon = something; wcex.hCursor = LoadCursor (nullptr, IDC_ARROW); wcex.hbrBackground = GetSysColorBrush (COLOR_3DFACE); wcex.lpszClassName = main_window_class; if (!RegisterClassEx (&wcex)) { explain (L"RegisterClassEx failed"); return 1; } window_data wd; HWND hWnd = CreateWindow (main_window_class, L"Qarma", WS_OVERLAPPEDWINDOW /*WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX */, CW_USEDEFAULT, CW_USEDEFAULT, 1024, 720, 0, 0, hInstance, &wd); if (!hWnd) { explain (L"CreateWindow failed"); return 1; } ShowWindow (hWnd, nCmdShow); UpdateWindow (hWnd); std::vector<HANDLE> handles; while (true) { handles.clear (); if (wd.mpt) handles.push_back (wd.mpt.get ()); DWORD r = MsgWaitForMultipleObjects (handles.size (), &handles[0], false, INFINITE, QS_ALLINPUT); if (r == WAIT_FAILED) { explain (L"MsgWaitForMultipleObjects failed"); return 1; } else if (r == WAIT_OBJECT_0 + handles.size ()) { MSG msg; while (PeekMessage (&msg, nullptr, 0, 0, PM_REMOVE)) { if (msg.message == WM_QUIT) return msg.wParam; TranslateMessage (&msg); DispatchMessage (&msg); } } else if (r >= WAIT_OBJECT_0 && r < WAIT_OBJECT_0 + handles.size ()) { HANDLE h = handles[r - WAIT_OBJECT_0]; if (h == wd.mpt.get ()) { if (wd.master_refreshing) { std::wostringstream ss; ss << L"Unexpected exit ("; DWORD code; if (GetExitCodeThread (wd.mpt.get (), &code)) ss << code << ')'; else ss << wstrerror (GetLastError ()) << L" while getting exit code)"; wd.on_master_error (ss.str ()); } wd.mpt.reset (nullptr); } } else { std::wostringstream ss; ss << L"MsgWaitForMultipleObjects returned an unexpected value: " << r; MessageBox (hWnd, ss.str ().c_str (), L"Qarma", 0); } } }
__stdcall unsigned int master_proto (void* _args) { master_proto_args args = *reinterpret_cast<master_proto_args*> (_args); PostMessage (args.hwnd, qm_master_begin, args.id, 0); std::unique_ptr<addrinfo, decltype(&freeaddrinfo)> lookup (nullptr, freeaddrinfo); { std::default_random_engine reng (std::chrono::system_clock::now ().time_since_epoch ().count ()); std::uniform_int_distribution<> rdist (0, 19); std::ostringstream host; host << "arma2oapc.ms" << rdist (reng) << ".gamespy.com"; addrinfo hints = addrinfo (); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; addrinfo* tmp; int r = getaddrinfo (host.str ().c_str (), "28910", &hints, &tmp); // TODO load balance if (r) { SendMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (wstrerror (WSAGetLastError ()).c_str ())); return 0; } lookup.reset (tmp); } qsocket socket {lookup->ai_family, lookup->ai_socktype, lookup->ai_protocol}; if (socket == INVALID_SOCKET) { SendMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (wstrerror (WSAGetLastError ()).c_str ())); return 0; } int r = connect (socket, lookup->ai_addr, lookup->ai_addrlen); if (r == SOCKET_ERROR) { SendMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (wstrerror (WSAGetLastError ()).c_str ())); return 0; } // transmit request std::array<unsigned char, 9> master_validate; enctypex_decoder_rand_validate (&master_validate[0]); { std::ostringstream packet; packet << '\0' << '\1' << '\3' << '\0' // 32-bit << '\0' << '\0' << '\0' << "arma2oapc" << '\0' << "gslive" << '\0'; std::copy (master_validate.begin (), master_validate.end () - 1, std::ostreambuf_iterator<char> (packet)); // note: don't copy the final '\0' byte of master_validate packet << "" << '\0' // filter (note, not preceeded by a '\0' separator either << REQUEST << '\0' << '\0' << '\0' << '\0' << '\1'; // 1 = requested information std::vector<char> buf (2 + packet.str ().size ()); WSAHtons (socket, buf.size (), reinterpret_cast<u_short*> (&buf[0])); const std::string s = packet.str (); std::copy (s.begin (), s.end (), 2 + buf.begin ()); int r = send (socket, &buf[0], buf.size (), 0); if (r == SOCKET_ERROR) { SendMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (wstrerror (WSAGetLastError ()).c_str ())); return 0; } else if (r != static_cast<int> (buf.size ())) { PostMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (L"short send")); return 0; } } shutdown (socket, SD_SEND); // XXX error check // read response enctypex_data_t enctypex_data; enctypex_data.start = 0; std::vector<unsigned char> data; data.reserve (16384); while (true) { std::array<char, 8192> buf; int r = recv (socket, &buf[0], buf.size (), 0); if (r == SOCKET_ERROR) { SendMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (wstrerror (WSAGetLastError ()).c_str ())); return 0; } else if (r == 0) { PostMessage (args.hwnd, qm_master_error, args.id, reinterpret_cast<LPARAM> (L"short recv")); return 0; } std::copy (buf.begin (), buf.begin () + r, std::back_inserter (data)); PostMessage (args.hwnd, qm_master_progress, args.id, data.size ()); int len = data.size (); unsigned char* endp = enctypex_decoder (reinterpret_cast<unsigned char*> (const_cast<char*> ("Xn221z")), &master_validate[0], &data[0], &len, &enctypex_data); assert (endp); if (endp && enctypex_decoder_convert_to_ipport (endp, data.size () - (reinterpret_cast<unsigned char*> (endp) - &data[0]), nullptr, nullptr, 0, 0)) { break; } } shutdown (socket, SD_RECEIVE); // XXX handle errors static_assert (sizeof (server_endpoint) == 6, "server_endpoint is a weird size"); { std::vector<server_endpoint> decoded_data (data.size () / 5); // XXX size seems like a bit of a guess! int len = enctypex_decoder_convert_to_ipport (&data[0] + enctypex_data.start, data.size () - enctypex_data.start, reinterpret_cast<unsigned char*> (decoded_data.data ()), nullptr, 0, 0); assert (len >= 0); // XXX handle (see gsmyfunc.h line 715) for (auto ep: decoded_data) SendMessage (args.hwnd, qm_master_found, args.id, reinterpret_cast<LPARAM> (&ep)); } PostMessage (args.hwnd, qm_master_complete, args.id, 0); return 0; }