Solved

Socket Function Leaking Memory

Posted on 2006-10-19
5
622 Views
Last Modified: 2013-12-14
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
Comment
Question by:littlezs
5 Comments
 
LVL 22

Accepted Solution

by:
grg99 earned 168 total points
ID: 17767073

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
 
LVL 11

Assisted Solution

by:DeepuAbrahamK
DeepuAbrahamK earned 166 total points
ID: 17767545
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
 
LVL 17

Assisted Solution

by:rstaveley
rstaveley earned 166 total points
ID: 17807498
Check the code that calls TelnetSend too. See how many bytes get sent on average every 4/5 calls.
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Update (December 2011): Since this article was published, the things have changed for good for Android native developers. The Sequoyah Project (http://www.eclipse.org/sequoyah/) automates most of the tasks discussed in this article. You can even fin…
Container Orchestration platforms empower organizations to scale their apps at an exceptional rate. This is the reason numerous innovation-driven companies are moving apps to an appropriated datacenter wide platform that empowers them to scale at a …
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.

785 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