Solved

Borland TStreamSockets

Posted on 1997-04-08
2
507 Views
Last Modified: 2012-06-22
I am unclear on how the TStreamSocket class handles socket notification.  If the socket is to be non blocking how do I set up the code to receive and read data from it?

What I'm realy looking for is sample code, something less complex than the single example provided by Borland.
0
Comment
Question by:Archadious
2 Comments
 
LVL 3

Accepted Solution

by:
gaohong earned 200 total points
ID: 1162639
Hi, following is my stream socket used in my telnet session.
You could use it strip down things from global.h and mxapp.h
(e.g. define of uint, DLLCLASS, Message(), Telnet class ...)


good luck
gaohong xie


.h file

 /**************************************************************************
 *        Programmer     G. Xie
 *        Version 1.0    date 22-03-1995 (Borland C++ V4.5)
 *
 *        copyright (c) 1995  Dept. of Psychiatry, MCV, VCU
 ***************************************************************************
 *            head file declares class TAsyncSocket
 ***************************************************************************
 */
#ifndef TASYNCSOCKET.H
#define TASYNCSOCKET.H

#include <fstream.h>
#include <owl\window.h>
#include "winsock.h"
#include "global.h"    //define uint, DLLCLASS etc...

//message id's
enum
{
  SM_HOSTNAME = WM_USER + 2100,
  SM_DATAREADY,
};

class Telnet;

class DLLCLASS TAsyncSocket : public TWindow
{
public:
      int SelectRequest;
      TAsyncSocket(TWindow* pParent);

      ~TAsyncSocket();

      int Connect(const char* pHost, const char *pUser,
                        const char *pPassword);
      bool ReConnect(const char* pHost, const char *pUser,
                        const char *pPassword);
      int SyncRead(unsigned char *pData, int nMaxLen);
      int SyncSend(const unsigned char *pData, int nLen);
      int LastError();
      int Startup();

      void SetTelClient(Telnet *cl) { TelClient = cl; }
      void WantAll();
      void WantRead();
      void WantWrite();
    void WantNone();

      char Server[64];            // used to store server name
      char User[16];              // "" user name
      char Password[16];          // "" password

      SOCKET sock;                     // socket identifier
      bool   bBlocking;                // true if socket is blocking
      bool   bConnected;               // true if socket are connected
      bool   bValid;                     // true if winsock.dll is valid

protected:
      int  Connect(char* pHost, int nPort = 0, int nProtocol = PF_INET);
      int  GenSocket(char* pHost, int nPort = 0, int nProtocol = PF_INET);
      int  AsyncGetHostByName(const char* ServerName);

      void EvTimer(uint uTimerId);
      void CleanupWindow();
      void SetupWindow();

      LRESULT SmHostName(WPARAM,LPARAM);
      LRESULT SmDataReady(WPARAM,LPARAM);

      Telnet              *TelClient;      // high level object owns the socket
      hostent       *pHostent;    // ptr to host entry
      protoent      *pProtoent;   // ptr to proto entry

      HANDLE               hAsync;            // handle used for async Winsocket calls
      HINSTANCE     hSockInstance;// HINSTANCE for socket
      WSADATA       wsaData;      // Winsocket data

      struct hostent  Host;            // instance of hostent
      struct protoent Proto;          // instance of protoent
      struct sockaddr_in inetAddr;// instance of sockeaddr_in strucutre

      char     *tmpBuffer;
      ofstream *ostra;
      ofstream *ostrb;

      DECLARE_RESPONSE_TABLE(TAsyncSocket);
      };

#endif

.cpp file

 /**************************************************************************
 *        Programmer     G. Xie
 *        Version 1.0    date 22-03-1995 (Borland C++ V4.5)
 *                      
 *        copyright (c) 1995  Dept. of Psychiatry, MCV, VCU
 ***************************************************************************
 *            head file declares class TAsyncSocket
 ***************************************************************************
 */
#include <string.h>
#include <owl\window.h>

#pragma hdrstop

#include "socket.h"
#include "telnet.h"
#include "mxapp.h"

const unsigned int VERSION_NEED = 0x101;  // winsock version we need
const int TIMEOUT_MS = 1000;              // 1000 millisecs --1 sec--
const int BLOCK_TIMEOUT = 10;             // in seconds
const int TIMER_ID = 1;                   // internal timer id
const int TMPBUFFSZ = 128;                // tmp working buffer size

//TAsyncSocket event handlers
DEFINE_RESPONSE_TABLE1(TAsyncSocket,TWindow)
      EV_WM_TIMER,
      EV_MESSAGE(SM_HOSTNAME,  SmHostName),
      EV_MESSAGE(SM_DATAREADY, SmDataReady),
END_RESPONSE_TABLE;

TAsyncSocket::TAsyncSocket(TWindow* pParent) : TWindow(pParent)
{
Attr.Style   &= ~WS_VISIBLE;                  // force window to be hidden
bValid        = false;                              // invalid until SetupWindow is hit
bConnected    = false;                              // invalid until connection is made
hSockInstance = 0;                                    // winsock library instance handle
SelectRequest = 0;

tmpBuffer = 0;
TelClient = 0;

//debug log file stream pointers
ostra = new ofstream("sockdebg.inp");
ostrb = new ofstream("sockdebg.out");
}

TAsyncSocket::~TAsyncSocket()
{
  if(tmpBuffer) delete [] tmpBuffer;
  delete ostra;
  delete ostrb;

      if(hSockInstance)
         ::FreeLibrary(hSockInstance);

      if(!bValid) return;

      //TelClient->Cleanup();

      if(WSAIsBlocking())                    //if we are blocking
            WSACancelBlockingCall();        //cancel the blocking call

      if(bConnected)                         //if we are connected
            closesocket(sock);              //close the socket

      WSACleanup();                         //clean up the Winsockets
      KillTimer(TIMER_ID);                   //and kill our timer
}

bool TAsyncSocket::ReConnect(const char* pHost, const char *pUser,
                                            const char *pPass)
      {
      if(!bValid) return false;

      if(!bConnected)                   //if it is not a reconnect
        {
            Connect(pHost, pUser, pPass);
         return bConnected;
        }

      int len = strlen(pHost);
      if(len < 64)
         strcpy(Server, pHost);
      else
        {
         strncpy(Server,   pHost, 63);
         Server[63] = '\0';
        }

      len = strlen(pUser);
      if(len < 16)
         strcpy(User, pUser);
      else
        {
         strncpy(User,     pUser, 15);
         User[15] = '\0';
        }

      len = strlen(pPass);
      if(len < 16)
         strcpy(Password, pPass);
      else
        {
         strncpy(Password, pPass, 15);
         Password[15] = '\0';
        }

      if(WSAIsBlocking())                          //if we are blocking
            WSACancelBlockingCall();              //cancel the blocking call

      bConnected = false;

      int rv = GenSocket(Server);
      if(rv == 0)
        {
            //connect the socket, sock has been create before the call
            if(connect(sock, (sockaddr far *) &inetAddr, sizeof(sockaddr)) == 0)
               bConnected = true;               //set connected flag if operation was ok

            if(bConnected) WantAll();            //let server starts negociation
                                                            //first message should be FD_WRITE
        }
      return bConnected;
      }

void TAsyncSocket::SetupWindow()
      {
       TWindow::SetupWindow();
      }

//Cancels any blocking calls, closes the socket if we are
//connected and kills the timer if necessary

void TAsyncSocket::CleanupWindow()
      {
            TWindow::CleanupWindow();               //call parent cleanupwindow
      }

//TAsyncSocket::Startup
//Startup the sockets and check version #
//Start our timer

int TAsyncSocket::Startup()
      {

      int retval = WSAStartup(VERSION_NEED, &wsaData);

      switch(retval)
            {
             case 0:
            bValid = true;
             break;

             case WSASYSNOTREADY:
            Global::Message("system not ready, network function disabled",
                            "WSAStartup error");
             break;

             case WSAVERNOTSUPPORTED:
             case WSAEINVAL:
            Global::Message("Winsock version incompatible",
                                  "Network Function Disabled");
             break;
            }
       //if we have a good version
      if(bValid) SetTimer(TIMER_ID, TIMEOUT_MS);
      return retval;
      }

int TAsyncSocket::GenSocket(char* pHost, int nPort , int nProtocol)
{
if(!bValid) return 0;

memset(&inetAddr, 0, sizeof(inetAddr)); //cleanup structure
inetAddr.sin_family = nProtocol;        //set protocol (always PF_INET)
inetAddr.sin_port = htons(nPort);         //0 let system bind a port
inetAddr.sin_addr.s_addr = htonl(INADDR_ANY);

if(bConnected) closesocket(sock);

sock = socket(nProtocol, SOCK_STREAM, IPPROTO_TCP);

if(sock == INVALID_SOCKET)                     //socket was not created ok
   return LastError();                         //return WSAError
else if(bind(sock, (LPSOCKADDR)&inetAddr, sizeof(inetAddr)) == SOCKET_ERROR)
   return LastError();
return 0;
}

// TAsyncSocket::Connect() public function
// Starts the process of an asynchronous connection
// sets up portions of the internet address structure inetAddr
// for use later when the host look up finishes, etc.
//    pHost -- ptr to desired host name
//    nPort -- local port number to use
//    nProtocol -- protocol, defaults PF_INET
//  Returns:
//    integer -- 0 on success, any other value is either a WinSocket error or
//    one of our defined errors

int TAsyncSocket::Connect(char* pHost, int nPort, int nProtocol)
{
if(!bValid) return 0;

int rv = GenSocket(pHost, nPort,  nProtocol);

if(rv == 0)
      return AsyncGetHostByName(pHost);        //acquire the host asynchronously
return rv;                                              //return last error
}

int TAsyncSocket::Connect(const char* pHost, const char *pUser,
                                      const char *pPass)
      {
      int len = strlen(pHost);
      if(len < 64)
         strcpy(Server, pHost);
      else
        {
         strncpy(Server,   pHost, 63);
         Server[63] = '\0';
        }

      len = strlen(pUser);
      if(len < 16)
         strcpy(User, pUser);
      else
        {
         strncpy(User,     pUser, 15);
         User[15] = '\0';
        }

      len = strlen(pPass);
      if(len < 16)
         strcpy(Password, pPass);
      else
        {
         strncpy(Password, pPass, 15);
         Password[15] = '\0';
        }

      if(!bConnected) Connect(Server);
      return 0;
      }

void TAsyncSocket::WantAll()
      {
      if(WSAAsyncSelect(sock, HWindow, SM_DATAREADY,
                        FD_CONNECT | FD_WRITE | FD_READ | FD_CLOSE) == SOCKET_ERROR)
            Global::Message("in Select network events", "WSASelect error");
      }

void TAsyncSocket::WantRead()
      {
      if(WSAAsyncSelect(sock, HWindow, SM_DATAREADY, FD_READ) ==
            SOCKET_ERROR)
            Global::Message("in Select network read", "WSASelect error");
      }

void TAsyncSocket::WantWrite()
      {
      if(WSAAsyncSelect(sock, HWindow, SM_DATAREADY, FD_WRITE) ==
            SOCKET_ERROR)
            Global::Message("in Select network write", "WSASelect error");
      }

//TAsyncSocket::AsyncGetHostByName
//Starts an asyncronous host name lookup
//stores the returned handle in hAsync
//pHost  : ptr to host name
//Returns: 0 if ok, LastError() if a problem was encountered

int TAsyncSocket::AsyncGetHostByName(const char* pHost)
{
//send HWindow a SM_HOSTNAME message, with hostent
//structure copied in ReadBuffer

unsigned long IPAddress;

if(tmpBuffer == 0) tmpBuffer = new char [TMPBUFFSZ + 1];

if(pHost[0] >= '0' && pHost[0] <= '9')
  {
    IPAddress = inet_addr(pHost);
      hAsync = WSAAsyncGetHostByAddr(HWindow, SM_HOSTNAME, (char *) &IPAddress,
                                     4, PF_INET, tmpBuffer, TMPBUFFSZ);
  }
else
      hAsync = WSAAsyncGetHostByName(HWindow, SM_HOSTNAME, pHost,
                                                tmpBuffer, TMPBUFFSZ);

//use synchorous call to get host, asynchorous call sometimes not working
//pHostent = gethostbyname("electro");
/*
  char lpzmessage[100];
  char lpzIP[16];

  //setup host structures,, copy hostent structure back
  memcpy(&inetAddr.sin_addr, pHostent->h_addr, pHostent->h_length);

  inetAddr.sin_family = PF_INET;
  inetAddr.sin_port = htons(IPPORT_TELNET);

  wsprintf(lpzmessage, "Host %s has IP address ", pHostent->h_name);
  wsprintf(lpzIP, "%s", inet_ntoa(inetAddr.sin_addr));
  lstrcat(lpzmessage, lpzIP);
  mxApp::GPMxApp->SetMessageText(lpzmessage);

  //connect the socket, sock has been create before the call
  if(connect(sock, (sockaddr far *) &inetAddr, sizeof(sockaddr)) == 0)
        bConnected = true;                  //set connected flag if operation was ok
  if(bConnected) WantAll();            //let server starts negociation

      return 0;
*/

if (hAsync == 0)                      //if we did not receive a handle
      return LastError();               //return socket error
else                                  //otherwise
      return 0;                         //return 0 for success
}

//TAsyncSocket::SmHostName
//receives host name notification and connects the socket
//WSAGETSELECTERROR(lp) error information
//WSAGETSELECTEVENT(lp) event code

LRESULT TAsyncSocket::SmHostName(WPARAM /* wp */, LPARAM lp)
{
  char lpzmessage[100];
  char lpzIP[16];

  WSACancelAsyncRequest(hAsync);   //cancel async requests
  if(WSAGETSELECTERROR(lp) == 0)
      {
      //setup host structures,, copy hostent structure back
      memcpy(&Host, tmpBuffer, sizeof(Host));
      memcpy(&inetAddr.sin_addr, Host.h_addr, Host.h_length);

      inetAddr.sin_family = PF_INET;
      inetAddr.sin_port = htons(IPPORT_TELNET);

      sprintf(lpzmessage, "Contact Host %s with IP address ", Host.h_name);
      sprintf(lpzIP, "%s", inet_ntoa(inetAddr.sin_addr));
      strcat(lpzmessage, lpzIP);
      mxApp::GPMxApp->SetMessageText(lpzmessage);
      mxApp::GPMxApp->PumpWaitingMessages();

      //connect the socket, sock has been create before the call
      if(connect(sock, (sockaddr far *) &inetAddr, sizeof(sockaddr)) == 0)
         bConnected = true;                  //set connected flag if operation was ok

      if(bConnected) WantAll();            //let server starts negociation
  }
  delete [] tmpBuffer;  tmpBuffer = 0;
  return true;
}

//Returns the last WinSocket error encountered
//if the error is not connect, try to do reconnect

int TAsyncSocket::LastError()
      {
     if(!bValid) return 0;

       int rv = WSAGetLastError();
       if(rv == WSAENOTCONN && bConnected)
            {
             if(WSAIsBlocking())              //if we are blocking
                  WSACancelBlockingCall();        //cancel the blocking call

             bConnected = false;

            int rn = GenSocket(Server);
            if(rn == 0)
              {
                  if(connect(sock, (sockaddr far *) &inetAddr, sizeof(sockaddr)) == 0)
                     bConnected = true;              //set connected flag if operation was ok
                   if(bConnected) WantAll();      //let server starts negociation
                                                            //first message should be FD_WRITE
              }
            }
      return rv;
      }

//TAsyncSocket::SyncSend
//Syncronous send, use for small amounts of data
//pData -- ptr to data to send
//nLen  -- length of data
//Returns:
//    integer -- SOCKET_ERROR - extract error info with LastError()
//            -- Anything else - contains amount of data sent

int TAsyncSocket::SyncSend(const unsigned char * pData, int nLen)
      {
    if(!bValid) return 0;

      if(WSAIsBlocking()) return 0;

      int rv = send(sock, (char *) pData, nLen, 0);
      if(rv == SOCKET_ERROR)
        {
                  int lasterror = LastError();
                  if(lasterror == WSAEWOULDBLOCK)
                    { return 0; }
                  Global::Message((char *) pData, "Socket Send Error");
                  return 0;
        }
      *ostrb << pData << endl;
      return rv;
      }

//TAsyncSocket::SyncRead
//Syncronous recv, use when you expect small amounts of data
//pData -- ptr to data for storage
//nMaxLen  -- max length of data
//Returns:
//    integer -- SOCKET_ERROR - extract error info with LastError()
//            -- Anything else - contains amount of data received

int TAsyncSocket::SyncRead(unsigned char * pData, int nMaxLen)
      {
    if(!bValid) return 0;

      if(WSAIsBlocking()) return 0;

      memset(pData, 0, nMaxLen-1);

      int rv = recv(sock, (char *) pData, nMaxLen, 0);
      *ostra << pData << endl;

      if(rv == SOCKET_ERROR)
        {
            int lasterror = LastError();
            if(lasterror == WSAEWOULDBLOCK)
              { return 0; }
            Global::Message((char *) pData, "Socket Read Error");
            return 0;
        }
      return rv;
      }

//TAsyncSocket::EvTimer
//Catches potential blocking problems and times out
//after BLOCK_TIMEOUT number of seconds

static int bTick = 0;
static bool bInTimer = false;

void TAsyncSocket::EvTimer(uint /* uTimerId */)
{
    if(!bValid) return;

      if (!bInTimer)
      {
      bInTimer = true;
      if (WSAIsBlocking())
            {
            bTick++;
            if (bTick > BLOCK_TIMEOUT)
                  {
                  WSACancelBlockingCall();
                  Global::Message("cancel blocking call","Error in EvTimer");
                  }
            }
            else bTick = 0;
            bInTimer = false;
      }
}

void TAsyncSocket::WantNone()
      {
      //cancel any previous selection
      WSAAsyncSelect(sock, HWindow, 0, 0);
      }

LRESULT TAsyncSocket::SmDataReady(WPARAM wp, LPARAM lp)
{
if(WSAGETSELECTERROR(lp) != 0) return true;

WSAAsyncSelect(sock, HWindow, 0, 0);

if(WSAGETSELECTEVENT(lp) == FD_CLOSE)
  {
  if(TelClient)
    {
       if(TelClient->Read())
         {
          PostMessage(SM_DATAREADY, wp, lp);
            return true;
         }
      }
  bConnected = false; closesocket(sock); return true;
  }

else if(WSAGETSELECTEVENT(lp) == FD_CONNECT)
  {
  }

else if(WSAGETSELECTEVENT(lp) == FD_READ)
  {
  if(TelClient) TelClient->Read();
  }

else if(WSAGETSELECTEVENT(lp) == FD_WRITE)
  {
  if(TelClient) TelClient->Send();
  }

return true;
}
0
 

Author Comment

by:Archadious
ID: 1162640
Thanks for the sample code, it should help me understand where my own code is faulty.  

-Daniel

0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Written by John Humphreys C++ Threading and the POSIX Library This article will cover the basic information that you need to know in order to make use of the POSIX threading library available for C and C++ on UNIX and most Linux systems.   [s…
Introduction This article is a continuation of the C/C++ Visual Studio Express debugger series. Part 1 provided a quick start guide in using the debugger. Part 2 focused on additional topics in breakpoints. As your assignments become a little more …
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

759 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

20 Experts available now in Live!

Get 1:1 Help Now