- Hold on to the disconnect IRP until all pending sending IRPs are sent to the transport driver if a controlled disconnect was requested (merge of r52415)
[TCPIP]
- add some mroe debug statements to track new current sync problem
- remove some old debug statements that are useless now
[lwIP]
- add some mroe debug statements to track new current sync problem

svn path=/branches/GSoC_2011/TcpIpDriver/; revision=52424
This commit is contained in:
Claudiu Mihail 2011-06-22 15:32:46 +00:00
parent 7ba87c3d72
commit 474c5138f8
9 changed files with 174 additions and 83 deletions

View file

@ -208,7 +208,7 @@ AfdSetConnectDataSize(PDEVICE_OBJECT DeviceObject, PIRP Irp,
}
NTSTATUS WarmSocketForConnection( PAFD_FCB FCB )
NTSTATUS WarmSocketForConnection(PAFD_FCB FCB)
{
NTSTATUS Status;
@ -240,18 +240,21 @@ NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB )
Status = TdiQueryMaxDatagramLength(FCB->Connection.Object,
&FCB->Send.Size);
DbgPrint("[AFD, MakeSocketIntoConnection] Called\n");
if (!NT_SUCCESS(Status))
return Status;
FCB->Recv.Size = FCB->Send.Size;
/* Allocate the receive area and start receiving */
FCB->Recv.Window = ExAllocatePool(PagedPool, FCB->Recv.Size);
FCB->Recv.Window = (PCHAR)ExAllocatePool(PagedPool, FCB->Recv.Size);
if (!FCB->Recv.Window)
return STATUS_NO_MEMORY;
FCB->Send.Window = ExAllocatePool(PagedPool, FCB->Send.Size);
FCB->Send.Window = (PCHAR)ExAllocatePool(PagedPool, FCB->Send.Size);
if (!FCB->Send.Window)
{
@ -279,6 +282,8 @@ NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB )
FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
PollReeval( FCB->DeviceExt, FCB->FileObject );
DbgPrint("[AFD, MakeSocketIntoConnection] Leaving\n");
return Status;
}
@ -528,7 +533,7 @@ AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
DbgPrint("[AFD, AfdStreamSocketConnect] Queueing IRP %x\n", Irp);
if( Status == STATUS_PENDING )
if (Status == STATUS_PENDING)
{
FCB->State = SOCKET_STATE_CONNECTING;
return LeaveIrpUntilLater(FCB, Irp, FUNCTION_CONNECT);

View file

@ -48,7 +48,8 @@ AfdGetDisconnectOptions(PDEVICE_OBJECT DeviceObject, PIRP Irp,
ASSERT(FCB->DisconnectOptions);
if (FCB->FilledDisconnectOptions < BufferSize) BufferSize = FCB->FilledDisconnectOptions;
if (FCB->FilledDisconnectOptions < BufferSize)
BufferSize = FCB->FilledDisconnectOptions;
RtlCopyMemory(Irp->UserBuffer,
FCB->DisconnectOptions,
@ -595,56 +596,42 @@ AfdCloseSocket(PDEVICE_OBJECT DeviceObject, PIRP Irp,
static
NTSTATUS
NTAPI
AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
DoDisconnect(PAFD_FCB FCB, PIRP CurrentIrp)
{
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAFD_FCB FCB = (PAFD_FCB)FileObject->FsContext;
PAFD_DISCONNECT_INFO DisReq;
IO_STATUS_BLOCK Iosb;
PTDI_CONNECTION_INFORMATION ConnectionReturnInfo;
NTSTATUS Status = STATUS_SUCCESS;
PIO_STACK_LOCATION CurrentIrpSp;
USHORT Flags = 0;
if (!SocketAcquireStateLock(FCB))
return LostSocket(Irp);
if (!(DisReq = LockRequest(Irp, IrpSp)))
return UnlockAndMaybeComplete(FCB, STATUS_NO_MEMORY, Irp, 0);
NTSTATUS Status;
if ( DisReq->DisconnectType & AFD_DISCONNECT_SEND)
CurrentIrpSp = IoGetCurrentIrpStackLocation(CurrentIrp);
DisReq = GetLockedData(CurrentIrp, CurrentIrpSp);
if (DisReq->DisconnectType & AFD_DISCONNECT_SEND)
Flags |= TDI_DISCONNECT_RELEASE;
if ( DisReq->DisconnectType & AFD_DISCONNECT_RECV ||
if (DisReq->DisconnectType & AFD_DISCONNECT_RECV ||
DisReq->DisconnectType & AFD_DISCONNECT_ABORT)
Flags |= TDI_DISCONNECT_ABORT;
if (!(FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS))
Status = TdiBuildNullConnectionInfo(&ConnectionReturnInfo,
FCB->RemoteAddress->Address[0].AddressType);
if (NT_SUCCESS(Status))
{
if (!FCB->ConnectInfo)
return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
ASSERT(FCB->RemoteAddress);
Status = TdiBuildNullConnectionInfo
( &ConnectionReturnInfo, FCB->RemoteAddress->Address[0].AddressType );
if (!NT_SUCCESS(Status))
return UnlockAndMaybeComplete(FCB, Status, Irp, 0);
FCB->ConnectInfo->UserData = FCB->DisconnectData;
FCB->ConnectInfo->UserDataLength = FCB->DisconnectDataSize;
FCB->ConnectInfo->Options = FCB->DisconnectOptions;
FCB->ConnectInfo->OptionsLength = FCB->DisconnectOptionsSize;
Status = TdiDisconnect( FCB->Connection.Object,
&DisReq->Timeout,
Flags,
&Iosb,
NULL,
NULL,
FCB->ConnectInfo,
ConnectionReturnInfo);
Status = TdiDisconnect(FCB->Connection.Object,
&DisReq->Timeout,
Flags,
&Iosb,
NULL,
NULL,
FCB->ConnectInfo,
ConnectionReturnInfo);
if (NT_SUCCESS(Status))
{
FCB->FilledDisconnectData = MIN(FCB->DisconnectDataSize, ConnectionReturnInfo->UserDataLength);
@ -654,7 +641,7 @@ AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
ConnectionReturnInfo->UserData,
FCB->FilledDisconnectData);
}
FCB->FilledDisconnectOptions = MIN(FCB->DisconnectOptionsSize, ConnectionReturnInfo->OptionsLength);
if (FCB->FilledDisconnectOptions)
{
@ -663,15 +650,92 @@ AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
FCB->FilledDisconnectOptions);
}
}
ExFreePool( ConnectionReturnInfo );
ExFreePool(ConnectionReturnInfo);
if (Flags & TDI_DISCONNECT_RELEASE)
FCB->PollState |= AFD_EVENT_DISCONNECT;
else
FCB->PollState |= AFD_EVENT_ABORT;
FCB->PollStatus[FD_CLOSE_BIT] = STATUS_SUCCESS;
PollReeval( FCB->DeviceExt, FCB->FileObject );
FCB->PollStatus[FD_CLOSE_BIT] = Status;
PollReeval(FCB->DeviceExt, FCB->FileObject);
}
CurrentIrp->IoStatus.Status = Status;
CurrentIrp->IoStatus.Information = 0;
UnlockRequest(CurrentIrp, CurrentIrpSp);
(void)IoSetCancelRoutine(CurrentIrp, NULL);
IoCompleteRequest(CurrentIrp, IO_NETWORK_INCREMENT);
return Status;
}
VOID
RetryDisconnectCompletion(PAFD_FCB FCB)
{
if (IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]))
{
PIRP CurrentIrp;
PLIST_ENTRY CurrentEntry;
ASSERT(FCB->RemoteAddress);
while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_DISCONNECT]))
{
CurrentEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_DISCONNECT]);
CurrentIrp = CONTAINING_RECORD(CurrentEntry, IRP, Tail.Overlay.ListEntry);
DoDisconnect(FCB, CurrentIrp);
}
}
}
static
NTSTATUS
NTAPI
AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp)
{
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAFD_FCB FCB = (PAFD_FCB)FileObject->FsContext;
PAFD_DISCONNECT_INFO DisReq;
NTSTATUS Status = STATUS_SUCCESS;
USHORT Flags = 0;
if (!SocketAcquireStateLock(FCB))
return LostSocket(Irp);
if (!(DisReq = LockRequest(Irp, IrpSp)))
return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp, 0);
if (DisReq->DisconnectType & AFD_DISCONNECT_SEND)
Flags |= TDI_DISCONNECT_RELEASE;
if (DisReq->DisconnectType & AFD_DISCONNECT_RECV ||
DisReq->DisconnectType & AFD_DISCONNECT_ABORT)
Flags |= TDI_DISCONNECT_ABORT;
if (!(FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS))
{
if (!FCB->ConnectInfo)
return UnlockAndMaybeComplete(FCB, STATUS_INVALID_PARAMETER, Irp, 0);
if (IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) || (Flags & TDI_DISCONNECT_ABORT))
{
/* Go ahead an execute the disconnect because we're ready for it */
Status = DoDisconnect(FCB, Irp);
/* DoDisconnect takes care of the IRP */
SocketStateUnlock(FCB);
return Status;
}
else
{
/* We have a graceful disconnect waiting on pending sends to complete */
return LeaveIrpUntilLater(FCB, Irp, FUNCTION_DISCONNECT);
}
}
else
{

View file

@ -42,8 +42,7 @@ static BOOLEAN CantReadMore( PAFD_FCB FCB )
{
UINT BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
return !BytesAvailable &&
(FCB->PollState & (AFD_EVENT_CLOSE | AFD_EVENT_ABORT));
return !BytesAvailable && (FCB->PollState & (AFD_EVENT_CLOSE | AFD_EVENT_ABORT));
}
static VOID RefillSocketBuffer( PAFD_FCB FCB )
@ -78,8 +77,7 @@ TryToSatisfyRecvRequestFromBuffer
PUINT TotalBytesCopied )
{
UINT i, BytesToCopy = 0, FcbBytesCopied = FCB->Recv.BytesUsed,
BytesAvailable =
FCB->Recv.Content - FCB->Recv.BytesUsed;
BytesAvailable = FCB->Recv.Content - FCB->Recv.BytesUsed;
PAFD_MAPBUF Map;
*TotalBytesCopied = 0;
@ -174,8 +172,9 @@ ReceiveActivity(PAFD_FCB FCB, PIRP Irp)
TotalBytesCopied));
UnlockBuffers(RecvReq->BufferArray, RecvReq->BufferCount, FALSE);
Status = NextIrp->IoStatus.Status =
FCB->Overread ? STATUS_END_OF_FILE : STATUS_SUCCESS;
//Status = NextIrp->IoStatus.Status =
// FCB->Overread ? STATUS_END_OF_FILE : STATUS_SUCCESS;
Status = NextIrp->IoStatus.Status = FCB->PollStatus[FD_CLOSE_BIT];
NextIrp->IoStatus.Information = 0;
if (NextIrp == Irp)
@ -185,7 +184,7 @@ ReceiveActivity(PAFD_FCB FCB, PIRP Irp)
(void)IoSetCancelRoutine(NextIrp, NULL);
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
FCB->Overread = TRUE;
//FCB->Overread = TRUE;
}
}
else
@ -239,8 +238,8 @@ ReceiveActivity(PAFD_FCB FCB, PIRP Irp)
}
}
if( FCB->Recv.Content - FCB->Recv.BytesUsed &&
IsListEmpty(&FCB->PendingIrpList[FUNCTION_RECV]) )
if (FCB->Recv.Content - FCB->Recv.BytesUsed &&
IsListEmpty(&FCB->PendingIrpList[FUNCTION_RECV]))
{
FCB->PollState |= AFD_EVENT_RECEIVE;
FCB->PollStatus[FD_READ_BIT] = STATUS_SUCCESS;

View file

@ -68,6 +68,8 @@ SendComplete
(void)IoSetCancelRoutine(NextIrp, NULL);
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
}
RetryDisconnectCompletion(FCB);
SocketStateUnlock(FCB);
return STATUS_FILE_CLOSED;
@ -98,6 +100,8 @@ SendComplete
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
}
RetryDisconnectCompletion(FCB);
SocketStateUnlock( FCB );
return STATUS_SUCCESS;
@ -177,6 +181,8 @@ SendComplete
&FCB->SendIrp.Iosb,
SendComplete,
FCB );
RetryDisconnectCompletion(FCB);
}
else
{
@ -433,6 +439,8 @@ AfdConnectedSocketWriteData
AFD_DbgPrint(MID_TRACE,("Dismissing request: %x (%d)\n",
Status, TotalBytesCopied));
}
RetryDisconnectCompletion(FCB);
return UnlockAndMaybeComplete(FCB, Status, Irp, TotalBytesCopied);
}

View file

@ -99,8 +99,9 @@ typedef struct IPADDR_ENTRY {
#define FUNCTION_SEND 2
#define FUNCTION_PREACCEPT 3
#define FUNCTION_ACCEPT 4
#define FUNCTION_CLOSE 5
#define MAX_FUNCTIONS 6
#define FUNCTION_DISCONNECT 5
#define FUNCTION_CLOSE 6
#define MAX_FUNCTIONS 7
#define IN_FLIGHT_REQUESTS 4
@ -304,11 +305,11 @@ PVOID GetLockedData( PIRP Irp, PIO_STACK_LOCATION IrpSp );
/* main.c */
VOID OskitDumpBuffer( PCHAR Buffer, UINT Len );
NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function );
VOID DestroySocket( PAFD_FCB FCB );
VOID NTAPI AfdCancelHandler(PDEVICE_OBJECT DeviceObject,
PIRP Irp);
VOID RetryDisconnectCompletion(PAFD_FCB FCB);
/* read.c */

View file

@ -384,8 +384,7 @@ NTSTATUS FileOpenAddress(
* RETURNS:
* Status of operation
*/
NTSTATUS FileCloseAddress(
PTDI_REQUEST Request)
NTSTATUS FileCloseAddress(PTDI_REQUEST Request)
{
PADDRESS_FILE AddrFile = Request->Handle.AddressHandle;
KIRQL OldIrql;
@ -397,8 +396,6 @@ NTSTATUS FileCloseAddress(
LockObject(AddrFile, &OldIrql);
DbgPrint("[TCPIP, FileCloseAddress] AddrFile->RefCount = %d before TCPClose\n", AddrFile->RefCount);
/* We have to close this listener because we started it */
if ( AddrFile->Listener )
{
@ -412,8 +409,6 @@ NTSTATUS FileCloseAddress(
DereferenceObject(AddrFile);
DbgPrint("[TCPIP, FileCloseAddress] AddrFile->RefCount = %d after TCPClose\n", AddrFile->RefCount);
TI_DbgPrint(MAX_TRACE, ("Leaving.\n"));
DbgPrint("[TCPIP, FileCloseAddress] Leaving\n");

View file

@ -15,7 +15,7 @@
NTSTATUS TCPCheckPeerForAccept(PVOID Context,
PTDI_REQUEST_KERNEL Request)
{
struct tcp_pcb *newpcb = Context;
struct tcp_pcb *newpcb = (struct tcp_pcb*)Context;
NTSTATUS Status;
PTDI_CONNECTION_INFORMATION WhoIsConnecting;
PTA_IP_ADDRESS RemoteAddress;
@ -46,7 +46,7 @@ NTSTATUS TCPCheckPeerForAccept(PVOID Context,
/* This listen is on a socket we keep as internal. That socket has the same
* lifetime as the address file */
NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog )
NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
{
NTSTATUS Status = STATUS_SUCCESS;
struct ip_addr AddressToBind;
@ -84,8 +84,9 @@ NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog )
return Status;
}
BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection )
BOOLEAN TCPAbortListenForSocket
( PCONNECTION_ENDPOINT Listener,
PCONNECTION_ENDPOINT Connection)
{
PLIST_ENTRY ListEntry;
PTDI_BUCKET Bucket;
@ -97,7 +98,7 @@ BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
LockObject(Listener, &OldIrql);
ListEntry = Listener->ListenRequest.Flink;
while ( ListEntry != &Listener->ListenRequest )
while (ListEntry != &Listener->ListenRequest)
{
Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
@ -135,10 +136,11 @@ NTSTATUS TCPAccept ( PTDI_REQUEST Request,
LockObject(Listener, &OldIrql);
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
TDI_BUCKET_TAG );
Bucket = (PTDI_BUCKET)ExAllocatePoolWithTag(NonPagedPool,
sizeof(*Bucket),
TDI_BUCKET_TAG );
if( Bucket )
if (Bucket)
{
Bucket->AssociatedEndpoint = Connection;
ReferenceObject(Bucket->AssociatedEndpoint);

View file

@ -34,10 +34,10 @@ static
VOID
BucketCompletionWorker(PVOID Context)
{
PTDI_BUCKET Bucket = Context;
PTDI_BUCKET Bucket = (PTDI_BUCKET)Context;
PTCP_COMPLETION_ROUTINE Complete;
Complete = Bucket->Request.RequestNotifyObject;
Complete = (PTCP_COMPLETION_ROUTINE)Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
@ -203,7 +203,7 @@ TCPAcceptEventHandler(void *arg, struct tcp_pcb *newpcb)
DbgPrint("[IP, TCPAcceptEventHandler] Trying to unlock Bucket->AssociatedEndpoint\n");
UnlockObject(Bucket->AssociatedEndpoint, OldIrql);
/* sanity assert...this should never be in a LISTEN state */
/* sanity assert...this should never be in anything else but a CLOSED state */
ASSERT(((struct tcp_pcb*)OldSocketContext)->state == CLOSED);
/* free socket context created in FileOpenConnection, as we're using a new
one; we free it asynchornously because otherwise we create a dedlock */
@ -251,6 +251,8 @@ TCPSendEventHandler(void *arg, u16_t space)
TI_DbgPrint(DEBUG_TCP,
("Writing %d bytes to %x\n", SendLen, SendBuffer));
DbgPrint("[IP, TCPSendEventHandler] Sending out &d bytes on pcb = 0x%x\n",
Connection->SocketContext);
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
@ -325,10 +327,7 @@ TCPRecvEventHandler(void *arg, struct pbuf *p)
("[IP, TCPRecvEventHandler] Reading %d bytes to %x\n", RecvLen, RecvBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("[IP, TCPRecvEventHandler] Connection->SocketContext: %x\n",
Connection->SocketContext));
TI_DbgPrint(DEBUG_TCP, ("[IP, TCPRecvEventHandler] Connection->SocketContext: %x\n", Connection->SocketContext));
TI_DbgPrint(DEBUG_TCP, ("[IP, TCPRecvEventHandler] RecvBuffer: %x\n", RecvBuffer));
RecvLen = MIN(p->tot_len, RecvLen);

View file

@ -65,6 +65,8 @@ InternalSendEventHandler(void *arg, struct tcp_pcb *pcb, u16_t space)
if (!arg) return ERR_OK;
TCPSendEventHandler(arg, space);
DbgPrint("[lwIP, InternalSendEventHandler] Done\n");
return ERR_OK;
}
@ -75,13 +77,17 @@ InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t e
{
u32_t len;
DbgPrint("[lwIP, InternalRecvEventHandler] RecvEvent (0x%x, 0x%x, 0x%x, %d)\n",
DbgPrint("[lwIP, InternalRecvEventHandler] RecvEvent (0x%x, pcb = 0x%x, pbuf = 0x%x, err = %d)\n",
arg, pcb, p, (unsigned int)err);
/* Make sure the socket didn't get closed */
if (!arg)
{
if (p) pbuf_free(p);
if (p)
pbuf_free(p);
DbgPrint("[lwIP, InternalRecvEventHandler] Done ERR_OK 0 - socket got closed on us\n");
return ERR_OK;
}
@ -97,6 +103,8 @@ InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t e
pbuf_free(p);
DbgPrint("[lwIP, InternalRecvEventHandler] Done ERR_OK 1\n");
return ERR_OK;
}
else if (len != 0)
@ -106,12 +114,14 @@ InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t e
tcp_recved(pcb, len);
/* Possible memory leak of pbuf here? */
DbgPrint("[lwIP, InternalRecvEventHandler] Done ERR_OK 2\n");
return ERR_OK;
}
else
{
/* We want lwIP to store the pbuf on its queue for later */
DbgPrint("[lwIP, InternalRecvEventHandler] Done ERR_TIMEOUT\n");
return ERR_TIMEOUT;
}
}
@ -120,6 +130,8 @@ InternalRecvEventHandler(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t e
TCPFinEventHandler(arg, ERR_OK);
tcp_close(pcb);
}
DbgPrint("[lwIP, InternalRecvEventHandler] Done ERR_OK 3\n");
return ERR_OK;
}
@ -151,7 +163,7 @@ static
err_t
InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err)
{
DbgPrint("[lwIP, InternalConnectEventHandler] ConnectEvent(0x%x, 0x%x, %d)\n",
DbgPrint("[lwIP, InternalConnectEventHandler] ConnectEvent (0x%x, pcb = 0x%x, err = %d)\n",
arg, pcb, (unsigned int)err);
/* Make sure the socket didn't get closed */
@ -159,6 +171,8 @@ InternalConnectEventHandler(void *arg, struct tcp_pcb *pcb, err_t err)
return ERR_OK;
TCPConnectEventHandler(arg, err);
DbgPrint("[lwIP, InternalConnectEventHandler] Done\n");
return ERR_OK;
}
@ -511,7 +525,11 @@ LibTCPConnect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
tcpip_callback_with_block(LibTCPConnectCallback, msg, 1);
if (WaitForEventSafely(&msg->Event))
{
ret = msg->Error;
if (pcb->state != CLOSED && ret == ERR_INPROGRESS)
ret = ERR_OK;
}
else
ret = ERR_CLSD;