mirror of
https://github.com/reactos/reactos.git
synced 2024-05-31 17:51:49 +00:00
e7cfa907e9
The interesting kernel32 part is a port of 0.4.15-dev-2069-gfd8080b094
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-g27fcfe66a2
(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-g979b7d4d8e
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-g4aeb45ce0c
(#3170)
442 lines
11 KiB
C
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);
|
|
}
|