Solved

Socket Function Leaking Memory

Posted on 2006-10-19
5
625 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

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
Here is a helpful source code for C++ Builder programmers that allows you to manage and manipulate HTML content from C++ code, while also handling HTML events like onclick, onmouseover, ... Some objects defined and used in this source include: …
The viewer will learn how to use NetBeans IDE 8.0 for Windows to connect to a MySQL database. Open Services Panel: Create a new connection using New Connection Wizard: Create a test database called eetutorial: Create a new test tabel called ee…
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

696 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