bool CNet::InitWinsock() { // can't initialize twice if ( m_bInitialized ) return false; #ifdef ARCHDEF_PLATFORM_WIN32 // here we start up winsock WSADATA WSAData; int error = WSAStartup(MAKEWORD(2,2), &WSAData); if ( error != 0 ) { CLog::Error(CNet::m_Errors[error].c_str(), __FUNCTION__); return false; } if ( WSAData.wVersion != MAKEWORD(2,2) ) { // couldn't get the right version CLog::Error("Winsock 2.2 required", __FUNCTION__); CloseWinsock(); return false; } #endif m_bInitialized = true; // CLog::Error("Winsock initialized", __FUNCTION__); return true; }
CNet::~CNet(void) { if ( m_bInitialized ) { CloseWinsock(); } }
// Return port number listening on, return 0 if failed to listen int StartListen(int Port) { // If winsock doesn't start return false if (!StartWinsock()) return 0; // Limit port to 1-32767 range if ((Port < 1) || (Port > 32767)) Port = 80; SocketListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (SocketListen == INVALID_SOCKET) { SocketListen = NULL; return 0; } sockaddr_in SockAddr; SockAddr.sin_family = AF_INET; SockAddr.sin_port = htons(Port); SockAddr.sin_addr.S_un.S_addr = INADDR_ANY; int Result = bind(SocketListen, (sockaddr*)(&SockAddr), sizeof(SockAddr)); if (Result != 0) { CloseWinsock(); SocketListen = NULL; return 0; } listen(SocketListen, 1); WSAAsyncSelect(SocketListen, fMain, WM_SOCKET, FD_CONNECT | FD_ACCEPT); return Port; };
LRESULT CALLBACK WndProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam) { switch (Message) { case WM_SOCKET: { switch (WSAGETSELECTEVENT(lParam)) { case FD_READ: { // Look pointer to Client using wParam (Socket) Client *pClient = NULL; if (Clients.find((SOCKET)wParam) != Clients.end()) pClient = Clients[(SOCKET)wParam]; // Retrieve data available char Buffer[BUFFER_LENGTH]; int BufferLength = recv((SOCKET)wParam, Buffer, BUFFER_LENGTH, 0); if (BufferLength) { // Create Data variable and fill with unprocessed data and new data std::vector<char> Data(pClient->Buffer); Data.insert(Data.end(), Buffer, Buffer + BufferLength); do { // Get length of current packet DWORD PacketLength; memcpy(&PacketLength, &Data[1], 4); /* If length of buffer now exceeds or is equal to size of packet, then / process the packet. Otherwise keep appending newly received / data until a full packet has been accumlated. */ if (Data.size() >= (int)PacketLength) { // Parse packet data to Client class Packet CurrentPacket(std::vector<char>(Data.begin(), Data.begin() + (int)PacketLength)); pClient->ParsePacket(CurrentPacket); // Erase Packet from remaining data Data.erase(Data.begin(), Data.begin() + (int)PacketLength); // Clear Client's buffered data pClient->Buffer.clear(); } else { // If not enough data for a complete packet, add remaining data to Client's buffer pClient->Buffer.clear(); pClient->Buffer = Data; Data.clear(); } } while (!Data.empty()); } } break; case FD_CLOSE: { // Look up pointer to Client using wParam (Socket) Client *pClient = NULL; if (Clients.find((SOCKET)wParam) != Clients.end()) pClient = Clients[(SOCKET)wParam]; // Delete Client delete pClient; } break; case FD_ACCEPT: { if (wParam == SocketListen) { // Create new Client Client *NewClient = new Client(SocketListen); Clients[NewClient->Socket()] = NewClient; } } break; case FD_WRITE: // break; case FD_CONNECT: // break; default: ; } } break; case WM_COMMAND: { if (LOWORD(wParam) == (WORD)IDM_START) { // Create 'imgs' directory to store files if doesn't already exists CreateImageDirectory(); // Get port from textbox int Length = SendMessage(tPort, WM_GETTEXTLENGTH, NULL, NULL); std::wstring Text; if (Length > 0) { std::vector<WCHAR> Buffer(Length + 1); SendMessage(tPort, WM_GETTEXT, Buffer.size(), (LPARAM)&Buffer[0]); Text = &Buffer[0]; } // Convert variable types wstring -> string -> int std::string Port(Text.begin(), Text.end()); int iStartListen = StartListen(atoi(Port.c_str())); if (iStartListen) { EnableWindow(lPort, (int)false); EnableWindow(tPort, (int)false); EnableWindow(bStart, (int)false); EnableWindow(bClose, (int)true); std::wstringstream wsPort; wsPort << iStartListen; SendMessage(tPort, WM_SETTEXT, NULL, (LPARAM)wsPort.str().c_str()); AddLog(L"Server listening on " + GetLocalIP() + L" using port " + wsPort.str().c_str() + L"."); } else AddLog(L"Failed to start server."); } else if (LOWORD(wParam) == (WORD)IDM_CLOSE) { CloseWinsock(); EnableWindow(bClose, (int)false); EnableWindow(lPort, (int)true); EnableWindow(tPort, (int)true); EnableWindow(bStart, (int)true); SendMessage(lsClients, LB_RESETCONTENT, 0, 0); SendMessage(lsFiles, LB_RESETCONTENT, 0, 0); for (int i = 0; i < USERS_COUNT;) Users[i++].LoggedIn = false; std::list<File *>::iterator itFile = Files.begin(); // Clear file list and clear remaining objects while (itFile != Files.end()) delete *itFile++; Files.clear(); AddLog(L"Server closed."); } } break; case WM_CREATE: { // Set hWnd here as WM_CREATE executes before CreateWindowEx() returns fMain = hWnd; // Start window center screen RECT Rect; if (GetWindowRect(hWnd, &Rect)) { int Width, Height, Left, Top; Width = Rect.right - Rect.left; Height = Rect.bottom - Rect.top; Left = (GetSystemMetrics(SM_CXSCREEN) - Width) / 2; Top = (GetSystemMetrics(SM_CYSCREEN) - Height) / 2; SetWindowPos(hWnd, NULL, Left, Top, NULL, NULL, SWP_NOZORDER | SWP_NOSIZE); } // Create controls lPort = CreateWindow(L"EDIT", L"Port:", DefaultStyles | ES_RIGHT, 16, 16, 33, 25, hWnd, 0, 0, 0); if (lPort) SetFont(lPort); tPort = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", L"80", DefaultStyles | ES_NUMBER, 56, 16, 81, 24, hWnd, 0, WinInstance, 0); if (tPort) { SetFont(tPort); SendMessage(tPort, EM_LIMITTEXT, (WPARAM)5, NULL); // Set max length to 5 characters } bStart = CreateWindowEx(0, L"Button", L"&Start Server", DefaultStyles, 144, 8, 113, 33, hWnd, IDM_START, WinInstance, NULL); if (bStart) SetFont(bStart); bClose = CreateWindowEx(0, L"Button", L"&Close Server", DefaultStyles | WS_DISABLED, 264, 8, 113, 33, hWnd, IDM_CLOSE, WinInstance, NULL); if (bClose) SetFont(bClose); tLog = CreateWindowEx(WS_EX_CLIENTEDGE, L"Edit", L"", DefaultStyles | ES_READONLY | ES_MULTILINE | WS_VSCROLL | ES_AUTOVSCROLL, 16, 48, 450, 344, hWnd, 0, WinInstance, 0); if (tLog) SetFont(tLog); lsClients = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", L"", DefaultStyles | WS_VSCROLL, 480, 48, 376, 280, hWnd, 0, WinInstance, 0); if (lsClients) SetFont(lsClients); lsFiles = CreateWindowEx(WS_EX_CLIENTEDGE, L"Listbox", L"", DefaultStyles | WS_VSCROLL, 16, 400, 840, 220, hWnd, 0, WinInstance, 0); if (lsFiles) SetFont(lsFiles); } break; case WM_CLOSE: DestroyWindow(hWnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, Message, wParam, lParam); } return 0; }