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)
: 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<char*>(&no), sizeof(no));
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);
}
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<sockaddr*>(&remoteAddr), &remoteSize);
if (conSock == INVALID_SOCKET) {
std::cerr << std::format("Error: could not accept connection!\n");;
SOCKET conSock = INVALID_SOCKET;
int errorCode = 0;
while (m_running) {
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;
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);
ioctlsocket(conSock, FIONBIO, &no);
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);
std::string buf(1000, 0);
int bytesRecvd = 1;
while (bytesRecvd = recv(conSock, buf.data(), 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(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<LPARAM>(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<LPARAM>(&balloon));
return TRUE;
}
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));
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));
RECT dlgRect = { };
@ -203,6 +216,6 @@ namespace wc {
}
Application::~Application() {
WSACleanup();
}
}

View File

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

View File

@ -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<int>(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<int>(data.size()), 0);
send(sock, data.data(), static_cast<int>(data.size()), NULL);
}
closesocket(sock);