From: "Bill" don't want more on
Steve,

I read your post but partially addressed it in a reply to another post.

Now I handle the OnConnect() and check if error or no error. If error, I
wrap things up and delete the socket.

But is there any way to safely delete before getting the OnConnect()
callback? The user might get impatient and click the button while waiting.
Will I always always get the OnConnect() with timeout (if there is no port
to connect to)? I could disable the button, but if the callback never comes,
the program will have to be aborted.

For example, if I call Close() even though it hadn't conencted yet, would it
be safe?

Thanks,

Bill

"Stephen Myers" <""StephenMyers\"@discussions(a)microsoft.com"> wrote in
message news:us7qjoFwKHA.4492(a)TK2MSFTNGP05.phx.gbl...
> Bill Brehm wrote:
>> I have a problem with CAsynsocket. I can connect to a remote socket. When
>> I want to close the connection, I just delete the socket object (which
>> closes the connection) and have no problems.
>>
>> But if I've started to connect to a remote socket that doesn't exist (or
>> doesn't accept), and I delete the local socket object while waiting for
>> the connection, I sometimes get an assert in CAsyncSocket::DoCallBack().
>> See below. Actually, it's not in the middle of an Accept call because I
>> test with an address and port that I know doesn't exist.
>>
>> Any idea how I should be doing this so as not to crash my program?
>>
>> Thanks,
>>
>> Bill
>>
>>
>> void PASCAL CAsyncSocket::DoCallBack(WPARAM wParam, LPARAM lParam)
>> {
>> if (wParam == 0 && lParam == 0)
>> return;
>>
>> // Has the socket be closed?
>> CAsyncSocket* pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam,
>> TRUE);
>>
>> // If yes ignore message
>> if (pSocket != NULL)
>> return;
>>
>> pSocket = CAsyncSocket::LookupHandle((SOCKET)wParam, FALSE);
>> if (pSocket == NULL)
>> {
>> // Must be in the middle of an Accept call
>> pSocket = CAsyncSocket::LookupHandle(INVALID_SOCKET, FALSE);
>> ASSERT(pSocket != NULL);
>> <-------------------------------------------------asserts here sometimes
>> but not always.
>> pSocket->m_hSocket = (SOCKET)wParam;
>> CAsyncSocket::DetachHandle(INVALID_SOCKET, FALSE);
>> CAsyncSocket::AttachHandle(pSocket->m_hSocket, pSocket, FALSE);
>> }
>>
>>
>
> My guess is that the Connect handling is causing the problem. Connect()
> will return immediately. You will then get OnConnect(), with or without an
> error. The timeout varies, but I would expect it to be on the order of 5
> seconds. Once OnConnect has been called you should be able to close the
> socket.
>
> HTH
> Steve


From: Hector Santos on
Bill,

Two points:

First, dealing with async, you need to watch for your events and they
need to be handled.

Second, the subject "proper way to close a socket" is important to
understand the basics here because not doing it properly can cause
MORE unexpected events.

The proper way to close a socket is to use whats called:

TCP Half Closed

And you need to make sure your MFC Async socket class implementation
supports it as well.

Far too many applications do not do this correctly and have all sorts
of issues, including unexpected reconnection attemps (RESET).

The short end of the logic is that you are telling the other side

"Hey I am closing. Stop sending me data"
"Hey I am closing. I'm not going to be sending more data"

or both, but its half closed because you are closed but the other end
is not or vice-versa. So even if you close, the other end may not
finished sending/receiving and if you don't flush the I/O, then you
can get TCP resets.

I'm pretty sure MSDN had a lengthy discussion about this the last time
I visited the issue earlier in the decade when new things were
happening in our internet world:

- higher bandwidths, fast receiver, slower sends, so there
new timing issues here.

- broken software that didn't see the problem under slower
speeds (or same speeds) or did not flush 1 last byte or so.

Apache and IE has this problem, remember the famous "Page Not Found"
issue with IE? It was all related to incorrect usage of closing
sockets and half close socket teardown concepts.

The book "TCP/IP Illustrated Volume 1," specifically talks about "TCP
Half Close" operations and how so many applications are broken because
they done use it.

See shutdown() command.
See SO_LINGER
Google: sockets half-close

See http://msdn.microsoft.com/en-us/library/ms738547(VS.85).aspx
Graceful Shutdown, Linger Options, and Socket Closure

By the way, it is really not that hard. When closing, you simply need
to FLUSH any reads. For example, here the basic idea:

// HalfCloseSocket() performs a TCP Half Close by calling shutdown()
// which signals the remote that no more data is going to be
// sent (FIN signal). HalfCloseSocket() then goes into a
// recv() loop to wait for the remote to acknowledge the close.
// This acknowledgment comes as a recv() return value
// of zero (less).

BOOL HalfCloseSocket(SOCKET socket)
{
if (shutdown(socket,SD_SENT) != 0) {
return FALSE;
}
int ret = 0;
int msecs = 10; // poor man sanity check
char buf[8*1024];
while ((ret = recv(socket, buf,sizeof(buf),0)) > 0) {
buf[0] = 0;
buf[1] = 0;
msecs--;
if (msecs == 0) break;
}
return closesocket(socket);
}

---

Bill < wrote:

> Geoff,
>
> The code I showed was from MFC, not from me. So I'm not doing any polling. I
> pasted that in to show where the ASSERT is coming from.
>
> My code is deleting the socket object, which according to my comment will
> also close the connection.
>
> delete m_pClientSocket; // this will also close the connection
> m_pClientSocket = NULL;
>
> The help says "The socket object's destructor calls Close for you." so I
> guess that's why I think I only need to delete the object.
>
> I do respond to OnClose().
>
> I just put some breakpoints at OnClose(), OnConnect() and OnAccept().
> Neither is being hit when I try to connect to a non-existent IP and port,
> whether the ASSERT happens or not. The call stack looks like below, which
> only tells me it's not coming directly from a call in my code. It looks like
> the systems was preparing to do a callback.
>
> Oh, I see if I am patient, I will get a call to OnConnect() with an 10060
> (WSAETIMEDOUT) error about 20 seconds after initiating the conenct. I do
> have to handle that differently.
>
> I was thinking that maybe the timeout callback was coming in just as I was
> deleting the socket object. But it doesn't seem likely as I can get the
> ASSERT long before the 20 second timeout occurs. Any way I can determine
> what the callback would have been had it not crashed? wParam = 1764 and
> lParam = 657850384 or hex 27360010.
>
> Bill
>
> CAsyncSocket::DoCallBack(unsigned int 1764, long 657850384) line 513 + 25
> bytes
> CSocket::ProcessAuxQueue() line 823
> CSocketWnd::OnSocketNotify(unsigned int 1764, long 657850384) line 1127
> CWnd::OnWndMsg(unsigned int 883, unsigned int 1764, long 657850384, long *
> 0x0012f560) line 1815 + 17 bytes
> CWnd::WindowProc(unsigned int 883, unsigned int 1764, long 657850384) line
> 1585 + 30 bytes
> AfxCallWndProc(CWnd * 0x009f5798 {CSocketWnd hWnd=0x000110d6}, HWND__ *
> 0x000110d6, unsigned int 883, unsigned int 1764, long 657850384) line 215 +
> 26 bytes
> AfxWndProc(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764, long
> 657850384) line 368
> AfxWndProcBase(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764,
> long 657850384) line 220 + 21 bytes
> USER32! 7e418734()
> USER32! 7e418816()
> USER32! 7e4189cd()
> USER32! 7e4196c7()
> CWinThread::PumpMessage() line 853
> CWnd::RunModalLoop(unsigned long 4) line 3478 + 19 bytes
> CDialog::DoModal() line 539 + 12 bytes
> CSocketApp::InitInstance() line 65 + 11 bytes
> AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char *
> 0x00141f1e, int 1) line 39 + 11 bytes
> SOCKET! 0040dec8() line 30
> WinMainCRTStartup() line 330 + 54 bytes
>
>
> "Geoff" <geoff(a)invalid.invalid> wrote in message
> news:e6cep51nscc07242lblsa06lublh53030h(a)4ax.com...
>> On Wed, 10 Mar 2010 10:42:21 +0800, "Bill" <<don't want more spam>>
>> wrote:
>>
>>> Did I ask this in the right newsgroup? (Just not sure if there is a more
>>> appropriate palce to ask this.) Tnx.
>>>
>> Dr. Joe usually has a lot to say about callbacks and about
>> CAsyncSocket but he must be busy polishing his new MVP award.
>>
>> I am not sure why you think you need to poll the handle. What you
>> should be doing is either closing it with CAsyncSocket::Close when you
>> are done with your session on your end or else responding to
>> CAsyncSocket::OnClose and doing any cleanup if it is closed from the
>> other end.
>
>



--
HLS
From: Hector Santos on
Bill < wrote:

> But is there any way to safely delete before getting the OnConnect()
> callback?


Yes, use a TCP Half Close concept as illustrated in the
HalfCloseSocket() example in my last post.

Because you are not doing a shutdown, your destruction here:

delete m_pClientSocket; // this will also close the connection

will cause a TCP RST (RESET), hence an OnConnect() event.

Using proper half close teardown will resolve this. See the
shutdown() socket command in MSDN.

--
HLS
From: "Bill Brehm" don't want on
Hector,

Thanks for making me aware of this issue. I didn't know about it before. I
derived from AsyncSocket so once I got things mostly working, I didn't
really go back to see other member functions available and to understand
them. I have looked over the documentation and understand what must be done
and I will do it shortly.

But do you think this is the cause of my particular crash / assert? In my
case I'm trying to connect to a socket that doesn't exist (for testing
purposes) and want the user to be able to break the connection attempt
without waiting for the 20 second timeout. Since the connection is never
made, there is no chance of data being sent and received so would half
closing the socket from the client side have an affect on the assert that
I'm getting (intermittently)?

Thanks,

Bill


"Hector Santos" <sant9442(a)nospam.gmail.com> wrote in message
news:O5WlEERwKHA.1692(a)TK2MSFTNGP04.phx.gbl...
> Bill,
>
> Two points:
>
> First, dealing with async, you need to watch for your events and they need
> to be handled.
>
> Second, the subject "proper way to close a socket" is important to
> understand the basics here because not doing it properly can cause MORE
> unexpected events.
>
> The proper way to close a socket is to use whats called:
>
> TCP Half Closed
>
> And you need to make sure your MFC Async socket class implementation
> supports it as well.
>
> Far too many applications do not do this correctly and have all sorts of
> issues, including unexpected reconnection attemps (RESET).
>
> The short end of the logic is that you are telling the other side
>
> "Hey I am closing. Stop sending me data"
> "Hey I am closing. I'm not going to be sending more data"
>
> or both, but its half closed because you are closed but the other end is
> not or vice-versa. So even if you close, the other end may not finished
> sending/receiving and if you don't flush the I/O, then you can get TCP
> resets.
>
> I'm pretty sure MSDN had a lengthy discussion about this the last time I
> visited the issue earlier in the decade when new things were happening in
> our internet world:
>
> - higher bandwidths, fast receiver, slower sends, so there
> new timing issues here.
>
> - broken software that didn't see the problem under slower
> speeds (or same speeds) or did not flush 1 last byte or so.
>
> Apache and IE has this problem, remember the famous "Page Not Found" issue
> with IE? It was all related to incorrect usage of closing sockets and
> half close socket teardown concepts.
>
> The book "TCP/IP Illustrated Volume 1," specifically talks about "TCP
> Half Close" operations and how so many applications are broken because
> they done use it.
>
> See shutdown() command.
> See SO_LINGER
> Google: sockets half-close
>
> See http://msdn.microsoft.com/en-us/library/ms738547(VS.85).aspx
> Graceful Shutdown, Linger Options, and Socket Closure
>
> By the way, it is really not that hard. When closing, you simply need to
> FLUSH any reads. For example, here the basic idea:
>
> // HalfCloseSocket() performs a TCP Half Close by calling shutdown()
> // which signals the remote that no more data is going to be
> // sent (FIN signal). HalfCloseSocket() then goes into a
> // recv() loop to wait for the remote to acknowledge the close.
> // This acknowledgment comes as a recv() return value
> // of zero (less).
>
> BOOL HalfCloseSocket(SOCKET socket)
> {
> if (shutdown(socket,SD_SENT) != 0) {
> return FALSE;
> }
> int ret = 0;
> int msecs = 10; // poor man sanity check
> char buf[8*1024];
> while ((ret = recv(socket, buf,sizeof(buf),0)) > 0) {
> buf[0] = 0;
> buf[1] = 0;
> msecs--;
> if (msecs == 0) break;
> }
> return closesocket(socket);
> }
>
> ---
>
> Bill < wrote:
>
>> Geoff,
>>
>> The code I showed was from MFC, not from me. So I'm not doing any
>> polling. I pasted that in to show where the ASSERT is coming from.
>>
>> My code is deleting the socket object, which according to my comment will
>> also close the connection.
>>
>> delete m_pClientSocket; // this will also close the connection
>> m_pClientSocket = NULL;
>>
>> The help says "The socket object's destructor calls Close for you." so I
>> guess that's why I think I only need to delete the object.
>>
>> I do respond to OnClose().
>>
>> I just put some breakpoints at OnClose(), OnConnect() and OnAccept().
>> Neither is being hit when I try to connect to a non-existent IP and port,
>> whether the ASSERT happens or not. The call stack looks like below, which
>> only tells me it's not coming directly from a call in my code. It looks
>> like the systems was preparing to do a callback.
>>
>> Oh, I see if I am patient, I will get a call to OnConnect() with an 10060
>> (WSAETIMEDOUT) error about 20 seconds after initiating the conenct. I do
>> have to handle that differently.
>>
>> I was thinking that maybe the timeout callback was coming in just as I
>> was deleting the socket object. But it doesn't seem likely as I can get
>> the ASSERT long before the 20 second timeout occurs. Any way I can
>> determine what the callback would have been had it not crashed? wParam =
>> 1764 and lParam = 657850384 or hex 27360010.
>>
>> Bill
>>
>> CAsyncSocket::DoCallBack(unsigned int 1764, long 657850384) line 513 + 25
>> bytes
>> CSocket::ProcessAuxQueue() line 823
>> CSocketWnd::OnSocketNotify(unsigned int 1764, long 657850384) line 1127
>> CWnd::OnWndMsg(unsigned int 883, unsigned int 1764, long 657850384, long
>> * 0x0012f560) line 1815 + 17 bytes
>> CWnd::WindowProc(unsigned int 883, unsigned int 1764, long 657850384)
>> line 1585 + 30 bytes
>> AfxCallWndProc(CWnd * 0x009f5798 {CSocketWnd hWnd=0x000110d6}, HWND__ *
>> 0x000110d6, unsigned int 883, unsigned int 1764, long 657850384) line 215
>> + 26 bytes
>> AfxWndProc(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764, long
>> 657850384) line 368
>> AfxWndProcBase(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764,
>> long 657850384) line 220 + 21 bytes
>> USER32! 7e418734()
>> USER32! 7e418816()
>> USER32! 7e4189cd()
>> USER32! 7e4196c7()
>> CWinThread::PumpMessage() line 853
>> CWnd::RunModalLoop(unsigned long 4) line 3478 + 19 bytes
>> CDialog::DoModal() line 539 + 12 bytes
>> CSocketApp::InitInstance() line 65 + 11 bytes
>> AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char *
>> 0x00141f1e, int 1) line 39 + 11 bytes
>> SOCKET! 0040dec8() line 30
>> WinMainCRTStartup() line 330 + 54 bytes
>>
>>
>> "Geoff" <geoff(a)invalid.invalid> wrote in message
>> news:e6cep51nscc07242lblsa06lublh53030h(a)4ax.com...
>>> On Wed, 10 Mar 2010 10:42:21 +0800, "Bill" <<don't want more spam>>
>>> wrote:
>>>
>>>> Did I ask this in the right newsgroup? (Just not sure if there is a
>>>> more
>>>> appropriate palce to ask this.) Tnx.
>>>>
>>> Dr. Joe usually has a lot to say about callbacks and about
>>> CAsyncSocket but he must be busy polishing his new MVP award.
>>>
>>> I am not sure why you think you need to poll the handle. What you
>>> should be doing is either closing it with CAsyncSocket::Close when you
>>> are done with your session on your end or else responding to
>>> CAsyncSocket::OnClose and doing any cleanup if it is closed from the
>>> other end.
>>
>>
>
>
>
> --
> HLS


From: Joseph M. Newcomer on
You should do a shutdown() of the socket first (guarantees all pending buffers are
flushed).

What you are seeing here is the ASSERT that happens when the socket is not found in the
thread's local handle map, which can happen if you manage to delete the socket object when
there is still pending I/O. Hence the need for the shutdown() call. It kills all future
I/O and you can safely delete the socket object after closing it.
joe


On Thu, 11 Mar 2010 17:12:44 +0800, "Bill" <<don't want more spam>> wrote:

>Geoff,
>
>The code I showed was from MFC, not from me. So I'm not doing any polling. I
>pasted that in to show where the ASSERT is coming from.
>
>My code is deleting the socket object, which according to my comment will
>also close the connection.
>
> delete m_pClientSocket; // this will also close the connection
> m_pClientSocket = NULL;
>
>The help says "The socket object's destructor calls Close for you." so I
>guess that's why I think I only need to delete the object.
>
>I do respond to OnClose().
>
>I just put some breakpoints at OnClose(), OnConnect() and OnAccept().
>Neither is being hit when I try to connect to a non-existent IP and port,
>whether the ASSERT happens or not. The call stack looks like below, which
>only tells me it's not coming directly from a call in my code. It looks like
>the systems was preparing to do a callback.
>
>Oh, I see if I am patient, I will get a call to OnConnect() with an 10060
>(WSAETIMEDOUT) error about 20 seconds after initiating the conenct. I do
>have to handle that differently.
>
>I was thinking that maybe the timeout callback was coming in just as I was
>deleting the socket object. But it doesn't seem likely as I can get the
>ASSERT long before the 20 second timeout occurs. Any way I can determine
>what the callback would have been had it not crashed? wParam = 1764 and
>lParam = 657850384 or hex 27360010.
>
>Bill
>
>CAsyncSocket::DoCallBack(unsigned int 1764, long 657850384) line 513 + 25
>bytes
>CSocket::ProcessAuxQueue() line 823
>CSocketWnd::OnSocketNotify(unsigned int 1764, long 657850384) line 1127
>CWnd::OnWndMsg(unsigned int 883, unsigned int 1764, long 657850384, long *
>0x0012f560) line 1815 + 17 bytes
>CWnd::WindowProc(unsigned int 883, unsigned int 1764, long 657850384) line
>1585 + 30 bytes
>AfxCallWndProc(CWnd * 0x009f5798 {CSocketWnd hWnd=0x000110d6}, HWND__ *
>0x000110d6, unsigned int 883, unsigned int 1764, long 657850384) line 215 +
>26 bytes
>AfxWndProc(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764, long
>657850384) line 368
>AfxWndProcBase(HWND__ * 0x000110d6, unsigned int 883, unsigned int 1764,
>long 657850384) line 220 + 21 bytes
>USER32! 7e418734()
>USER32! 7e418816()
>USER32! 7e4189cd()
>USER32! 7e4196c7()
>CWinThread::PumpMessage() line 853
>CWnd::RunModalLoop(unsigned long 4) line 3478 + 19 bytes
>CDialog::DoModal() line 539 + 12 bytes
>CSocketApp::InitInstance() line 65 + 11 bytes
>AfxWinMain(HINSTANCE__ * 0x00400000, HINSTANCE__ * 0x00000000, char *
>0x00141f1e, int 1) line 39 + 11 bytes
>SOCKET! 0040dec8() line 30
>WinMainCRTStartup() line 330 + 54 bytes
>
>
>"Geoff" <geoff(a)invalid.invalid> wrote in message
>news:e6cep51nscc07242lblsa06lublh53030h(a)4ax.com...
>> On Wed, 10 Mar 2010 10:42:21 +0800, "Bill" <<don't want more spam>>
>> wrote:
>>
>>>Did I ask this in the right newsgroup? (Just not sure if there is a more
>>>appropriate palce to ask this.) Tnx.
>>>
>>
>> Dr. Joe usually has a lot to say about callbacks and about
>> CAsyncSocket but he must be busy polishing his new MVP award.
>>
>> I am not sure why you think you need to poll the handle. What you
>> should be doing is either closing it with CAsyncSocket::Close when you
>> are done with your session on your end or else responding to
>> CAsyncSocket::OnClose and doing any cleanup if it is closed from the
>> other end.
>
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm