Solved

Socket Function Leaking Memory

Posted on 2006-10-19
5
617 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
Comment Utility

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
Comment Utility
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
Comment Utility
Check the code that calls TelnetSend too. See how many bytes get sent on average every 4/5 calls.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

  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 …
Programmer's Notepad is, one of the best free text editing tools available, simply because the developers appear to have second-guessed every weird problem or issue a programmer is likely to run into. One of these problems is selecting and deleti…
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
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…

763 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

7 Experts available now in Live!

Get 1:1 Help Now