From 8f66edfa0413798b460bbc75481c8abd260a59f9 Mon Sep 17 00:00:00 2001 From: Grayson Riffe Date: Mon, 9 Oct 2023 13:50:17 -0500 Subject: [PATCH] Connect to any port and add quick start --- WinChat/WinChat.rc | Bin 11218 -> 11516 bytes WinChat/resource.h | 6 ++- WinChat/src/Application.cpp | 73 +++++++++++++++++++++++++++--------- WinChat/src/Application.h | 4 +- WinChat/src/Chat.cpp | 15 ++++---- WinChat/src/Chat.h | 3 +- WinChat/src/main.cpp | 5 +-- 7 files changed, 74 insertions(+), 32 deletions(-) diff --git a/WinChat/WinChat.rc b/WinChat/WinChat.rc index 0116b46fdc258020789c343328cb28cff1144bb2..ab3e20c51bb069d90a1a347ecd80590bff074720 100644 GIT binary patch delta 149 zcmcZ<{wH$76COr`%};rbGfrN@t0nBi;K>lo5W?Wf;KvZa;Li}m5HeYjM^YJ!ID-y@ z84z1C7ywB_2BXQmeA<)uN%2h*65D)%Pe)ulkfD?znIW4&0cc_gLn1>FkW^yOnJlQL bJlRZ5KroOYl);(78*HB=$fnH~RT(mainDlgProc), reinterpret_cast(input))) { //Create a Chat with the collected input or the incoming connection MainDlgOutput* output = reinterpret_cast(result); - const auto [address, screenname, x, y, inSocket] = *output; + const auto [address, port, screenname, x, y, inSocket] = *output; delete output; { - Chat chat(address, screenname); + Chat chat(address, port, screenname); chat.run(x, y, inSocket); } @@ -74,9 +80,6 @@ namespace wc { } void Application::startListen() { - addrinfo* hostInfo = nullptr; - getaddrinfo("::", "9430", nullptr, &hostInfo); - SOCKET sock = socket(AF_INET6, SOCK_STREAM, NULL); if (sock == INVALID_SOCKET) { MessageBox(nullptr, L"Error: could not create network socket!", L"Error", MB_ICONERROR); @@ -87,16 +90,23 @@ namespace wc { unsigned long no = 0; setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast(&no), sizeof(no)); - while (bind(sock, hostInfo->ai_addr, static_cast(hostInfo->ai_addrlen)) != 0) { - freeaddrinfo(hostInfo); - getaddrinfo("::", "9431", nullptr, &hostInfo); - } + int tryPort = m_defaultPort - 1; + addrinfo* hostInfo = nullptr; + do { + freeaddrinfo(hostInfo); + tryPort++; + getaddrinfo("::", std::to_string(tryPort).c_str(), nullptr, &hostInfo); + } while (bind(sock, hostInfo->ai_addr, static_cast(hostInfo->ai_addrlen)) != 0); + + m_listenPort = tryPort; freeaddrinfo(hostInfo); listen(sock, 1); ioctlsocket(sock, FIONBIO, &yes); + m_running = true; + sockaddr_in6 remoteAddr = { }; int remoteSize = sizeof(remoteAddr); SOCKET conSock = INVALID_SOCKET; @@ -160,8 +170,9 @@ namespace wc { HFONT font = CreateFontIndirect(&lFont); SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast(font), NULL); SetDlgItemText(dlg, IDC_STATICDESC, L"A simple Windows chat app"); - SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SETCUEBANNER, TRUE, reinterpret_cast(L"Address")); + SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SETCUEBANNER, TRUE, reinterpret_cast(L"Address(/Port)")); SendDlgItemMessage(dlg, IDC_EDITSCREENNAME, EM_SETCUEBANNER, TRUE, reinterpret_cast(L"User")); + SetDlgItemText(dlg, IDC_STATICLISTENPORT, std::format(L"Listening on port {}", app->m_listenPort).c_str()); SetTimer(dlg, IDT_CHECKINCONN, 100, nullptr); @@ -186,17 +197,43 @@ namespace wc { screenname.resize(screennameSize); GetDlgItemText(dlg, IDC_EDITSCREENNAME, screenname.data(), static_cast(screenname.size() + 1)); + //Check port if present + std::wstring port; + size_t portStart = address.find(L"/"); + if (portStart != std::wstring::npos) { + port = address.substr(portStart + 1); + address.resize(portStart); + bool isANumber = std::all_of(port.begin(), port.end(), [](wchar_t in) {return std::isdigit(in); }); + + if (port.empty() || !isANumber || std::stoi(port) < 1024 || std::stoi(port) > 49151) { + EDITBALLOONTIP balloon = { .cbStruct = sizeof(balloon), .pszTitle = L"Alert", .pszText = L"An invalid port was entered." }; + SendDlgItemMessage(dlg, IDC_EDITADDRESS, EM_SHOWBALLOONTIP, NULL, reinterpret_cast(&balloon)); + return TRUE; + } + } + else + port = std::to_wstring(app->m_defaultPort); + RECT dlgRect = { }; GetWindowRect(dlg, &dlgRect); - EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ address, screenname, dlgRect.left, dlgRect.top, INVALID_SOCKET })); + EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ address, port, screenname, dlgRect.left, dlgRect.top, INVALID_SOCKET })); return TRUE; } - case ID_HELP_ABOUT: { - MessageBox(dlg, std::format(L"{} {}\nGrayson Riffe 2023", app->m_appName, app->m_appVersion).c_str(), L"About", MB_OK); + case ID_HELP_QUCKSTART: { + std::wstring helpStr = L"To start a chat, start the program on both computers\n" + "and enter the IP address or hostname of one into the other's address box.\n\n" + "If the program is not listening on the default port of {}, the\n" + "other computer must enter this port when connecting to it."; + std::wstring defPortStr = std::to_wstring(app->m_defaultPort); + MessageBox(dlg, std::vformat(helpStr, std::make_wformat_args(defPortStr)).c_str(), L"Quick Start", MB_OK); return TRUE; } + case ID_HELP_ABOUT: + MessageBox(dlg, std::format(L"{} {}\nGrayson Riffe 2023", app->m_appName, app->m_appVersion).c_str(), L"About", MB_OK); + return TRUE; + case IDC_BUTTONEXIT: case ID_FILE_EXIT: case IDCANCEL: //Escape key press @@ -225,7 +262,7 @@ namespace wc { MainDlgOutput* out = reinterpret_cast(result); - EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ app->m_inAddress, out->screenname, dlgRect.left, dlgRect.top, tempSock })); + EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ app->m_inAddress, std::wstring(), out->screenname, dlgRect.left, dlgRect.top, tempSock })); delete out; return TRUE; } @@ -269,7 +306,7 @@ namespace wc { std::wstring buffer(inputLength, 0); GetDlgItemText(dlg, IDC_EDITSCREENNAME, buffer.data(), static_cast(buffer.size() + 1)); - EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ std::wstring(), buffer, NULL, NULL, INVALID_SOCKET })); + EndDialog(dlg, reinterpret_cast(new MainDlgOutput{ std::wstring(), std::wstring(), buffer, NULL, NULL, INVALID_SOCKET })); return TRUE; } diff --git a/WinChat/src/Application.h b/WinChat/src/Application.h index d7c55f3..e1fc9fe 100644 --- a/WinChat/src/Application.h +++ b/WinChat/src/Application.h @@ -7,7 +7,7 @@ namespace wc { class Application { public: - Application(std::string& appName, std::string& appVersion); + Application(const std::string& appName, const std::string& appVersion, const int defaultPort); void run(); @@ -19,6 +19,8 @@ namespace wc { const std::wstring m_appName; const std::wstring m_appVersion; + const int m_defaultPort; + int m_listenPort; bool m_running; std::atomic m_inSocket; diff --git a/WinChat/src/Chat.cpp b/WinChat/src/Chat.cpp index 75defdc..0d0db8f 100644 --- a/WinChat/src/Chat.cpp +++ b/WinChat/src/Chat.cpp @@ -13,8 +13,9 @@ namespace wc { int xPos, yPos; }; - Chat::Chat(std::wstring address, std::wstring screenname) + Chat::Chat(std::wstring address, std::wstring port, std::wstring screenname) : m_address(address) + , m_port(port) , m_screenname(screenname) , m_remoteScreenname(1000, 0) , m_connected(false) @@ -45,7 +46,7 @@ namespace wc { SOCKET sock = inSocket; if (sock == INVALID_SOCKET) { addrinfo* destInfo = nullptr; - if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) { + if (getaddrinfo(toStr(m_address).c_str(), toStr(m_port).c_str(), nullptr, &destInfo) != 0) { MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR); m_connectionError = true; return; @@ -128,7 +129,7 @@ namespace wc { break; case WSAECONNREFUSED: - out = L"Connection refused (WinChat may not be running on remote host)"; + out = L"Connection refused"; break; case WSAENETUNREACH: @@ -158,7 +159,7 @@ namespace wc { SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN)))); SetWindowPos(dlg, nullptr, in->xPos + 100, in->yPos + 100, 0, 0, SWP_NOSIZE | SWP_NOZORDER); - SetDlgItemText(dlg, IDC_STATICADDRESS, chat->m_address.c_str()); + SetDlgItemText(dlg, IDC_STATICADDRESS, std::format(L"{} on port {}", chat->m_address, chat->m_port).c_str()); SendDlgItemMessage(dlg, IDC_PROGRESS, PBM_SETMARQUEE, TRUE, NULL); SetTimer(dlg, IDT_CHECKCONN, 100, nullptr); @@ -184,7 +185,7 @@ namespace wc { ChatDlgInput* in = reinterpret_cast(lParam); chat = in->chatPtr; - SetWindowText(dlg, std::format(L"{} - WinChat", chat->m_remoteScreenname).c_str()); + SetWindowText(dlg, std::format(L"Chat with {}", chat->m_remoteScreenname).c_str()); SendMessage(dlg, WM_SETICON, ICON_BIG, reinterpret_cast(LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICONMAIN)))); SetWindowPos(dlg, nullptr, in->xPos - 50, in->yPos - 50, 0, 0, SWP_NOSIZE | SWP_NOZORDER); SendDlgItemMessage(dlg, IDC_EDITCHATINPUT, EM_SETCUEBANNER, TRUE, reinterpret_cast(L"Message")); @@ -210,7 +211,7 @@ namespace wc { GetDlgItemText(dlg, IDC_EDITCHATINPUT, buffer.data(), static_cast(buffer.size() + 1)); chat->m_sendQueue.push(buffer); - chat->addMessage(dlg, std::format(L"{} - {}", chat->m_screenname, buffer).c_str()); + chat->addMessage(dlg, std::format(L"{} - {}", chat->m_screenname, buffer)); SetDlgItemText(dlg, IDC_EDITCHATINPUT, L""); @@ -233,7 +234,7 @@ namespace wc { std::wstring remoteStr; while (!chat->m_recvQueue.empty()) { remoteStr = chat->m_recvQueue.pop(); - chat->addMessage(dlg, std::format(L"{} - {}", chat->m_remoteScreenname, remoteStr).c_str()); + chat->addMessage(dlg, std::format(L"{} - {}", chat->m_remoteScreenname, remoteStr)); } return TRUE; diff --git a/WinChat/src/Chat.h b/WinChat/src/Chat.h index 314101c..cabad1c 100644 --- a/WinChat/src/Chat.h +++ b/WinChat/src/Chat.h @@ -8,7 +8,7 @@ namespace wc { class Chat { public: - Chat(std::wstring address, std::wstring screenname); + Chat(std::wstring address, std::wstring port, std::wstring screenname); void run(int xPos, int yPos, SOCKET socket); @@ -21,6 +21,7 @@ namespace wc { void addMessage(HWND dlg, std::wstring str); const std::wstring m_address; + const std::wstring m_port; const std::wstring m_screenname; std::wstring m_remoteScreenname; bool m_connected; diff --git a/WinChat/src/main.cpp b/WinChat/src/main.cpp index ca0047a..d2bb93c 100644 --- a/WinChat/src/main.cpp +++ b/WinChat/src/main.cpp @@ -3,13 +3,12 @@ #include "Application.h" #define APPNAME "WinChat" +#define DEFAULTPORT 9430 int main(int argc, char* argv[]) { - std::string appName = APPNAME; - std::string appVer = APPVERSION; { - wc::Application app(appName, appVer); + wc::Application app(APPNAME, APPVERSION, DEFAULTPORT); app.run(); }