Solved

Socket Function Leaking Memory

Posted on 2006-10-19
5
629 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
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

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

688 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