Article View: borland.public.cppbuilder.internet.socket
Article #5670BCB6 bug ?
From: maxch
Date: Mon, 05 Jul 2004 15:57
Date: Mon, 05 Jul 2004 15:57
743 lines
19407 bytes
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-mailShow 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