Add listen loop, error messages, ip4 & 6 support

This commit is contained in:
Grayson Riffe 2023-09-21 13:56:59 -05:00
parent cebbb1dc19
commit 3053a0b8f8
3 changed files with 102 additions and 60 deletions

View File

@ -24,8 +24,21 @@ namespace wc {
Application::Application(std::string& appName, std::string& appVersion) Application::Application(std::string& appName, std::string& appVersion)
: m_appName(appName.begin(), appName.end()) : m_appName(appName.begin(), appName.end())
, m_appVersion(appVersion.begin(), appVersion.end()) , m_appVersion(appVersion.begin(), appVersion.end())
, m_running(true)
{ {
std::wcout << std::format(L"{} {}\n", m_appName, m_appVersion); 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() { void Application::run() {
@ -50,75 +63,68 @@ namespace wc {
input = new MainDlgInput{ this, x, y }; input = new MainDlgInput{ this, x, y };
} }
m_running = false;
listenThread.join(); listenThread.join();
} }
void Application::startListen() { 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; addrinfo* hostInfo = nullptr;
hints.ai_family = AF_UNSPEC; getaddrinfo("::", "9430", nullptr, &hostInfo);
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(nullptr, "9430", &hints, &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) { 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); std::exit(1);
} }
unsigned long yes = 1;
unsigned long no = 0;
setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&no), sizeof(no));
if (bind(sock, hostInfo->ai_addr, static_cast<int>(hostInfo->ai_addrlen)) != 0) { if (bind(sock, hostInfo->ai_addr, static_cast<int>(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); std::exit(1);
} }
freeaddrinfo(hostInfo); freeaddrinfo(hostInfo);
listen(sock, 1); listen(sock, 1);
sockaddr_storage remoteAddr = { }; ioctlsocket(sock, FIONBIO, &yes);
sockaddr_in6 remoteAddr = { };
int remoteSize = sizeof(remoteAddr); int remoteSize = sizeof(remoteAddr);
SOCKET conSock = accept(sock, reinterpret_cast<sockaddr*>(&remoteAddr), &remoteSize); SOCKET conSock = INVALID_SOCKET;
if (conSock == INVALID_SOCKET) { int errorCode = 0;
std::cerr << std::format("Error: could not accept connection!\n");; while (m_running) {
std::exit(1); conSock = accept(sock, reinterpret_cast<sockaddr*>(&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; ioctlsocket(conSock, FIONBIO, &no);
remoteStr.resize(INET6_ADDRSTRLEN);
void* addrLocation = nullptr;
if (remoteAddr.ss_family == AF_INET) {
addrLocation = reinterpret_cast<void*>(&reinterpret_cast<sockaddr_in*>(&remoteAddr)->sin_addr);
}
else if (remoteAddr.ss_family = AF_INET6) {
addrLocation = reinterpret_cast<void*>(&reinterpret_cast<sockaddr_in6*>(&remoteAddr)->sin6_addr);
}
inet_ntop(remoteAddr.ss_family, addrLocation, remoteStr.data(), INET6_ADDRSTRLEN);
std::cout << std::format("Connected to: {}\n", remoteStr);
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; std::string buf(1000, 0);
while (bytesRecvd = recv(conSock, buf.data(), 1000, 0)) { int bytesRecvd = 0;
buf.resize(bytesRecvd); while (bytesRecvd = recv(conSock, buf.data(), 1000, NULL)) {
std::cout << std::format("Remote: {}\n", buf); buf.resize(bytesRecvd);
buf.resize(1000); std::cout << std::format("Remote: {}\n", buf);
buf.resize(1000);
}
closesocket(conSock);
} }
closesocket(conSock);
closesocket(sock); closesocket(sock);
WSACleanup();
} }
BOOL CALLBACK Application::mainDlgProc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam) { 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); SetWindowPos(dlg, nullptr, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName.c_str()); SetDlgItemText(dlg, IDC_STATICTITLE, app->m_appName.c_str());
LOGFONT lFont = { }; LOGFONT lFont = { .lfHeight = 50 };
lFont.lfHeight = 50;
HFONT font = CreateFontIndirect(&lFont); HFONT font = CreateFontIndirect(&lFont);
SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast<LPARAM>(font), NULL); SendMessage(GetDlgItem(dlg, IDC_STATICTITLE), WM_SETFONT, reinterpret_cast<LPARAM>(font), NULL);
@ -163,11 +168,19 @@ namespace wc {
case WM_COMMAND: case WM_COMMAND:
switch (LOWORD(wParam)) { switch (LOWORD(wParam)) {
case IDC_BUTTONCONNECT: { 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<LPARAM>(&balloon));
return TRUE;
}
std::wstring address; std::wstring address;
address.resize(GetWindowTextLength(GetDlgItem(dlg, IDC_EDITADDRESS))); address.resize(addressSize);
GetDlgItemText(dlg, IDC_EDITADDRESS, address.data(), static_cast<int>(address.size() + 1)); GetDlgItemText(dlg, IDC_EDITADDRESS, address.data(), static_cast<int>(address.size() + 1));
std::wstring screenname; std::wstring screenname;
screenname.resize(GetWindowTextLength(GetDlgItem(dlg, IDC_EDITSCREENNAME))); screenname.resize(screennameSize);
GetDlgItemText(dlg, IDC_EDITSCREENNAME, screenname.data(), static_cast<int>(screenname.size() + 1)); GetDlgItemText(dlg, IDC_EDITSCREENNAME, screenname.data(), static_cast<int>(screenname.size() + 1));
RECT dlgRect = { }; RECT dlgRect = { };
@ -203,6 +216,6 @@ namespace wc {
} }
Application::~Application() { Application::~Application() {
WSACleanup();
} }
} }

View File

@ -17,5 +17,6 @@ namespace wc {
const std::wstring m_appName; const std::wstring m_appName;
const std::wstring m_appVersion; const std::wstring m_appVersion;
bool m_running;
}; };
} }

View File

@ -12,21 +12,49 @@ namespace wc {
} }
void Chat::run() { void Chat::run() {
addrinfo hints = { };
addrinfo* destInfo = nullptr; addrinfo* destInfo = nullptr;
hints.ai_family = AF_UNSPEC; if (getaddrinfo(toStr(m_address).c_str(), "9430", nullptr, &destInfo) != 0) {
hints.ai_socktype = SOCK_STREAM; MessageBox(nullptr, L"Error: Could not resolve host or invalid address!", L"Error", MB_ICONERROR);
getaddrinfo(toStr(m_address).c_str(), "9430", &hints, &destInfo); 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) { 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); freeaddrinfo(destInfo);
return;
} }
if (connect(sock, destInfo->ai_addr, static_cast<int>(destInfo->ai_addrlen)) != 0) { if (connect(sock, destInfo->ai_addr, static_cast<int>(destInfo->ai_addrlen)) != 0) {
std::cerr << std::format("Error: could not connect to destination!\n"); int errorCode = WSAGetLastError();
std::exit(1); 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); freeaddrinfo(destInfo);
@ -34,7 +62,7 @@ namespace wc {
std::string data; std::string data;
while (data != "end") { while (data != "end") {
std::getline(std::cin, data); std::getline(std::cin, data);
send(sock, data.data(), static_cast<int>(data.size()), 0); send(sock, data.data(), static_cast<int>(data.size()), NULL);
} }
closesocket(sock); closesocket(sock);