reactos/sdk/lib/drivers/ip/transport/tcp/event.c
Joachim Henze e7cfa907e9 [0.4.14][KERNEL32][TCPIP] A big squashed fix for CORE-16757 CORE-17596 CORE-17647 CORE-6473 (#3170)
The interesting kernel32 part is a port of
0.4.15-dev-2069-g fd8080b094
CORE-16757 'Task Manager failed to show process's priority'
which I actually wanted to improve for 0.4.14.

But if we took that on its own, then it would unhide
CORE-17596 'Google Earth 7.1.8 regressed AGAIN by the same work'
That's why we take with us:
0.4.15-dev-2766-g 27fcfe66a2 (is also part of CORE-6473, I left the 2nd commit out that added an assert in NTOSKRNL)

Small hack: this backport required me to define _Unreferenced_parameter_ myself in tcp.c
stolen from newer sdk/include/psdk/specstrings.h. I didn't want to port back that entire file as well.

In combination those two fixes allow both 'Google Earth and to change process priority' to be fixed within the same build.

But I felt a bit more safe then by taking
0.4.15-dev-2793-g 979b7d4d8e
with me as well, because I was too afraid, that I might otherwise introduce
CORE-17647 'BSOD 0xc2 BAD_POOL_CALLER induced by networking, triggered by using KeePass 2.23'
although I could not trigger that in practice when leaving that third commit out as an experiment.

And since it was a safe no-brainer-fix, I couldn't resist to also pick
0.4.15-dev-764-g 4aeb45ce0c (#3170)
2021-11-20 05:09:54 +01:00

442 lines
11 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS TCP/IP protocol driver
* FILE: transport/tcp/event.c
* PURPOSE: Transmission Control Protocol
* PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
*/
#include "precomp.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "lwip/pbuf.h"
#include "lwip/tcp.h"
#include "lwip/api.h"
#include "rosip.h"
extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList;
static
VOID
BucketCompletionWorker(PVOID Context)
{
PTDI_BUCKET Bucket = (PTDI_BUCKET)Context;
PTCP_COMPLETION_ROUTINE Complete;
Complete = (PTCP_COMPLETION_ROUTINE)Bucket->Request.RequestNotifyObject;
Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
DereferenceObject(Bucket->AssociatedEndpoint);
ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
}
VOID
CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous)
{
ReferenceObject(Connection);
Bucket->AssociatedEndpoint = Connection;
if (Synchronous)
{
BucketCompletionWorker(Bucket);
}
else
{
ChewCreate(BucketCompletionWorker, Bucket);
}
}
VOID
FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while (!IsListEmpty(&Connection->ReceiveRequest))
{
Entry = RemoveHeadList(&Connection->ReceiveRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
VOID
FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while (!IsListEmpty(&Connection->SendRequest))
{
Entry = RemoveHeadList(&Connection->SendRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
VOID
FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while (!IsListEmpty(&Connection->ShutdownRequest))
{
Entry = RemoveHeadList(&Connection->ShutdownRequest);
Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry);
Bucket->Information = 0;
Bucket->Status = Status;
CompleteBucket(Connection, Bucket, FALSE);
}
}
VOID
FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while (!IsListEmpty(&Connection->ConnectRequest))
{
Entry = RemoveHeadList(&Connection->ConnectRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
}
VOID
FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
{
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
ASSERT_TCPIP_OBJECT_LOCKED(Connection);
while (!IsListEmpty(&Connection->ListenRequest))
{
Entry = RemoveHeadList(&Connection->ListenRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = Status;
Bucket->Information = 0;
DereferenceObject(Bucket->AssociatedEndpoint);
CompleteBucket(Connection, Bucket, FALSE);
}
}
VOID
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
{
// flush receive queue
FlushReceiveQueue(Connection, Status);
/* We completed the reads successfully but we need to return failure now */
if (Status == STATUS_SUCCESS)
{
Status = STATUS_FILE_CLOSED;
}
// flush listen queue
FlushListenQueue(Connection, Status);
// flush send queue
FlushSendQueue(Connection, Status);
// flush connect queue
FlushConnectQueue(Connection, Status);
// flush shutdown queue
FlushShutdownQueue(Connection, Status);
}
VOID
TCPFinEventHandler(void *arg, const err_t err)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection;
const NTSTATUS Status = TCPTranslateError(err);
ASSERT(Connection->SocketContext == NULL);
ASSERT(Connection->AddressFile);
ASSERT(err != ERR_OK);
LockObject(Connection);
/* Complete all outstanding requests now */
FlushAllQueues(Connection, Status);
LockObject(Connection->AddressFile);
/* Unlink this connection from the address file */
if (Connection->AddressFile->Connection == Connection)
{
Connection->AddressFile->Connection = Connection->Next;
DereferenceObject(Connection);
}
else if (Connection->AddressFile->Listener == Connection)
{
Connection->AddressFile->Listener = NULL;
DereferenceObject(Connection);
}
else
{
LastConnection = Connection->AddressFile->Connection;
while (LastConnection->Next != Connection && LastConnection->Next != NULL)
LastConnection = LastConnection->Next;
if (LastConnection->Next == Connection)
{
LastConnection->Next = Connection->Next;
DereferenceObject(Connection);
}
}
UnlockObject(Connection->AddressFile);
/* Remove the address file from this connection */
DereferenceObject(Connection->AddressFile);
Connection->AddressFile = NULL;
UnlockObject(Connection);
}
VOID
TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
LockObject(Connection);
while (!IsListEmpty(&Connection->ListenRequest))
{
PIO_STACK_LOCATION IrpSp;
Entry = RemoveHeadList(&Connection->ListenRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
TI_DbgPrint(DEBUG_TCP,("[IP, TCPAcceptEventHandler] Getting the socket\n"));
Status = TCPCheckPeerForAccept(newpcb,
(PTDI_REQUEST_KERNEL)&IrpSp->Parameters);
TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n", Status));
Bucket->Status = Status;
Bucket->Information = 0;
if (Status == STATUS_SUCCESS)
{
LockObject(Bucket->AssociatedEndpoint);
/* sanity assert...this should never be in anything else but a CLOSED state */
ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED );
/* free socket context created in FileOpenConnection, as we're using a new one */
LibTCPClose(Bucket->AssociatedEndpoint, TRUE, FALSE);
/* free previously created socket context (we don't use it, we use newpcb) */
Bucket->AssociatedEndpoint->SocketContext = newpcb;
UnlockObject(Bucket->AssociatedEndpoint);
LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
}
DereferenceObject(Bucket->AssociatedEndpoint);
CompleteBucket(Connection, Bucket, FALSE);
if (Status == STATUS_SUCCESS)
{
break;
}
}
UnlockObject(Connection);
}
VOID
TCPSendEventHandler(void *arg, const u16_t space)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
NTSTATUS Status;
PMDL Mdl;
ULONG BytesSent;
ReferenceObject(Connection);
LockObject(Connection);
while (!IsListEmpty(&Connection->SendRequest))
{
UINT SendLen = 0;
PVOID SendBuffer = 0;
Entry = RemoveHeadList(&Connection->SendRequest);
UnlockObject(Connection);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
TI_DbgPrint(DEBUG_TCP,
("Getting the user buffer from %x\n", Mdl));
NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
TI_DbgPrint(DEBUG_TCP,
("Writing %d bytes to %x\n", SendLen, SendBuffer));
TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
TI_DbgPrint
(DEBUG_TCP,
("Connection->SocketContext: %x\n",
Connection->SocketContext));
Status = TCPTranslateError(LibTCPSend(Connection,
SendBuffer,
SendLen, &BytesSent, TRUE));
TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", BytesSent));
if( Status == STATUS_PENDING )
{
LockObject(Connection);
InsertHeadList(&Connection->SendRequest, &Bucket->Entry);
break;
}
else
{
TI_DbgPrint(DEBUG_TCP,
("Completing Send request: %x %x\n",
Bucket->Request, Status));
Bucket->Status = Status;
Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? BytesSent : 0;
CompleteBucket(Connection, Bucket, FALSE);
}
LockObject(Connection);
}
// If we completed all outstanding send requests then finish all pending shutdown requests,
// cancel the timer and dereference the connection
if (IsListEmpty(&Connection->SendRequest))
{
FlushShutdownQueue(Connection, STATUS_SUCCESS);
if (KeCancelTimer(&Connection->DisconnectTimer))
{
DereferenceObject(Connection);
}
}
UnlockObject(Connection);
DereferenceObject(Connection);
}
VOID
TCPRecvEventHandler(void *arg)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
PIRP Irp;
PMDL Mdl;
UINT Received;
UINT RecvLen;
PUCHAR RecvBuffer;
NTSTATUS Status;
LockObject(Connection);
while(!IsListEmpty(&Connection->ReceiveRequest))
{
Entry = RemoveHeadList(&Connection->ReceiveRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Irp = Bucket->Request.RequestContext;
Mdl = Irp->MdlAddress;
NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
Status = LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer, RecvLen, &Received);
if (Status == STATUS_PENDING)
{
InsertHeadList(&Connection->ReceiveRequest, &Bucket->Entry);
break;
}
Bucket->Status = Status;
Bucket->Information = Received;
CompleteBucket(Connection, Bucket, FALSE);
}
UnlockObject(Connection);
}
VOID
TCPConnectEventHandler(void *arg, const err_t err)
{
PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg;
PTDI_BUCKET Bucket;
PLIST_ENTRY Entry;
LockObject(Connection);
while (!IsListEmpty(&Connection->ConnectRequest))
{
Entry = RemoveHeadList(&Connection->ConnectRequest);
Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
Bucket->Status = TCPTranslateError(err);
Bucket->Information = 0;
CompleteBucket(Connection, Bucket, FALSE);
}
UnlockObject(Connection);
}