🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.internet.socket
Article #5670

BCB6 bug ?

#5670
From: maxch
Date: Mon, 05 Jul 2004 15:57
743 lines
19407 bytes
Hi All,
I have a very very strange question on C++Builder6, maybe it should
be posted on Compiler group, however, the problem is encountered when I
compile a SOCKET program which download from
http://support.microsoft.com/default.aspx?scid=kb;en-us;193066 EchoC
which I just have changed some lines of the code.

Please see following for the code.
The symptom is
if I commented the line marked with **************
    the program terminated successfully
else
    the program goes to line marked with @@@@@@@@ and infinitely
    invoke that function, at last, a unkown software exception pop up.

I never encounted this problem before, whether it's a compiler bug?

Computer info:
Win2K prof, with SP4
C++BUILDER 6 with SP4


code:

//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%% the following is echoc.h

#ifndef _OVERLAPPEDECHOCLIENT
#define _OVERLAPPEDECHOCLIENT

#define MAX_CHAR_LINE 1024

VOID
dbgprintf(
 const PCHAR lpszFmt,
 ...)
/*++
Routine Description:

 Use this function for printf-style debugging output.

Arguments:

 lpszFmt - format string

Return Value:

    None.
--*/
{
 CHAR szBuf[512];
 va_list vargs;

 va_start(vargs, lpszFmt);
 vsprintf(szBuf, lpszFmt, vargs);
 va_end(vargs);
 OutputDebugString(szBuf);
 return;
} // dbgprintf


//
// Console control handler, intercept Ctrl+C and Ctrl+Brk
//

BOOL WINAPI
CtrlHandler (
 DWORD dwEvent
 );

WSAEVENT gheventAsynRecv = NULL;
WSAEVENT gheventAsynSend = NULL;
WSAEVENT gheventOlSock = NULL;

//
// echo client socket
//

SOCKET  gsClientSock = INVALID_SOCKET;

//
// Default is overlapped I/O without notifications.
//

BOOL bCompletionFunction = TRUE;

//
// If user hits Ctrl+C, gbEndClient is set to TRUE
//

BOOL gbEndClient = FALSE;

DWORD gbytesRecvd = 0;

//
// Socket state is closed
//

BOOL gbSocketClosed = FALSE;

#endif //_OVERLAPPEDECHOCLIENT


//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%% the following is echoc.cpp

// olechoc.cpp
//
// Copyright (c)1998 Microsoft Corporation, All Right Reserved
//
// Module description:
//
//  The program demonstrates overlapped socket I/O with or without
completion
//  callback functions. It reads from console input, sends the input to the
echo
//  server, and displays the echo.
//     Then it loops back to read again and continue the cycle in an endless
loop.
//  The endless loop will only break when users hit CTRL+C or
//  CTRL+Brk.
//
//
//

#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include "echoc.h"



void CALLBACK
AysncSendCompletion(
 DWORD dwError,
 DWORD cbTransferred,
 LPWSAOVERLAPPED lpOverlapped,
 DWORD dwFlags
 )
/*++
Routine Description:

 Aysnc Send Completion Routine

Return Value:

    None.
--*/
{
 dbgprintf("AysncSendCompletion dwError is %d \n", dwError); //
@@@@@@@@@@@@@@@@@@@@
 dbgprintf("AysncSendCompletion cbTransferred is %d \n", cbTransferred);
 dbgprintf("AysncSendCompletion dwFlags is %d \n", dwFlags);

 //
 // The other side closed socket, setting gbSocketClosed to TRUE so that
 // main thread can bail out and close the socket.
 //

 if (dwError == 0 && cbTransferred == 0) gbSocketClosed = TRUE;

 //
 // if not ERROR_IO_INCOMPLETE, then error occurs and we set
 // gbSocketClosed to TRUE so that
 // main thread can bail out and close the socket.
 //

 if (dwError !=0 && dwError != 996) gbSocketClosed = TRUE;

 //
 // Signal the event so that main thread wait unblocks.
 //

 WSASetEvent( gheventAsynSend);

} // AysncSendCompletion



void CALLBACK
AysncRecvCompletion(
 DWORD dwError,
 DWORD cbTransferred,
 LPWSAOVERLAPPED lpOverlapped,
 DWORD dwFlags)
/*++
Routine Description:

 Aysnc Recv Completion Routine

Return Value:

    None.
--*/
{
 dbgprintf("AysncRecvCompletion dwError is %d \n", dwError);
 dbgprintf("AysncRecvCompletion cbTransferred is %d \n", cbTransferred);
 dbgprintf("AysncRecvCompletion dwFlags is %d \n", dwFlags);

 gbytesRecvd = cbTransferred;

 //
 // The other side closed socket, setting gbSocketClosed to TRUE so that
 // main thread can bail out and close the socket.
 //

 if (dwError == 0 && cbTransferred == 0) gbSocketClosed = TRUE;


 //
 // if not ERROR_IO_INCOMPLETE, then error occurs and we set
 // gbSocketClosed to TRUE so that
 // main thread can bail out and close the socket.
 //

 if (dwError !=0 && dwError != 996) gbSocketClosed = TRUE;

 //
 // Signal the event so that main thread wait unblocks.
 //

 WSASetEvent( gheventAsynRecv);

} // AysncRecvCompletion



void main(int argc, char *argv[])
/*++

Routine Description:

 Process main. It first sets up a console control handler so that we can
intercetp
 CTRL+C or CTRL+Brk to shut down echo client and clean up resources. It then
 initiates winsock runtime, and depends the command line bCompletionFunction
to
 determine whether to use a completion routine with the socket overlapped
i/o.

Arguments:

 int argc,
 char *argv[]

Return Value:

    None.

--*/
{
 TCHAR  strSendData[MAX_CHAR_LINE]; // Send line buffer
 TCHAR  strRecvData[MAX_CHAR_LINE]; // Read line buffer
 WSABUF  buffSend;   // WSABuf for WSASend
 WSABUF  buffRecv;   // WSABuf for WSARecv

 TCHAR  strHostEntry[256];
 unsigned short  nPortID;

 int   nWSAError;
 WSADATA  wsaData;
 SOCKADDR_IN addrInet;


 WSAOVERLAPPED olSend;   // OL structure for send
 WSAOVERLAPPED olRecv;   // OL structure for recv
 WSAEVENT  eventArray[2];

 DWORD  dwNumBytes;
 DWORD  dwFlags;
 DWORD  dwRet, i;
 int   nZero = 0;
 int   ch;
 BOOL  bReadAll = FALSE;
 BOOL  bSendAll = FALSE;
 int   nSendSize = 0;

 if (argc != 4) {

  printf("Usage: echoc.exe <server> <port> <completion routine(0 or 1)>\n");
  return;
 }

 if (atoi(argv[3]) == 0) {
    bCompletionFunction = FALSE;
  }
 else {
    bCompletionFunction = TRUE;
  }

 lstrcpy(strHostEntry, argv[1]);
 nPortID = (unsigned short) atoi(argv[2]);

 try {
    try {

      if (!SetConsoleCtrlHandler (
            CtrlHandler,  //Console Control Handler
            TRUE    //Install Console Handler
            )) {
        printf ("SetConsoleCtrlHandler failed to install console handler:
%d\n",GetLastError());
        return;
        //__leave;
      }

      if ((gheventAsynRecv = WSACreateEvent()) == WSA_INVALID_EVENT) {
        printf("WSACreateEvent failed: %d\n", WSAGetLastError());
        dbgprintf("WSACreateEvent failed: %d\n", WSAGetLastError());
        return;//__leave;
      }

      if ((gheventAsynSend = WSACreateEvent()) == WSA_INVALID_EVENT) {
        printf("WSACreateEvent failed: %d\n", WSAGetLastError());
        dbgprintf("WSACreateEvent failed: %d\n", WSAGetLastError());
        return; //__leave;
      }

      if ((gheventOlSock = WSACreateEvent()) == WSA_INVALID_EVENT) {
        printf("WSACreateEvent failed: %d\n", WSAGetLastError());
        dbgprintf("WSACreateEvent failed: %d\n", WSAGetLastError());
        return; //__leave;
      }

      ZeroMemory(&olSend, sizeof(WSAOVERLAPPED));
      ZeroMemory(&olRecv, sizeof(WSAOVERLAPPED));

      if (  WSAStartup(0x202,    //Request Winsock 2.02
                        &wsaData
        ) == SOCKET_ERROR) {

        dbgprintf("WSAStartup failed with error %d\n",WSAGetLastError());
        return; //__leave;
      }

      if ((gsClientSock = WSASocket(
          AF_INET,   // address family
          SOCK_STREAM,  // socket type
          IPPROTO_IP,   // protocol
          NULL,    // pointer to a WSAPROTOCOL_INFO structure
          0,     // reserved for future use with socket groups
          WSA_FLAG_OVERLAPPED // socket attribute required for IOCP;
          )) == INVALID_SOCKET)  {

        throw "asdflkj";
        dbgprintf("Failed to get a socket %d\n", WSAGetLastError());
        return; //__leave;
      }

      if ((addrInet.sin_addr.s_addr = inet_addr(strHostEntry)) ==
INADDR_NONE) {
        printf("*** inaddress none\n");

        LPHOSTENT lphostent;
        if ((lphostent = gethostbyname(strHostEntry)) != NULL) {
          printf("*** get ip ok by name\n");
          addrInet.sin_addr.s_addr = ((LPIN_ADDR)
(lphostent->h_addr_list[0]))->s_addr;
        }
        else {
          printf("*** get ip error by name %s.\n", strHostEntry);
          dbgprintf("Failed to gethostbyname %d\n", WSAGetLastError());
//**************
          return; //__leave;
        }
      }

      printf("here ...\n");
      addrInet.sin_family = AF_INET;
      addrInet.sin_port = htons(nPortID);

      printf("start to connecting servier....\n");
      if (WSAConnect(
          gsClientSock,
          (PSOCKADDR) &addrInet,
          sizeof(addrInet),
          NULL,
          NULL,
          NULL,
          NULL
          ) == SOCKET_ERROR) {

        dbgprintf("Failed to connect a socket %d\n", WSAGetLastError());
        return; //__leave;
      }
      printf("connection ok\n");
      gbSocketClosed = FALSE;

      //
      // Disable send buffering on the socket.  Setting SO_SNDBUF
      // to 0 causes winsock to stop bufferring sends and perform
      // sends directly from our buffers, thereby reducing CPU
      // usage.
      //

      nZero = 0;
      if ( setsockopt(
          gsClientSock,
          SOL_SOCKET,
          SO_SNDBUF,
          (char *)&nZero,
          sizeof(nZero)
          ) == SOCKET_ERROR) {
        dbgprintf("setsockopt failed to set SO_SNDBUF %d\n",
WSAGetLastError());
        return; //__leave;
      }

      while (!gbEndClient) {

        buffSend.buf = strSendData;
        buffSend.len = 0;
        printf( "Enter a line: " );   /* Read in single line from "stdin":
*/

        for( i = 0; (i < MAX_CHAR_LINE) &&  ((ch = getchar()) != EOF)
                && (ch != '\n'); i++ )
          buffSend.buf[i] = (char)ch;
        /* Terminate string with null character: */
        buffSend.buf[i] = '\n';
        buffSend.buf[i+1] = '\0';

        buffSend.len = i+1;


        eventArray[0] = gheventOlSock;
        nSendSize = buffSend.len;
        //
        // if a completion function is used, we don't need an event handle
        // in the overlapped structure.
        //

        if (!bCompletionFunction) olSend.hEvent= gheventOlSock;

        bSendAll = FALSE;
        while (TRUE)  //we will send in a loop until nSendSize bytes are
sent
        {
          if ((dwRet = WSASend(
            gsClientSock,
            &buffSend,
            1,
            &dwNumBytes,
            0,
            &olSend,
            bCompletionFunction? AysncSendCompletion : NULL)
            ) == SOCKET_ERROR) {

            nWSAError= WSAGetLastError();

            if (nWSAError != ERROR_IO_PENDING) {

              dbgprintf("WSASend failed with error %d\n", nWSAError);
              return; //__leave;
            }
            else {
              //ERROR_IO_PENDING is expected.
            }
          }
          else {

            dbgprintf("WSASend sends data out immediately: %d bytes sent\n",
dwNumBytes);
          }

          //
          //  eventArray contains gheventOlSock.
          //  gheventOlSock is set in olSend only when no completion
function is used.
          //  When the overlapped send completes, gheventOlSock is going to
signal.
          //
          //  For overlapped send with completion function, gheventOlSock is
not set in
          //  olSend. So gheventOlSock is not going to signal, however the
last param
          //  of WSAWaitForMultipleEvents is going to put this thread into
an alertable
          //  wait state. When overlapped Send completes and completion
          //  function gets called, this Wait returns.
          //

          if (WSAWaitForMultipleEvents(
              1,
              eventArray,
              FALSE,
              WSA_INFINITE,
              bCompletionFunction
              ) == WSA_WAIT_FAILED) {

            dbgprintf("WSAWaitForMultipleEvents failed %d\n",
WSAGetLastError());
            return; //__leave;
          }

          //
          // Reset the gheventOlSock
          //

          WSAResetEvent(eventArray[0]);

          if (bCompletionFunction) {

            //
            // For overlapped send with completion routine, we will wait on
            // gheventAsynSend. The end of the AysncSendCompletion signals
            // the event
            //

            WSAWaitForMultipleEvents(
              1,
              &gheventAsynSend,
              TRUE,
              INFINITE,
              TRUE);
            WSAResetEvent(gheventAsynSend);
          }

          if (WSAGetOverlappedResult(
              gsClientSock,
              &olSend,
              &dwNumBytes,
              FALSE,
              &dwFlags
              ) == TRUE) {

            dbgprintf("%d bytes were sent\n", dwNumBytes);
          }
          else {

            dbgprintf("WSAGetOverlappedResult failed with error %d\n",
WSAGetLastError());
          }

          //
          // An overlapped write completes doesn't necessary mean all the
data to send are
          // sent.
          //

          buffSend.len -= dwNumBytes;
          if (buffSend.len == 0)
            break;
          else
            buffSend.buf += dwNumBytes;
        }

        dbgprintf ("send complete\n");

        //
        // Now we need to read the echo back.
        //

        //
        // if a completion function is used, we don't need an event handle
        // in the overlapped structure.
        //

        if (!bCompletionFunction) olRecv.hEvent = gheventOlSock;

        bReadAll = FALSE;
        while (TRUE)  //we will read until '\n' is received
        {

          buffRecv.buf = strRecvData;
          buffRecv.len = sizeof(strRecvData);
          ZeroMemory (buffRecv.buf, buffRecv.len);
          dwFlags = 0;
          dwNumBytes = 0;


          if ((dwRet =WSARecv(
              gsClientSock,
              &buffRecv,
              1,
              &dwNumBytes,
              &dwFlags,
              &olRecv,
              bCompletionFunction? AysncRecvCompletion : NULL
              )) == SOCKET_ERROR) {

            nWSAError = WSAGetLastError();

            if (nWSAError != ERROR_IO_PENDING)
            {
              dbgprintf("WSARecv failed with error %d\n", nWSAError);
              return; //__leave;
            }
          }
          else {

            dbgprintf("WSARecv returns immediately: %d bytes read\n",
dwNumBytes);
          }

        //
        //  eventArray contains gheventOlSock.
        //  gheventOlSock is set in olRecv only when no completion function
is used.
        //  When the overlapped recv completes, gheventOlSock is going to
signal.
        //
        //  For overlapped recv with completion function, gheventOlSock is
not set in
        //  olSend. So gheventOlSock is not going to signal, however the
last param of
        //  WSAWaitForMultipleEvents is going to put this thread into an
alertable wait state.
        //  When overlapped Recv completes and completion
        //  function gets called, this Wait returns.
        //
          if (WSAWaitForMultipleEvents(
              1,
              eventArray,
              FALSE,
              WSA_INFINITE,
              bCompletionFunction
              ) == WSA_WAIT_FAILED) {

            dbgprintf("WSAWaitForMultipleEvents failed %d\n",
WSAGetLastError());
            return; //__leave;
          }

          //
          // Reset the gheventOlSock
          //

          WSAResetEvent(eventArray[0]);

          if (bCompletionFunction) {

          //
          // For overlapped recv with completion routine, we will wait on
          // gheventAsynRecv. The end of the AysncSendCompletion signals
          // the event
          //
            WSAWaitForMultipleEvents(
              1,
              &gheventAsynRecv,
              TRUE,
              INFINITE,
              TRUE);
            WSAResetEvent(gheventAsynRecv);
          }

          if (!bCompletionFunction && WSAGetOverlappedResult(
                gsClientSock,
                &olRecv,
                &dwNumBytes,
                FALSE,
                &dwFlags
                ) == TRUE) {

            if (dwNumBytes == 0)
              break;

            gbytesRecvd = dwNumBytes;
            dbgprintf("%d bytes were received\n", dwNumBytes);
          }
          else {

            if (!bCompletionFunction) {

              dbgprintf("WSAGetOverlappedResult failed with error %d\n",
WSAGetLastError());
            }
          }
          if (gbSocketClosed) return; //__leave;

          printf(buffRecv.buf);

          nSendSize -= dwNumBytes;
          if (nSendSize == 0 ) break; // read all echo, break
        }
      }

    }
    catch (...) {
      printf("something error!!! \n");
    }
  }
 __finally {

  if (gheventAsynRecv) WSACloseEvent(gheventAsynRecv);
  if (gheventAsynSend) WSACloseEvent(gheventAsynSend);
  if (gheventOlSock)  WSACloseEvent(gheventOlSock);
  if (gsClientSock != INVALID_SOCKET) closesocket(gsClientSock);
  WSACleanup();
  SetConsoleCtrlHandler (CtrlHandler, FALSE);
 }

}// end main


BOOL WINAPI CtrlHandler (
 DWORD dwEvent
 )
/*++

Routine Description:

 Intecept CTRL+C or CTRL+Brk for the console.

Arguments:

 dwEvent - Console events

Return Value:

    None.

--*/
{
 switch (dwEvent) {

  case CTRL_C_EVENT:
  case CTRL_BREAK_EVENT:
  case CTRL_LOGOFF_EVENT:
  case CTRL_SHUTDOWN_EVENT:
  case CTRL_CLOSE_EVENT:

   gbEndClient = TRUE;

   if (gsClientSock) closesocket (gsClientSock);
   gsClientSock = INVALID_SOCKET;
   if (gheventAsynRecv) WSACloseEvent(gheventAsynRecv);
   gheventAsynRecv = NULL;
   if (gheventAsynSend) WSACloseEvent(gheventAsynSend);
   gheventAsynSend = NULL;
   if (gheventOlSock)  WSACloseEvent(gheventOlSock);
   gheventOlSock = NULL;
   WSACleanup();
   return (FALSE); //clean enough to exit the process now.

  default:
   // unknown type--better pass it on.
   return (FALSE);
  }
    // Handled all known events
 return (TRUE);
} //CtrlHandler
Technical Details
Message-ID: <40e97ab1@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!news.glorb.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail

Show Full Headers
Complete Article Headers
X-Google-Thread: 11508e,f984f2ee1eebe5f7,start
X-Google-Attributes: gid11508e,public
X-Google-Language: ENGLISH,ASCII-7-bit
From: "maxch" <chenzero@netease.com>
Newsgroups: borland.public.cppbuilder.internet.socket
Subject: BCB6 bug ?
Date: Mon, 5 Jul 2004 23:57:51 +0800
Lines: 747
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1409
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1409
NNTP-Posting-Host: 219.136.32.141
Message-ID: <40e97ab1@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1089043121 219.136.32.141 (5 Jul 2004 08:58:41 -0700)
Path: arc1-ca.pugleaf.net!g2news1.google.com!news1.google.com!news.glorb.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail