From 3053a0b8f880eab3a41f5dc71c8a0d13c80ab9a8 Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Thu, 21 Sep 2023 13:56:59 -0500 Subject: [PATCH] Add listen loop, error messages, ip4 & 6 support --- WinChat/src/Application.cpp | 113 ++++++++++++++++++++---------------- WinChat/src/Application.h | 1 + WinChat/src/Chat.cpp | 48 +++++++++++---- 3 files changed, 102 insertions(+), 60 deletions(-) diff --git a/WinChat/src/Application.cpp b/WinChat/src/Application.cpp index ebcd8a4..cc4233b 100644 --- a/WinChat/src/Application.cpp +++ b/WinChat/src/Application.cpp @@ -24,8 +24,21 @@ namespace wc { Application::Application(std::string& appName, std::string& appVersion) : m_appName(appName.begin(), appName.end()) , m_appVersion(appVersion.begin(), appVersion.end()) + , m_running(true) { std::wcout << std::format(L"{} {}\n", m_appName, m_appVersion); + + //Initialize Windows Sockets 2 + WSADATA data = { }; + if (WSAStartup(MAKEWORD(2, 2), &data) != 0) { + MessageBox(nullptr, L"Error: could not initialize WinSock 2!", L"Error", MB_ICONERROR); + std::exit(1); + } + + if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2) { + MessageBox(nullptr, L"Error: WinSock version 2.2 not available!", L"Error", MB_ICONERROR); + std::exit(1); + } } void Application::run() { @@ -50,75 +63,68 @@ namespace wc { input = new MainDlgInput{ this, x, y }; } + m_running = false; listenThread.join(); } void Application::startListen() { - WSADATA data = { }; - if (WSAStartup(MAKEWORD(2, 2), &data) != 0) { - std::cerr << std::format("Error: could not initialize WinSock 2!\n"); - std::exit(1); - } - - if (LOBYTE(data.wVersion) != 2 || HIBYTE(data.wVersion) != 2) { - std::cerr << std::format("Error: WinSock version 2.2 not available!\n"); - std::exit(1); - } - - addrinfo hints = { }; addrinfo* hostInfo = nullptr; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE; - getaddrinfo(nullptr, "9430", &hints, &hostInfo); + getaddrinfo("::", "9430", nullptr, &hostInfo); - SOCKET sock = socket(hostInfo->ai_family, hostInfo->ai_socktype, hostInfo->ai_protocol); + SOCKET sock = socket(AF_INET6, SOCK_STREAM, NULL); if (sock == INVALID_SOCKET) { - std::cerr << std::format("Error: could not create network socket!\n"); + MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR); std::exit(1); } + unsigned long yes = 1; + unsigned long no = 0; + setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&no), sizeof(no)); + if (bind(sock, hostInfo->ai_addr, static_cast(hostInfo->ai_addrlen)) != 0) { - std::cerr << std::format("Error: could not bind network socket!\n"); + MessageBox(nullptr, L"Error: could not bind network socket!", L"Error", MB_ICONERROR); std::exit(1); } freeaddrinfo(hostInfo); listen(sock, 1); - sockaddr_storage remoteAddr = { }; + ioctlsocket(sock, FIONBIO, &yes); + + sockaddr_in6 remoteAddr = { }; int remoteSize = sizeof(remoteAddr); - SOCKET conSock = accept(sock, reinterpret_cast(&remoteAddr), &remoteSize); - if (conSock == INVALID_SOCKET) { - std::cerr << std::format("Error: could not accept connection!\n");; - std::exit(1); - } + SOCKET conSock = INVALID_SOCKET; + int errorCode = 0; + while (m_running) { + conSock = accept(sock, reinterpret_cast(&remoteAddr), &remoteSize); + errorCode = WSAGetLastError(); + if (errorCode && errorCode != WSAEWOULDBLOCK) { + MessageBox(nullptr, L"Error: could not accept connection!", L"Error", MB_ICONERROR); + std::exit(1); + } + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + if (errorCode == WSAEWOULDBLOCK) + continue; - std::string remoteStr; - remoteStr.resize(INET6_ADDRSTRLEN); - void* addrLocation = nullptr; - if (remoteAddr.ss_family == AF_INET) { - addrLocation = reinterpret_cast(&reinterpret_cast(&remoteAddr)->sin_addr); - } - else if (remoteAddr.ss_family = AF_INET6) { - addrLocation = reinterpret_cast(&reinterpret_cast(&remoteAddr)->sin6_addr); - } - inet_ntop(remoteAddr.ss_family, addrLocation, remoteStr.data(), INET6_ADDRSTRLEN); - std::cout << std::format("Connected to: {}\n", remoteStr); + ioctlsocket(conSock, FIONBIO, &no); - std::string buf(1000, 0); + std::string remoteStr(INET6_ADDRSTRLEN, 0); + inet_ntop(AF_INET6, &remoteAddr.sin6_addr, remoteStr.data(), INET6_ADDRSTRLEN); + remoteStr.resize(remoteStr.find_first_of('\0', 0)); + std::cout << std::format("Connected to: {}\n", remoteStr); - int bytesRecvd = 1; - while (bytesRecvd = recv(conSock, buf.data(), 1000, 0)) { - buf.resize(bytesRecvd); - std::cout << std::format("Remote: {}\n", buf); - buf.resize(1000); + std::string buf(1000, 0); + int bytesRecvd = 0; + while (bytesRecvd = recv(conSock, buf.data(), 1000, NULL)) { + buf.resize(bytesRecvd); + std::cout << std::format("Remote: {}\n", buf); + buf.resize(1000); + } + + closesocket(conSock); } - closesocket(conSock); - closesocket(sock); - WSACleanup(); } BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { @@ -145,8 +151,7 @@ namespace wc { SetWindowPos(dlg, nullptr, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName.c_str()); - LOGFONT lFont = { }; - lFont.lfHeight = 50; + LOGFONT lFont = { .lfHeight = 50 }; HFONT font = CreateFontIndirect(&lFont); SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast(font), NULL); @@ -163,11 +168,19 @@ namespace wc { case WM_COMMAND: switch (LOWORD(wParam)) { case IDC_BUTTONCONNECT: { + int addressSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS)); + int screennameSize = GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME)); + if (!addressSize || !screennameSize) { + EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"You must enter an address and screenname." }; + SendDlgItemMessage(dlg, addressSize ? IDC_EDITSCREENNAME : IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast(&balloon)); + return TRUE; + } + std::wstring address; - address.resize(GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS))); + address.resize(addressSize); GetDlgItemText(dlg, IDC_EDITADDRESS, address.data(), static_cast(address.size() + 1)); std::wstring screenname; - screenname.resize(GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME))); + screenname.resize(screennameSize); GetDlgItemText(dlg, IDC_EDITSCREENNAME, screenname.data(), static_cast(screenname.size() + 1)); RECT dlgRect = { }; @@ -203,6 +216,6 @@ namespace wc { } Application::~Application() { - + WSACleanup(); } } \ No newline at end of file diff --git a/WinChat/src/Application.h b/WinChat/src/Application.h index e4482cb..a0d5c20 100644 --- a/WinChat/src/Application.h +++ b/WinChat/src/Application.h @@ -17,5 +17,6 @@ namespace wc { const std::wstring m_appName; const std::wstring m_appVersion; + bool m_running; }; } \ No newline at end of file diff --git a/WinChat/src/Chat.cpp b/WinChat/src/Chat.cpp index 0d612a1..679c211 100644 --- a/WinChat/src/Chat.cpp +++ b/WinChat/src/Chat.cpp @@ -12,21 +12,49 @@ namespace wc { } void Chat::run() { - addrinfo hints = { }; addrinfo* destInfo = nullptr; - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - getaddrinfo(toStr(m_address).c_str(), "9430", &hints, &destInfo); + if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) { + MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR); + return; + } - SOCKET sock = socket(destInfo->ai_family, destInfo->ai_socktype, destInfo->ai_protocol); + SOCKET sock = socket(destInfo->ai_family, SOCK_STREAM, NULL); if (sock == INVALID_SOCKET) { - std::cerr << std::format("Error: could not create network socket!\n"); - std::exit(1); + MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR); + freeaddrinfo(destInfo); + return; } if (connect(sock, destInfo->ai_addr, static_cast(destInfo->ai_addrlen)) != 0) { - std::cerr << std::format("Error: could not connect to destination!\n"); - std::exit(1); + int errorCode = WSAGetLastError(); + std::wstring errorStr; + switch (errorCode) { + case WSAETIMEDOUT: + errorStr = L"Timed out"; + break; + + case WSAECONNREFUSED: + errorStr = L"Connection refused (WinChat may not be running on remote host)"; + break; + + case WSAENETUNREACH: + case WSAEHOSTUNREACH: + errorStr = L"Remote host unreachable (You may not be connected to the internet)"; + break; + + case WSAEADDRNOTAVAIL: + errorStr = L"Not a valid address to connect to"; + break; + + default: + errorStr = std::format(L"Error Code {}", errorCode); + break; + } + + MessageBox(nullptr, std::format(L"Error: Could not connect - {}", errorStr).c_str(), L"Error", MB_ICONERROR); + freeaddrinfo(destInfo); + closesocket(sock); + return; } freeaddrinfo(destInfo); @@ -34,7 +62,7 @@ namespace wc { std::string data; while (data != "end") { std::getline(std::cin, data); - send(sock, data.data(), static_cast(data.size()), 0); + send(sock, data.data(), static_cast(data.size()), NULL); } closesocket(sock);