// SocketServerDlg.cpp : implementation file // #include "stdafx.h" #include #include #include "resource.h" #include "AboutBox.h" #include "ThreadPool.hpp" #include "SocketServerDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif const int AF_IPV4 = 0; const int AF_IPV6 = 1; const int SOCK_TCP = SOCK_STREAM-1; const int SOCK_UDP = SOCK_DGRAM-1; // CAboutDlg dialog CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD) { } void CAboutDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CAboutDlg, CDialog) END_MESSAGE_MAP() // CSocketServerDlg dialog CSocketServerDlg::CSocketServerDlg(CWnd* pParent /*=NULL*/) : CDialog(CSocketServerDlg::IDD, pParent) , m_nMode(AF_IPV4) , m_nSockType(SOCK_TCP) , m_strPort(_T("2000")) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_SocketServer.SetInterface(this); } CSocketServerDlg::~CSocketServerDlg() { } void CSocketServerDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Text(pDX, IDC_SVR_PORT, m_strPort); DDX_Radio(pDX, IDC_IPV4, m_nMode); DDX_Radio(pDX, IDC_TCP, m_nSockType); DDX_Control(pDX, IDC_TXT_MESSAGE, m_ctlMessage); DDX_Control(pDX, IDC_MESSAGE_LIST, m_ctlMsgList); } BOOL CSocketServerDlg::PreTranslateMessage(MSG* pMsg) { if ( pMsg->message == WM_KEYDOWN ) { if ( pMsg->wParam == VK_RETURN || pMsg->wParam == VK_ESCAPE ) { if ( pMsg->wParam == VK_RETURN ) { TCHAR szClassName[40] = { 0 }; CWnd* pWnd = GetFocus(); if ( pWnd ) { GetClassName(pWnd->GetSafeHwnd(), szClassName, 40); if ( lstrcmpi(_T("EDIT"), szClassName) == 0 ) { return FALSE; } } } return TRUE; } } return CDialog::PreTranslateMessage(pMsg); } BEGIN_MESSAGE_MAP(CSocketServerDlg, CDialog) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_WM_DESTROY() ON_BN_CLICKED(IDC_BTN_START, &CSocketServerDlg::OnBnClickedBtnStart) ON_BN_CLICKED(IDC_BTN_STOP, &CSocketServerDlg::OnBnClickedBtnStop) ON_BN_CLICKED(IDC_BTN_SEND, &CSocketServerDlg::OnBnClickedBtnSend) END_MESSAGE_MAP() // CSocketServerDlg message handlers BOOL CSocketServerDlg::OnInitDialog() { CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here SendDlgItemMessage(IDC_SVR_PORTINC, UDM_SETRANGE32, 2000, 64000); m_ctlMsgList.SetLimitText( 1*1024*1024 ); m_ctlMessage.SetFocus(); SyncControls(); TCHAR szIPAddr[MAX_PATH] = { 0 }; CSocketHandle::GetLocalAddress(szIPAddr, MAX_PATH, AF_INET); AppendText(_T("Local Address (IPv4): %s\r\n"), szIPAddr); CSocketHandle::GetLocalAddress(szIPAddr, MAX_PATH, AF_INET6); AppendText(_T("Local Address (IPv6): %s\r\n"), szIPAddr); return TRUE; // return TRUE unless you set the focus to a control } void CSocketServerDlg::OnSysCommand(UINT nID, LPARAM lParam) { if ((nID & 0xFFF0) == IDM_ABOUTBOX) { CAboutDlg dlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID, lParam); } } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CSocketServerDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } // The system calls this function to obtain the cursor to display while the user drags // the minimized window. HCURSOR CSocketServerDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } void CSocketServerDlg::OnDestroy() { m_SocketServer.Terminate(); CDialog::OnDestroy(); } void CSocketServerDlg::EnableControl(UINT nCtrlID, BOOL bEnable) { GetDlgItem(nCtrlID)->EnableWindow(bEnable); } void CSocketServerDlg::SyncControls() { bool bOpen = m_SocketServer.IsOpen(); EnableControl(IDC_BTN_START, !bOpen); EnableControl(IDC_BTN_STOP, bOpen); EnableControl(IDC_BTN_SEND, bOpen); EnableControl(IDC_IPV4, !bOpen); EnableControl(IDC_IPV6, !bOpen); EnableControl(IDC_TCP, !bOpen); EnableControl(IDC_UDP, !bOpen); } void CSocketServerDlg::GetAddress(const SockAddrIn& addrIn, CString& rString) const { TCHAR szIPAddr[MAX_PATH] = { 0 }; CSocketHandle::FormatIP(szIPAddr, MAX_PATH, addrIn); rString.Format(_T("%s : %d"), szIPAddr, static_cast(static_cast(ntohs(addrIn.GetPort()))) ); } void CSocketServerDlg::AppendText(LPCTSTR lpszFormat, ...) { if ( !::IsWindow(m_ctlMsgList.GetSafeHwnd()) ) return; TCHAR szBuffer[512]; HWND hWnd = m_ctlMsgList.GetSafeHwnd(); DWORD dwResult = 0; if (SendMessageTimeout(hWnd, WM_GETTEXTLENGTH, 0, 0, SMTO_NORMAL, 500L, &dwResult) != 0) { int nLen = (int) dwResult; if (SendMessageTimeout(hWnd, EM_SETSEL, nLen, nLen, SMTO_NORMAL, 500L, &dwResult) != 0) { size_t cb = 0; va_list args; va_start(args, lpszFormat); ::StringCchVPrintfEx(szBuffer, 512, NULL, &cb, 0, lpszFormat, args); va_end(args); SendMessageTimeout(hWnd, EM_REPLACESEL, FALSE, reinterpret_cast(szBuffer), SMTO_NORMAL, 500L, &dwResult); } } } bool CSocketServerDlg::GetDestination(SockAddrIn& addrIn) const { CString strPort; GetDlgItemText(IDC_SVR_PORT, strPort); int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; return addrIn.CreateFrom(NULL, strPort, nFamily); } bool CSocketServerDlg::SetupMCAST() { const TCHAR szIPv4MCAST[] = TEXT("239.121.1.2"); const TCHAR szIPv6MCAST[] = TEXT("FF02:0:0:0:0:0:0:1"); // All Nodes local address bool result = false; if ( m_nSockType == SOCK_UDP ) { if ( m_nMode == AF_IPV4 ) { result = m_SocketServer->AddMembership(szIPv4MCAST, NULL); } else { result = m_SocketServer->AddMembership(szIPv6MCAST, NULL); HRESULT hr = HRESULT_FROM_WIN32(GetLastError()); hr = hr; } } return result; } /////////////////////////////////////////////////////////////////////////////// void CSocketServerDlg::OnThreadBegin(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; SockAddrIn sockAddr; m_SocketServer->GetSockName(sockAddr); GetAddress( sockAddr, strAddr ); AppendText( _T("Server Running on: %s\r\n"), strAddr); } void CSocketServerDlg::OnThreadExit(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); AppendText( _T("Server Down!\r\n")); } void CSocketServerDlg::OnConnectionFailure(CSocketHandle* pSH, SOCKET newSocket) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; if (newSocket != INVALID_SOCKET) { sockHandle.Attach( newSocket ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); sockHandle.Close(); AppendText( _T("Connection abandoned: %s\r\n"), strAddr ); } else { AppendText( _T("Connection abandoned. Not a valid socket.\r\n"), strAddr ); } } void CSocketServerDlg::OnAddConnection(CSocketHandle* pSH, SOCKET newSocket) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr; CSocketHandle sockHandle; SockAddrIn sockAddr; sockHandle.Attach( newSocket ); sockHandle.GetPeerName( sockAddr ); GetAddress( sockAddr, strAddr ); sockHandle.Detach(); AppendText( _T("Connection established: %s\r\n"), strAddr ); } void CSocketServerDlg::OnDataReceived(CSocketHandle* pSH, const BYTE* pbData, DWORD dwCount, const SockAddrIn& addr) { ASSERT( pSH == m_SocketServer ); (pSH); CString strAddr, strText; USES_CONVERSION; LPTSTR pszText = strText.GetBuffer(dwCount+1); ::StringCchCopyN(pszText, dwCount+1, A2CT(reinterpret_cast(pbData)), dwCount); strText.ReleaseBuffer(); GetAddress( addr, strAddr ); AppendText( _T("%s>(%s)\r\n"), strAddr, strText); if (m_nSockType == SOCK_TCP) { // unsafe access to Socket list! #ifdef SOCKHANDLE_USE_OVERLAPPED const SocketBufferList& sl = m_SocketServer.GetSocketList(); for(SocketBufferList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #else const SocketList& sl = m_SocketServer.GetSocketList(); for(SocketList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #endif { CSocketHandle sockHandle; sockHandle.Attach( (*citer) ); SockAddrIn sockAddr; sockHandle.GetPeerName(sockAddr); if( sockAddr == addr ) { int nLen = strAddr.GetLength(); char *pBuffer = new char[nLen]; memcpy(pBuffer, (char *)(LPCTSTR)strAddr, nLen); sockHandle.Write((const LPBYTE)*pBuffer, nLen, NULL); //if(pBuffer) //{ // delete[] pBuffer; // pBuffer = NULL; //} //sockHandle.Write((const LPBYTE)"kklk", strlen("kklk"), NULL); } sockHandle.Detach(); } } else { SockAddrIn servAddr, sockAddr; m_SocketServer->GetSockName(servAddr); GetDestination(sockAddr); if ( servAddr != sockAddr ) { //m_SocketServer.Write((const LPBYTE)(T2CA(strMsg)), strMsg.GetLength(), sockAddr); } else { AppendText( _T("Please change the port number to send message to a client.\r\n") ); } } } void CSocketServerDlg::OnConnectionDropped(CSocketHandle* pSH) { ASSERT( pSH == m_SocketServer ); (pSH); AppendText( _T("Connection lost with client.\r\n") ); } void CSocketServerDlg::OnConnectionError(CSocketHandle* pSH, DWORD dwError) { ASSERT( pSH == m_SocketServer ); (pSH); _com_error err(dwError); AppendText( _T("Communication Error:\r\n%s\r\n"), err.ErrorMessage() ); } void CSocketServerDlg::OnBnClickedBtnStart() { UpdateData(TRUE); CString strPort; GetDlgItemText(IDC_SVR_PORT, strPort); int nFamily = (m_nMode == AF_IPV4) ? AF_INET : AF_INET6; if (!m_SocketServer.StartServer(NULL, strPort, nFamily, (m_nSockType+1))) { MessageBox(_T("Failed to start server."), NULL, MB_ICONSTOP); } SyncControls(); } void CSocketServerDlg::OnBnClickedBtnStop() { m_SocketServer.Terminate(); SyncControls(); } void CSocketServerDlg::OnBnClickedBtnSend() { if ( m_SocketServer.IsOpen() ) { CString strMsg; m_ctlMessage.GetWindowText( strMsg ); if ( strMsg.IsEmpty() ) { AppendText( _T("Please enter the message to send.\r\n") ); return; } USES_CONVERSION; if (m_nSockType == SOCK_TCP) { const LPBYTE lpbData = (const LPBYTE)(T2CA(strMsg)); // unsafe access to Socket list! #ifdef SOCKHANDLE_USE_OVERLAPPED const SocketBufferList& sl = m_SocketServer.GetSocketList(); for(SocketBufferList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #else const SocketList& sl = m_SocketServer.GetSocketList(); for(SocketList::const_iterator citer = sl.begin(); citer != sl.end(); ++citer) #endif { CSocketHandle sockHandle; sockHandle.Attach( (*citer) ); sockHandle.Write(lpbData, strMsg.GetLength(), NULL); sockHandle.Detach(); } } else { SockAddrIn servAddr, sockAddr; m_SocketServer->GetSockName(servAddr); GetDestination(sockAddr); if ( servAddr != sockAddr ) { m_SocketServer.Write((const LPBYTE)(T2CA(strMsg)), strMsg.GetLength(), sockAddr); } else { AppendText( _T("Please change the port number to send message to a client.\r\n") ); } } } else { MessageBox(_T("Socket is not connected")); } }