[Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 644
  • Last Modified:

Socket Function Leaking Memory

I am using eMbedded Visual C++ for developing an application running on Windows CE 5.0.  I am new to Windows programming and inherited some socket code from a former colleague.  The following socket code leaks 4k every 5-6 times the TelnetSend() is used.  Does anyone see any obvious leaks...please help!

CODE:

TSocket::TSocket()
{
    WSADATA wsaData;
    m_socket        = INVALID_SOCKET;
    m_hRxThread     = NULL;                  
    m_rxHandler     = NULL;
    m_abortRxThread = FALSE;
    m_in_addr       = INADDR_NONE;
    m_socket        = INVALID_SOCKET;
    m_port          = 80;                              
    returnValue = WSAStartup(MAKEWORD(1,1), &wsaData);
    InitializeCriticalSection(&m_criticalSection);
}

TSocket::~TSocket()
{
  int   timeout = 1000;
  DWORD exitCode;

  if (m_hRxThread != NULL)
  {
    m_abortRxThread = TRUE;
    do
    {
      GetExitCodeThread(m_hRxThread, &exitCode);
      if (exitCode == SOCKET_THREAD_EXIT_CODE)
        break;
      Sleep(1);
    } while (--timeout);
    CloseHandle(m_hRxThread);
    m_hRxThread = NULL;
  }

  if(m_socket != INVALID_SOCKET)
    Close();

  DeleteCriticalSection(&m_criticalSection);
  WSACleanup();
}

StatType TSocket::Open()
{
  StatType        retstat = ERROR_SUCCESS;
  SOCKADDR_IN sock_addr;

  EnterCriticalSection(&m_criticalSection);

  if((m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != INVALID_SOCKET)
  {
    if ((m_in_addr = inet_addr(m_ip_address)) != INADDR_NONE)
    {
      memset ((char *)&sock_addr, 0, sizeof(sock_addr));
      sock_addr.sin_family = AF_INET;
      sock_addr.sin_port = htons(m_port);
      sock_addr.sin_addr.S_un.S_addr = m_in_addr;
   
      if((retstat = connect(m_socket, (SOCKADDR *)&sock_addr, sizeof(sock_addr))) == SOCKET_ERROR)
      {
        retstat = WSAGetLastError();
      }
      else
      {
        retstat = ERROR_SUCCESS;    
      }
    }        
    else
      retstat = WSAEFAULT;
  }
  else
    retstat = (ERROR_INVALID_HANDLE);

  LeaveCriticalSection(&m_criticalSection);

  return (retstat);
}

StatType TSocket::Close(void)
{
  EnterCriticalSection(&m_criticalSection);

  shutdown(m_socket, SD_BOTH);

  if(m_socket != INVALID_SOCKET)
      closesocket(m_socket);

  m_socket = INVALID_SOCKET;

  LeaveCriticalSection(&m_criticalSection);

  return (ERROR_SUCCESS);
}

StatType TSocket::SetAddress(const char *ip_address)
{
  if (strlen(ip_address) > MAX_ADDRESS_LEN)
    return (ERROR_INVALID_PARAMETER);

  strcpy(m_ip_address, ip_address);
   
  return (ERROR_SUCCESS);
}

DWORD TSocket::BytesAvailable(void)
{
  fd_set  fdReadSet;
  TIMEVAL timeout = {0, 0};

  FD_ZERO(&fdReadSet);
  FD_SET(m_socket, &fdReadSet);

  if(select(0, &fdReadSet, NULL, NULL, &timeout) == 1)
    return(SOCKET_MAX_BUFFER_LENGTH);

  return 0;
}

DWORD TSocket::ReadBytes(void *buffer, DWORD count)
{
  int   retval;
   
  if((retval = recv (m_socket, (char *)buffer, count, 0)) == SOCKET_ERROR)
    retval = 0;

  return ((DWORD)retval);
}

DWORD TSocket::WriteBytes(const void *buffer, DWORD count)
{    
  fd_set   writefds;
  timeval  timeout;

  if(count == 0)
    return(0);

  timeout.tv_sec = 1;
  timeout.tv_usec = 0;
  FD_ZERO (&writefds);
  FD_SET (m_socket, &writefds);

  if (select (0, NULL, &writefds, NULL, &timeout) == 1)
    return send(m_socket, (char *)buffer, count, 0);

  Close(); // so the socket owner can detect that it's not open as well as getting the err code.
  return(SOCKET_ERROR);
}

StatType  TSocket::SetReceiveHandler(rx_handler_type  rxHandler,
                                     LPVOID           userParameter,
                                     rx_priority_type priority)
{
  DWORD dwThreadId;

  m_rxHandler     = rxHandler;
  m_userParameter = userParameter;

  m_hRxThread = CreateThread(NULL,                
                             0,                  
                             RxThreadProcWrapper,
                             this,                
                             0,                  
                             &dwThreadId);        
  if (m_hRxThread == NULL)
    return(GetLastError());

  return (ERROR_SUCCESS);
}

DWORD WINAPI TSocket::RxThreadProcWrapper(LPVOID cPtr)
{
  return ((TSocket *)cPtr)->RxThreadProc(NULL);
}

DWORD WINAPI TSocket::RxThreadProc(LPVOID lpParameter)
{
  DWORD dwRead, i, numBytes;

  while (!m_abortRxThread)
  {
    EnterCriticalSection(&m_criticalSection);

    dwRead = 0;
    if (m_socket != INVALID_SOCKET)
    {
      if ((dwRead = TSocket::BytesAvailable()) > 0)
      {
        if ((numBytes = recv (m_socket, m_buf, dwRead, 0)) != SOCKET_ERROR)
        {
          for (i = 0; i < numBytes; i++)
            m_rxHandler(m_buf[i], m_userParameter);
        }
      }
    }
    LeaveCriticalSection(&m_criticalSection);

    if (dwRead == 0)
      Sleep(50);
  }            
  ExitThread(SOCKET_THREAD_EXIT_CODE);
  return (ERROR_SUCCESS);
}

void TSocket::TelnetSetup                  (int port, char *gateway)
{
  if(!IsOpen())
  {
    m_buf[0] = NULL;
    m_bufferPos = 0;

    SetAddress(gateway);
    SetPort(port);
    if(Open() != SOCKET_ERROR)
    {
      TelnetFlush();
    }
  }
}

void TSocket::TelnetSetup                  (int port)
{
  TelnetSetup(port, aMC.GetGateway());
}

void TSocket::TelnetSend                  (char *data, int length, int sleep)
{
  if(IsOpen())
  {
    WriteBytes(data, length);

    Sleep(sleep);
            
    TelnetFlush();
  }
}

void TSocket::TelnetFlush                  (void)
{
  m_bufferPos = 0;
  m_buf[0] = NULL;
  if(IsOpen())
  {
    while(BytesAvailable())
    {
      int readCount = ReadBytes(m_buf+m_bufferPos, SOCKET_MAX_BUFFER_LENGTH - m_bufferPos - 1);
      if(!readCount)
      {
        TelnetShutdown();
      }
      else
      {
      m_bufferPos += readCount;
      m_buf[m_bufferPos] = NULL;
      if(m_bufferPos >= SOCKET_MAX_BUFFER_LENGTH - 1)
      {
        m_bufferPos = 0;
        m_buf[0] = NULL;
      }
      }
    }
  }
}

void TSocket::TelnetShutdown            (void)
{
  if(IsOpen())
  {
    Close();
  }
}

char *TSocket::TelnetGetBuffer            (void)
{
  return m_buf;
}

0
littlezs
Asked:
littlezs
3 Solutions
 
grg99Commented:

You want to do the wsastartup() call only ONCE.  Not once per socket object creation.



Also make sure that in every path thru the code  the socket gets closed and the critical section gets returned.


Also doing a shutdown() should be reserved for the rare error situation, do a normal close to ensure the data all makes it to the destination.  A shutdown slams the connection shut, which is bad if any packets are still in transit or get lost and need to be resent.





0
 
Deepu AbrahamR & D Engineering ManagerCommented:
Hi!
I am suspecting the *m_criticalSection*. Could you replace it with Mutex and try? Also keep and eye on the handle count?
Find out if it is the handle is leaking or the memory.*CloseHandle(m_hRxThread)*

Last resort :If possible get hold of Entrek tool for finding memory leak in wince (recommended by Microsoft too!).
Best Regards,
DeepuAbrahamK
0
 
rstaveleyCommented:
Check the code that calls TelnetSend too. See how many bytes get sent on average every 4/5 calls.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now