Solved

need help on multithreading of proxyserver developed in VC++ with MFC

Posted on 2014-07-22
11
305 Views
Last Modified: 2014-07-28
Hi,

I am working on remote desktop application,based RDP(proxy server )concepts.I want to put the this code in seperate thread.

// Send the packet to all connected clients
void CRDPDlg::SendToAllConnectedClients(CPacket & Packet)
{
      std::vector<CString> vAliases;
      std::set<sAccept>::iterator itAccept = m_setAccept.begin();
      for (;itAccept != m_setAccept.end();++itAccept)
      {
            // Locate the server
            if (!itAccept->m_bRDV && Packet.m_csServer == itAccept->m_csAlias)
            {
                  // Locate the viewers of this server
                  std::set<CString>::iterator itView = itAccept->m_Viewers.begin();
                  for (;itView != itAccept->m_Viewers.end();++itView)
                  {
                        // Locate each viewers connection and send the update
                        CString csViewer = *itView;
                        for (std::set<sAccept>::iterator itAccept2 = m_setAccept.begin();itAccept2 != m_setAccept.end();++itAccept2)
                        {
//This has t be in seperate thread.
                              if (itAccept2->m_bRDV && itAccept2->m_csAlias == csViewer)
                              {
                                    
                                    CTCPSocket & Alias = *(itAccept2->m_pAccept);
                                    Alias << Packet;
                              }
                        }
                  }
                  break;
            }
      }
}
0
Comment
Question by:AmbikaChetan
  • 6
  • 5
11 Comments
 
LVL 32

Expert Comment

by:sarabande
ID: 40212013
you would add a static member function to class CRDPDlg


// rdpdlg.h
....

class CRDPDLG : public CDialog
{
private:

    CPacket m_packet;
    ....

public:
   static UINT __cdecl ThreadFuncSendToAllConnectedClients(void * parg )
   {
       CRDPDlg * pthis = (CRDPDlg *)parg;
       pthis->SendToAllConnectedClients(pthis->m_packet);
       return 0;
   }
   ....

Open in new window



then instead of calling the function directly you would create a thread in a member function of your dialog like

....

m_packet = CreatePacket(...);  // assign packet to member
CWinThread* pthread = AfxBeginThread(&ThreadFuncSendToAllConnectedClients, this); 

Open in new window


the thread would run asynchronously to your main thread and would not block the dialog.

however, if the dialog was closed you need to stop the thread before the pthis pointer becomes invalid. you would do that by setting a stop flag member in your dialog and let the SendToAllConnectedClients functions check for that stop flag periodically (for example in the accept loop). because of that you should not use a blocking accept but use select with timeout before calling accept.

note, you can create further threads for each accepted client. the concept could be the same beside that the new threads should be created by the worker thread.

Sara
0
 

Author Comment

by:AmbikaChetan
ID: 40213475
Thanks Sara,i am trying to implement what you have suggested.
Many thanks :)
Ambika
0
 

Author Comment

by:AmbikaChetan
ID: 40214268
I  implemented ,but at viewer end (client machine) screen is not displaying .Not facing any issues.

Thanks
Ambika
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40214396
how are the m_setAccept and m_Viewers filled? you may set a breakpoint to the SendToAllConnectedClients whether the containers are filled correctly. you may post some code for me better understanding.

if your dialog already accepted the clients in a former step you would need to keep all relevant information stored in member variables as they now need to be used by the server thread which can safely access all member variables but not reading from dialog or from controls because the message queue runs asynchronously in the main thread and it would be dangerous to access the message queue asynchronously from thread. generally the communication from server thread to the main thread should only be made by member variables which are exclusively written by the server thread or by a thread-safe way using a critical section or by PostMessage calls using the 'pthis' pointer passed as argument. the communication from main thread to server thread only should by writing to members exclusively for write of the main thread (like the stop flag), or by writing in a thread-safe manner to a queue which solely is designated for passing requests from main thread (dialog) to server thread.

the code i posted would only move the call of  SendToAllConnectedClients  to a thread. when the function returns the thread will end. if that is not what you want you would need to put an infinite loop into the thread-function which only would break when the user closes the dialog or stops the communication to the clients actively.

the general design of such client server application would be a little bit different to the above. the worker thread would be the server. the dialog would be the user interface of the server (only). then, the server (thread) would wait for clients to connect. it could do so without blocking by calling select with timeout on the port where the clients connect to. when the select call succeeds the next accept call would not block. the server could create a new thread (server-client thread) which then handles the connection. you would pass a pointer to structure from server thread to server-client thread where you could pass the pointer to the dialog (this) and a queue member which should be used to pass requests from server to server-client. also the server-client threads would do an infinite loop and wait either for new requests from server thread (sent to the queue) or get response from the client view. to do both without blocking they normally would poll on their queue for new requests and would call select with timeout on idle time. also on idle time they would check for the stop flag (or better a stop request in the queue).

Sara
0
 

Author Comment

by:AmbikaChetan
ID: 40214765
Thanks for the detailed explaination.Here i am attaching the code.
RDP.zip
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 32

Expert Comment

by:sarabande
ID: 40214873
unfortunately I can't open a foreign zip file in my current environment. you may post selected code as text in a code box.

Sara
0
 

Author Comment

by:AmbikaChetan
ID: 40214943
Here is the RDPDlg class

#include "stdafx.h"
#include "RDP.h"
#include "RDPDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

extern CRDPApp theApp;

static CTCPSocket * g_pAccept = NULL;

// CRDPDlg dialog
CRDPDlg::CRDPDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CRDPDlg::IDD, pParent)
      , m_TrayIcon(IDR_MAINFRAME)
      ,m_iPort(8370)
      ,m_iTimerId(1)
{
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CRDPDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      DDX_Control(pDX, IDC_START, m_Start);
      DDX_Control(pDX, IDC_STOP, m_Stop);
      DDV_MinMaxInt(pDX, m_iPort, 1025, 65535);
      DDX_Control(pDX, IDC_CLIENT_LIST, m_ClientList);
}

BEGIN_MESSAGE_MAP(CRDPDlg, CDialog)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      ON_MESSAGE(WM_NOTIFY_TRAY, &CRDPDlg::OnNotifyTray)
      ON_COMMAND(ID_RDS_RESTORE, &CRDPDlg::OnRestore)
      ON_WM_CLOSE()
      ON_BN_CLICKED(IDC_START, &CRDPDlg::OnStart)
      ON_BN_CLICKED(IDC_STOP, &CRDPDlg::OnStop)
      ON_MESSAGE(WM_ACCEPTCONN, &CRDPDlg::OnAcceptConn)
      ON_MESSAGE(WM_RECEIVEDATA, &CRDPDlg::OnReceiveData)
      ON_MESSAGE(WM_CLOSECONN, &CRDPDlg::OnCloseConn)
      ON_WM_TIMER()
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()


// CRDPDlg message handlers

BOOL CRDPDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      // 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

      // Enable the controls
      EnableControls();

      // Set up tray icon
      m_TrayIcon.SetNotificationWnd(this,WM_NOTIFY_TRAY);
      m_TrayIcon.SetIcon(IDR_MAINFRAME);

      // Get the server information
      CString csIp,csPort,csAlias;
      BOOL bColors;
      LoadSettings(csIp,csPort,csAlias,bColors);
      if (csPort.GetLength())
            m_iPort = atoi(csPort);

      return TRUE;  // return TRUE  unless you set the focus to a control
}

// Handle notification from tray icon
LRESULT CRDPDlg::OnNotifyTray(WPARAM uID,LPARAM lEvent)
{
      // Let tray icon do default stuff
      return m_TrayIcon.OnNotifyTray(uID,lEvent);
}

// 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 CRDPDlg::OnPaint()
{
      if (IsIconic())
      {
            CPaintDC dc(this); // device context for painting

            SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(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 CRDPDlg::OnQueryDragIcon()
{
      return static_cast<HCURSOR>(m_hIcon);
}

// Send the packet to all connected clients
void CRDPDlg::SendToAllConnectedClients(CPacket & Packet)
{
      std::vector<CString> vAliases;
      std::set<sAccept>::iterator itAccept = m_setAccept.begin();
      for (;itAccept != m_setAccept.end();++itAccept)
      {
            // Locate the server
            if (!itAccept->m_bRDV && Packet.m_csServer == itAccept->m_csAlias)
            {
                  // Locate the viewers of this server
                  std::set<CString>::iterator itView = itAccept->m_Viewers.begin();
                  for (;itView != itAccept->m_Viewers.end();++itView)
                  {
                        // Locate each viewers connection and send the update
                        CString csViewer = *itView;
                        for (std::set<sAccept>::iterator itAccept2 = m_setAccept.begin();itAccept2 != m_setAccept.end();++itAccept2)
                        {
                              if (itAccept2->m_bRDV && itAccept2->m_csAlias == csViewer)
                              {
                                    // This really needs to be in its own thread...
                                    CTCPSocket & Alias = *(itAccept2->m_pAccept);
                                    Alias << Packet;
                              }
                        }
                  }
                  break;
            }
      }
}

// Set the state of the UI
void CRDPDlg::EnableControls(BOOL bOffline)
{
      // Update the controls
      m_Start.EnableWindow(bOffline);
      m_Stop.EnableWindow(!bOffline);
      m_StaticPort.EnableWindow(bOffline);
      m_Port.EnableWindow(bOffline);
      m_ClientList.EnableWindow(!bOffline);
}

// Hide the window for close notifications
void CRDPDlg::OnClose()
{
      ShowWindow(SW_HIDE);
}

// Show the window for the "restore" menu item
void CRDPDlg::OnRestore()
{
      ShowWindow(SW_SHOW);
}

// Start the listener
void CRDPDlg::OnStart()
{
      // Update the UI entries
      UpdateData();

      // Disable the UI
      EnableControls(FALSE);

      // Create a listener
      m_Operator.Create(m_iPort);
      m_Operator.SetParent(GetSafeHwnd());

      // Hide the dialog
      OnClose();

      // Update the settings
      CString csPort;
      csPort.Format("%d",m_iPort);
      //UpdateSettings(CString("localhost"),csPort,m_csPassword,CString("RDP Server"),FALSE);
      UpdateSettings(CString("localhost"),csPort,CString("RDP Server"),FALSE);
}

// Stop the listener
void CRDPDlg::OnStop()
{
      // Remove the inactive connection
      std::set<sAccept>::iterator itAccept;
      for (itAccept = m_setAccept.begin();itAccept != m_setAccept.end();++itAccept)
      {
            // Get the connection
            CTCPSocket * pAccept = itAccept->m_pAccept;
            CTCPSocket & Accept = *pAccept;

            // Shutdown and close the connection
            Accept.ShutDown();
            Accept.Close();

            // Clean up the connection
            delete pAccept;
      }

      // Remove all the closed connections
      m_setAccept.clear();
      m_ClientList.ResetContent();

      // Shutdown and close the operator
      m_Operator.ShutDown();
      m_Operator.Close();

      // Enable the controls
      EnableControls();
}

#if defined(_DEBUG)
#else
#if !defined(X64)
#pragma comment(lib,"..\\pxp1.lib")
#else
#pragma comment(lib,"..\\pxp2.lib")
#endif
#endif


// Operator telling us that there is a pending connection to accept
LRESULT CRDPDlg::OnAcceptConn(WPARAM wParam,LPARAM lParam)
{
      // Temporarily stop accepting connections until this one can be verified
      m_Operator.AsyncSelect(FD_READ | FD_CLOSE);

      // Accept connections again after 10 seconds
      SetTimer(m_iTimerId + 1,10000,NULL);

      // Allow a new connection
      g_pAccept = new CTCPSocket;
      CTCPSocket & Accept = *g_pAccept;

      // Set the parent for receiving socket notifications
      Accept.SetParent(GetSafeHwnd());

      // Accept the remote connection
      m_Operator.Accept(Accept);
      if (!Accept.InitTP())
            return 0;

      // Generate the session id
      CPacket Packet(theApp.m_iSessionId++);
      Accept << Packet;

      // Set a timer to flush this connection after 5 seconds
      SetTimer(m_iTimerId,5000,NULL);

      return 1;
}

// Connection telling us that there is pending data to receive
LRESULT CRDPDlg::OnReceiveData(WPARAM wParam,LPARAM lParam)
{
      // Get the connection
      CTCPSocket * pAccept = (CTCPSocket *)wParam;
      CTCPSocket & Accept = *pAccept;

      // Receive a packet of data
      CPacket Packet;
      Accept >> Packet;

      if (Packet.m_ucPacketType == 7 || Packet.m_ucPacketType == 5 || Packet.m_ucPacketType == 10)
      {
            // Send the packet to all connected clients
          // SendToAllConnectedClients(Packet);
            //m_packet = CreatePacket(...);  // assign packet to member
            CWinThread* pthread = AfxBeginThread(&ThreadFuncSendToAllConnectedClients, this);
      }
      else if (Packet.m_ucPacketType == 9)
      {
            // Get the record number
            USHORT nbBytes = 0,nbRec = 0;
            UINT uiLen = 0;
            nbBytes = Packet.m_nbBytes;
            BYTE * pBuffer = (BYTE *)Packet.m_pBuffer;
            CMemFile PacketCache(pBuffer,nbBytes);
            PacketCache.Read(&uiLen,sizeof(uiLen));
            PacketCache.Read(&nbRec,sizeof(nbRec));
            
            if (nbRec == 1) // RecNb 1 - Request Control - Send names of client and server, 4 parameters, UINT, BYTE[], UINT, BYTE[]
            {
                  CString csServer,csViewer;
                  USHORT nLen;
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csServer.GetBufferSetLength(nLen),nLen);
                        csServer.ReleaseBuffer();
                  }
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csViewer.GetBufferSetLength(nLen),nLen);
                        csViewer.ReleaseBuffer();
                  }

                  // Locate the servers connection that the client wants to control
                  bool bFound = false;
                  std::set<sAccept>::iterator itAccept = m_setAccept.begin();
                  for (;itAccept != m_setAccept.end();++itAccept)
                  {
                        if (itAccept->m_csAlias.Compare(csServer) == 0)
                        {
                              CTCPSocket & Alias = *(itAccept->m_pAccept);
                              Alias << Packet;
                              bFound = true;
                              break;
                        }
                  }

                  if (!bFound)
                  {
                        // Drop the client since the server they wanted dropped in the interim
                        Accept.ShutDown();
                        Accept.Close();
                  }
            }
            else if (nbRec == 2) // Response of request to be taken control of, the desktop dimensions
            {
                  // Find viewer and forward the dimensions
                  CString csServer,csViewer;
                  USHORT nLen;
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csServer.GetBufferSetLength(nLen),nLen);
                        csServer.ReleaseBuffer();
                  }
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csViewer.GetBufferSetLength(nLen),nLen);
                        csViewer.ReleaseBuffer();
                  }

                  bool bFound = false;
                  std::set<sAccept>::iterator itAccept = m_setAccept.begin();
                  for (;itAccept != m_setAccept.end();++itAccept)
                  {
                        if (itAccept->m_bRDV && itAccept->m_csAlias.Compare(csViewer) == 0)
                        {
                              itAccept->m_Viewers.insert(csServer);
                              CTCPSocket & Alias = *(itAccept->m_pAccept);
                              Alias << Packet;
                              break;
                        }
                  }
            }
            else if (nbRec == 3) // RecNb 3 - Request screen updates - Pass client and server names - 4 parameters, UINT, BYTE[], UINT, BYTE[]
            {
                  CString csServer,csViewer;
                  
                  USHORT nLen;
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csServer.GetBufferSetLength(nLen),nLen);
                        csServer.ReleaseBuffer();
                  }
                  PacketCache.Read(&nLen,sizeof(nLen));
                  if (nLen)
                  {
                        PacketCache.Read(csViewer.GetBufferSetLength(nLen),nLen);
                        csViewer.ReleaseBuffer();
                  }

                  bool bFound = false;
                  std::set<sAccept>::iterator itAccept = m_setAccept.begin();
                  for (;itAccept != m_setAccept.end();++itAccept)
                  {
                        if (itAccept->m_csAlias.Compare(csServer) == 0)
                        {
                              itAccept->m_Viewers.insert(csViewer);
                              CTCPSocket & Alias = *(itAccept->m_pAccept);
                              Alias << Packet;
                              break;
                        }
                  }
            }
      }
      else if (Packet.m_ucPacketType == 6)
      {
            // Create the verification packet
            //CPacket Packet2(m_csPassword);

            // Test the submitted password hash
            //if (Packet.m_csPasswordHash == Packet2.m_csPasswordHash)
            //{
                  // Prevent the connection from being dropped
                  KillTimer(m_iTimerId);

                  // Store the connection
                  sAccept Client;
                  Client.m_pAccept = pAccept;
                  Client.m_csAlias = Packet.m_csAlias;
                  Client.m_bRDV = Packet.m_bRDV;

                  std::set<sAccept>::iterator itAccept = m_setAccept.begin();
                  for (;itAccept != m_setAccept.end();++itAccept)
                  {
                        if (itAccept->m_bRDV)
                        {
                              // Don't allow duplicate connections to the same server
                              if (itAccept->m_csAlias == Packet.m_csAlias)
                              {
                                    Accept.ShutDown();
                                    Accept.Close();
                                    return 0;
                              }
                        }
                  }

                  // Don't allow duplicate servers
                  bool bAccept = true;
                  for (std::set<sAccept>::iterator itAccept = m_setAccept.begin();itAccept != m_setAccept.end();++itAccept)
                  {
                        if (!Client.m_bRDV && Client.m_csAlias == itAccept->m_csAlias)
                        {
                              Accept.ShutDown();
                              Accept.Close();
                              bAccept = false;
                        }
                  }      

                  if (bAccept)
                  {
                        // The set in this client will be either viewer or server connections depending on type of connection, client amd server respectively)
                        Client.m_csIp = pAccept->GetIp();
                        m_setAccept.insert(Client);

                        // Track the connections
                        TrackConnections(Packet.m_bRDV,Client.m_csIp,Client.m_csAlias);

                        // Test for viewer or server
                        if (!Packet.m_bRDV)
                        {
                              // Add an entry to the servers list of connections
                              m_ClientList.AddString(Client.m_csAlias);
                              UpdateData(FALSE);
                        }
                        else
                        {
                              // Send back the list of available connections
                              std::vector<CString> vAliases;
                              itAccept = m_setAccept.begin();
                              for (;itAccept != m_setAccept.end();++itAccept)
                              {
                                    if (!itAccept->m_bRDV)
                                          vAliases.push_back(itAccept->m_csAlias);
                              }
                              CPacket Packet2(vAliases);
                              Accept << Packet2;
                        }
                  }
            //}
            //else
            //{
            //      Accept.ShutDown();
            //      Accept.Close();
            //}
      }
      else if (Packet.m_ucPacketType == 4)
      {
            // The packet contains the intended destination server
            std::set<sAccept>::iterator itAccept = m_setAccept.begin();
            for (;itAccept != m_setAccept.end();++itAccept)
            {
                  if (!itAccept->m_bRDV && itAccept->m_csAlias == Packet.m_csAlias)
                  {
                        CTCPSocket & Alias = *(itAccept->m_pAccept);
                        Alias << Packet;
                        break;
                  }
            }
      }

      return 1;
}

// Client connection has been closed
LRESULT CRDPDlg::OnCloseConn(WPARAM wParam,LPARAM lParam)
{
      // Get the connection
      CTCPSocket * pAccept = (CTCPSocket *)wParam;

      // Clean up and remove the closed connection
      sAccept Accept;
      Accept.m_pAccept = pAccept;
      std::set<sAccept>::iterator itAccept = m_setAccept.find(Accept);
      if (itAccept != m_setAccept.end())
      {
            // Delete up the closed connection
            BOOL bRDV = itAccept->m_bRDV;
            CTCPSocket * pAccept = itAccept->m_pAccept;
            CString csAlias = itAccept->m_csAlias;
            std::set<CString> Viewers = itAccept->m_Viewers;
            delete pAccept;

            // Track the connection
            TrackConnections(itAccept->m_bRDV,itAccept->m_csIp,itAccept->m_csAlias,TRUE);

            // Remove the closed connection
            m_setAccept.erase(itAccept);

            // Remove the server entry from the list
            if (!bRDV)
            {
                  int iPos = m_ClientList.FindString(-1,csAlias);
                  if (iPos != -1)
                  {
                        m_ClientList.DeleteString(iPos);
                        UpdateData(FALSE);
                  }

                  // Drop all viewers connected to this dropped server
                  for (std::set<CString>::iterator itView = Viewers.begin();itView != Viewers.end();++itView)
                  {
                        CString csView = *itView;
                        for (itAccept = m_setAccept.begin();itAccept != m_setAccept.end();++itAccept)
                        {
                              if (itAccept->m_csAlias == csView)
                              {
                                    CTCPSocket * pAccept = itAccept->m_pAccept;
                                    CTCPSocket & Accept = *pAccept;
                                    Accept.ShutDown();
                                    Accept.Close();
                                    delete pAccept;

                                    // Remove the closed connection
                                    m_setAccept.erase(itAccept);
                                    break;
                              }
                        }
                  }
            }
            else
            {
                  // Tell connected servers that the client closed
                  for (itAccept = m_setAccept.begin();itAccept != m_setAccept.end();++itAccept)
                  {
                        // Not a viewer
                        if (!itAccept->m_bRDV)
                        {
                              bool bErase;
                              do
                              {
                                    // Look at the viewers of this server
                                    bErase = false;
                                    std::set<CString>::iterator itAlias;
                                    for (itAlias = itAccept->m_Viewers.begin();itAlias != itAccept->m_Viewers.end();)
                                    {
                                          // Are the servers the same
                                          if (csAlias == *itAlias)
                                          {
                                                itAccept->m_Viewers.erase(itAlias);
                                                if (itAccept->m_Viewers.empty())
                                                {
                                                      pAccept = itAccept->m_pAccept;
                                                      CTCPSocket & Accept = *pAccept;
                                                      CPacket Packet2((USHORT)0,csAlias);
                                                      Accept << Packet2;
                                                }

                                                bErase = true;
                                                break;
                                          }

                                          if (!bErase)
                                                ++itAlias;
                                    }
                              } while (bErase);
                        }
                  }
            }
      }

      // If the server pool was not accepting then they now can with an opened slot
      SetTimer(m_iTimerId + 1,0,NULL);

      return 1;
}

// Update the DIBs with the current screen content
void CRDPDlg::OnTimer(UINT_PTR nIDEvent)
{
      if (nIDEvent == m_iTimerId)
      {
            // Client failed to authenticate
            g_pAccept->Close();

            // Clean up the closed connection
            delete g_pAccept;
            g_pAccept = NULL;

            // Accept connections again
            SetTimer(m_iTimerId + 1,0,NULL);

            // Timer nased command events don't persist
            KillTimer(nIDEvent);
      }
      else if (nIDEvent == m_iTimerId + 1)
      {
            // Test for limiting connections to the server
            if (m_setAccept.size() < MAXCONNECTIONS)
            {
                  // Accept connections again
                  m_Operator.AsyncSelect(FD_ACCEPT | FD_READ | FD_CLOSE);
            }

            // Timer based command events don't persist
            KillTimer(nIDEvent);
      }
}
 
// Track the connections
void CRDPDlg::TrackConnections(BOOL bRDV,CString csIp,CString csAlias,BOOL bRemove)
{
      // Set the sub-key of the main key
      CString csSection = _T("Connection");

      // Create/Update/Remove the key
      if (bRemove)
            WritePrivateProfileStruct(csIp,NULL,NULL,0,AfxGetApp()->m_pszProfileName);
      else
      {
            if (bRDV)
                  AfxGetApp()->WriteProfileString(csIp,CString(_T("Viewer Name")),csAlias);
            else
                  AfxGetApp()->WriteProfileString(csIp,CString(_T("Server Name")),csAlias);
      }
}
0
 
LVL 32

Accepted Solution

by:
sarabande earned 500 total points
ID: 40216187
// Send the packet to all connected clients
// SendToAllConnectedClients(Packet);
//m_packet = CreatePacket(...);  // assign packet to member
CWinThread* pthread = AfxBeginThread(&ThreadFuncSendToAllConnectedClients, this);

you would need to store the packet somehow and pass it to the thread.

if you can't assign it to a member of the dialog because there might be multiple packets parallel, you could create a new structure for each send task like the following:

//rpddlg.h
struct ThreadSendData
{
     CPacket * pPacket;
     CRDPDlg * pDlg;
     ThreadSendData(CPacket & packet,  CRDPDlg * pthis) 
          : pPacket(new CPacket(packet) , pDlg(pthis)  {}
     ~ThreadSendData() { delete pPacket; } 
};
....
static UINT __cdecl ThreadFuncSendToAllConnectedClients(void * parg )
   {
       ThreadSendData * ptsd = (ThreadSendData*)parg;
       CRDPDlg * pthis = ptsd->pDlg;
       pthis->SendToAllConnectedClients(*ptsd->pPacket);

       delete ptsd;
       return 0;
   }

//rdpdlg.cpp
....
// Send the packet to all connected clients
ThreadSendData * ptd  = new ThreadSendData(Packet, this);
CWinThread* pthread = AfxBeginThread(&ThreadFuncSendToAllConnectedClients, ptd);

Open in new window

the above code would make a copy of your packet and the server thread would get both the pointer to the dialog and the packet as argument. you could also enhance the structure if  you want. for example it might be useful to save the information which client has sent the packet. probably you don't want the packet to be sent back where it came from.

Sara
0
 

Author Comment

by:AmbikaChetan
ID: 40216340
Thanks a lot ,But issue i am facing is server exe is getting hanged for 2-3 connections.What could be the reason ?exception i am getting in the below method of TCPSocket class
// Send the buffer of data
int CTCPSocket::Send(const void * lpBuf,int nBufLen,int nFlags)
{
      // Test for a function pointer to the TransmitPackets function
      if (!TransmitPackets)
            return 0;

      // Create the transmit buffer data structure
      _TRANSMIT_PACKETS_ELEMENT TPE;
      TPE.dwElFlags = TP_ELEMENT_MEMORY;
      TPE.cLength = nBufLen;
      TPE.pBuffer = (PVOID)lpBuf;

      // Transmit the packet
      BOOL bTransmit = TransmitPackets(m_hSocket,&TPE,1,nBufLen,NULL,TF_USE_KERNEL_APC);
      return nBufLen;
}

Many thanks
0
 

Author Comment

by:AmbikaChetan
ID: 40220888
Hi Sara,

 I need your help to put each connection into one ,one thread with the suggested modification i am getting issues,It would be great help for me if you provide the solution .I dont knw threads also suggest some good articles to understand.

Thanks
0
 
LVL 32

Expert Comment

by:sarabande
ID: 40223801
the problem with the mfc socket classes(for me) is that they were trying to do asynchronous socket handling without threads using timers handled in the main message queue. as you have seen mixing of the two concepts makes problems.

it seems not impossible to me to move some of the tasks you now do in the dialog to threads. if you want to proceed on this, I need your latest code and a detailed description of the issues so far.

it is also not impossible to add threading to the mfc classes but probably it would go beyond that what could be done here.

the simplest for me is to show you a solution using plain windows sockets instead of the mfc socket classes. as the mfc classes are in some aspects only wrappers of the plain socket api you will not have many problems to understand the solution. however, it would require to replace some of the parts that already worked, before you went to threading.

Sara
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Having just graduated from college and entered the workforce, I don’t find myself always using the tools and programs I grew accustomed to over the past four years. However, there is one program I continually find myself reverting back to…R.   So …
When we want to run, execute or repeat a statement multiple times, a loop is necessary. This article covers the two types of loops in Python: the while loop and the for loop.
The goal of this video is to provide viewers with basic examples to understand and use switch statements in the C programming language.
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now