mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 13:45:56 +00:00
[TCPIP]
- Add logging of address files and connections (on temporarily for testing changes) [LWIP] - Drastically simplify the closing state machine - All connection objects (and as a result address files too) are now getting properly reaped now - Tested with Firefox and Abyss Web Server svn path=/trunk/; revision=59705
This commit is contained in:
parent
4ed049cc7b
commit
578fec3cac
6 changed files with 166 additions and 48 deletions
|
@ -35,4 +35,6 @@ NTSTATUS FileOpenControlChannel(
|
||||||
NTSTATUS FileCloseControlChannel(
|
NTSTATUS FileCloseControlChannel(
|
||||||
PTDI_REQUEST Request);
|
PTDI_REQUEST Request);
|
||||||
|
|
||||||
|
VOID LogActiveObjects(VOID);
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -211,3 +211,6 @@ VOID
|
||||||
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status);
|
FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status);
|
||||||
|
|
||||||
VOID CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous);
|
VOID CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous);
|
||||||
|
|
||||||
|
void
|
||||||
|
LibTCPDumpPcb(PVOID SocketContext);
|
||||||
|
|
|
@ -281,6 +281,7 @@ typedef struct _CONNECTION_ENDPOINT {
|
||||||
BOOLEAN SendShutdown;
|
BOOLEAN SendShutdown;
|
||||||
BOOLEAN ReceiveShutdown;
|
BOOLEAN ReceiveShutdown;
|
||||||
NTSTATUS ReceiveShutdownStatus;
|
NTSTATUS ReceiveShutdownStatus;
|
||||||
|
BOOLEAN Closing;
|
||||||
|
|
||||||
struct _CONNECTION_ENDPOINT *Next; /* Next connection in address file list */
|
struct _CONNECTION_ENDPOINT *Next; /* Next connection in address file list */
|
||||||
} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
|
} CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include "precomp.h"
|
#include "precomp.h"
|
||||||
|
|
||||||
|
/* Uncomment for logging of connections and address files every 10 seconds */
|
||||||
|
#define LOG_OBJECTS
|
||||||
|
|
||||||
/* List of all address file objects managed by this driver */
|
/* List of all address file objects managed by this driver */
|
||||||
LIST_ENTRY AddressFileListHead;
|
LIST_ENTRY AddressFileListHead;
|
||||||
|
@ -99,6 +101,88 @@ BOOLEAN AddrReceiveMatch(
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
|
LogActiveObjects(VOID)
|
||||||
|
{
|
||||||
|
#ifdef LOG_OBJECTS
|
||||||
|
PLIST_ENTRY CurrentEntry;
|
||||||
|
KIRQL OldIrql;
|
||||||
|
PADDRESS_FILE AddrFile;
|
||||||
|
PCONNECTION_ENDPOINT Conn;
|
||||||
|
|
||||||
|
DbgPrint("----------- TCP/IP Active Object Dump -------------\n");
|
||||||
|
|
||||||
|
TcpipAcquireSpinLock(&AddressFileListLock, &OldIrql);
|
||||||
|
|
||||||
|
CurrentEntry = AddressFileListHead.Flink;
|
||||||
|
while (CurrentEntry != &AddressFileListHead)
|
||||||
|
{
|
||||||
|
AddrFile = CONTAINING_RECORD(CurrentEntry, ADDRESS_FILE, ListEntry);
|
||||||
|
|
||||||
|
DbgPrint("Address File (%s, %d, %d) @ 0x%p | Ref count: %d | Sharers: %d\n",
|
||||||
|
A2S(&AddrFile->Address), WN2H(AddrFile->Port), AddrFile->Protocol,
|
||||||
|
AddrFile, AddrFile->RefCount, AddrFile->Sharers);
|
||||||
|
DbgPrint("\tListener: ");
|
||||||
|
if (AddrFile->Listener == NULL)
|
||||||
|
DbgPrint("<None>\n");
|
||||||
|
else
|
||||||
|
DbgPrint("0x%p\n", AddrFile->Listener);
|
||||||
|
DbgPrint("\tAssociated endpoints: ");
|
||||||
|
if (AddrFile->Connection == NULL)
|
||||||
|
DbgPrint("<None>\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Conn = AddrFile->Connection;
|
||||||
|
while (Conn)
|
||||||
|
{
|
||||||
|
DbgPrint("0x%p ", Conn);
|
||||||
|
Conn = Conn->Next;
|
||||||
|
}
|
||||||
|
DbgPrint("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpipReleaseSpinLock(&AddressFileListLock, OldIrql);
|
||||||
|
|
||||||
|
TcpipAcquireSpinLock(&ConnectionEndpointListLock, &OldIrql);
|
||||||
|
|
||||||
|
CurrentEntry = ConnectionEndpointListHead.Flink;
|
||||||
|
while (CurrentEntry != &ConnectionEndpointListHead)
|
||||||
|
{
|
||||||
|
Conn = CONTAINING_RECORD(CurrentEntry, CONNECTION_ENDPOINT, ListEntry);
|
||||||
|
|
||||||
|
DbgPrint("Connection @ 0x%p | Ref count: %d\n", Conn, Conn->RefCount);
|
||||||
|
DbgPrint("\tPCB: ");
|
||||||
|
if (Conn->SocketContext == NULL)
|
||||||
|
DbgPrint("<None>\n");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DbgPrint("0x%p\n", Conn->SocketContext);
|
||||||
|
LibTCPDumpPcb(Conn->SocketContext);
|
||||||
|
}
|
||||||
|
DbgPrint("\tPacket queue status: %s\n", IsListEmpty(&Conn->PacketQueue) ? "Empty" : "Not Empty");
|
||||||
|
DbgPrint("\tRequest lists: Connect: %s | Recv: %s | Send: %s | Shutdown: %s | Listen: %s\n",
|
||||||
|
IsListEmpty(&Conn->ConnectRequest) ? "Empty" : "Not Empty",
|
||||||
|
IsListEmpty(&Conn->ReceiveRequest) ? "Empty" : "Not Empty",
|
||||||
|
IsListEmpty(&Conn->SendRequest) ? "Empty" : "Not Empty",
|
||||||
|
IsListEmpty(&Conn->ShutdownRequest) ? "Empty" : "Not Empty",
|
||||||
|
IsListEmpty(&Conn->ListenRequest) ? "Empty" : "Not Empty");
|
||||||
|
DbgPrint("\tSend shutdown: %s\n", Conn->SendShutdown ? "Yes" : "No");
|
||||||
|
DbgPrint("\tReceive shutdown: %s\n", Conn->ReceiveShutdown ? "Yes" : "No");
|
||||||
|
if (Conn->ReceiveShutdown) DbgPrint("\tReceive shutdown status: 0x%x\n", Conn->ReceiveShutdownStatus);
|
||||||
|
DbgPrint("\tClosing: %s\n", Conn->Closing ? "Yes" : "No");
|
||||||
|
|
||||||
|
CurrentEntry = CurrentEntry->Flink;
|
||||||
|
}
|
||||||
|
|
||||||
|
TcpipReleaseSpinLock(&ConnectionEndpointListLock, OldIrql);
|
||||||
|
|
||||||
|
DbgPrint("---------------------------------------------------\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
PADDRESS_FILE AddrFindShared(
|
PADDRESS_FILE AddrFindShared(
|
||||||
PIP_ADDRESS BindAddress,
|
PIP_ADDRESS BindAddress,
|
||||||
USHORT Port,
|
USHORT Port,
|
||||||
|
|
|
@ -24,6 +24,8 @@ BOOLEAN IpWorkItemQueued = FALSE;
|
||||||
|
|
||||||
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
|
IP_PROTOCOL_HANDLER ProtocolTable[IP_PROTOCOL_TABLE_SIZE];
|
||||||
|
|
||||||
|
ULONG IpTimerExpirations;
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
TCPRegisterInterface(PIP_INTERFACE IF);
|
TCPRegisterInterface(PIP_INTERFACE IF);
|
||||||
|
|
||||||
|
@ -119,9 +121,16 @@ VOID NTAPI IPTimeoutDpcFn(PKDPC Dpc,
|
||||||
* SystemArgument1 = Unused
|
* SystemArgument1 = Unused
|
||||||
* SystemArgument2 = Unused
|
* SystemArgument2 = Unused
|
||||||
* NOTES:
|
* NOTES:
|
||||||
* This routine is dispatched once in a while to do maintainance jobs
|
* This routine is dispatched once in a while to do maintenance jobs
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
IpTimerExpirations++;
|
||||||
|
|
||||||
|
if ((IpTimerExpirations % 10) == 0)
|
||||||
|
{
|
||||||
|
LogActiveObjects();
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if datagram fragments have taken too long to assemble */
|
/* Check if datagram fragments have taken too long to assemble */
|
||||||
IPDatagramReassemblyTimeout();
|
IPDatagramReassemblyTimeout();
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,21 @@ extern NPAGED_LOOKASIDE_LIST QueueEntryLookasideList;
|
||||||
/* Required for ERR_T to NTSTATUS translation in receive error handling */
|
/* Required for ERR_T to NTSTATUS translation in receive error handling */
|
||||||
NTSTATUS TCPTranslateError(const err_t err);
|
NTSTATUS TCPTranslateError(const err_t err);
|
||||||
|
|
||||||
|
void
|
||||||
|
LibTCPDumpPcb(PVOID SocketContext)
|
||||||
|
{
|
||||||
|
struct tcp_pcb *pcb = (struct tcp_pcb*)SocketContext;
|
||||||
|
unsigned int addr = ntohl(pcb->remote_ip.addr);
|
||||||
|
|
||||||
|
DbgPrint("\tState: %s\n", tcp_state_str[pcb->state]);
|
||||||
|
DbgPrint("\tRemote: (%d.%d.%d.%d, %d)\n",
|
||||||
|
(addr >> 24) & 0xFF,
|
||||||
|
(addr >> 16) & 0xFF,
|
||||||
|
(addr >> 8) & 0xFF,
|
||||||
|
addr & 0xFF,
|
||||||
|
pcb->remote_port);
|
||||||
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
LibTCPEmptyQueue(PCONNECTION_ENDPOINT Connection)
|
LibTCPEmptyQueue(PCONNECTION_ENDPOINT Connection)
|
||||||
|
@ -231,19 +246,16 @@ InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t er
|
||||||
Connection->ReceiveShutdown = TRUE;
|
Connection->ReceiveShutdown = TRUE;
|
||||||
Connection->ReceiveShutdownStatus = STATUS_SUCCESS;
|
Connection->ReceiveShutdownStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
/* This code path executes for both remotely and locally initiated closures,
|
/* If we already did a send shutdown, we're in TIME_WAIT so we can't use this PCB anymore */
|
||||||
* and we need to distinguish between them */
|
if (Connection->SendShutdown)
|
||||||
if (Connection->SocketContext)
|
|
||||||
{
|
{
|
||||||
|
Connection->SocketContext = NULL;
|
||||||
|
tcp_arg(pcb, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Remotely initiated close */
|
/* Remotely initiated close */
|
||||||
TCPRecvEventHandler(arg);
|
TCPRecvEventHandler(arg);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Locally initated close */
|
|
||||||
TCPFinEventHandler(arg, ERR_CLSD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
@ -285,30 +297,18 @@ void
|
||||||
InternalErrorEventHandler(void *arg, const err_t err)
|
InternalErrorEventHandler(void *arg, const err_t err)
|
||||||
{
|
{
|
||||||
PCONNECTION_ENDPOINT Connection = arg;
|
PCONNECTION_ENDPOINT Connection = arg;
|
||||||
KIRQL OldIrql;
|
|
||||||
|
|
||||||
/* Make sure the socket didn't get closed */
|
/* Make sure the socket didn't get closed */
|
||||||
if (!arg) return;
|
if (!arg) return;
|
||||||
|
|
||||||
/* Check if data is left to be read */
|
/* The PCB is dead now */
|
||||||
LockObject(Connection, &OldIrql);
|
Connection->SocketContext = NULL;
|
||||||
if (IsListEmpty(&Connection->PacketQueue))
|
|
||||||
{
|
|
||||||
UnlockObject(Connection, OldIrql);
|
|
||||||
|
|
||||||
/* Deliver the error now */
|
|
||||||
TCPFinEventHandler(arg, err);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UnlockObject(Connection, OldIrql);
|
|
||||||
|
|
||||||
/* Defer the error delivery until all data is gone */
|
/* Defer the error delivery until all data is gone */
|
||||||
Connection->ReceiveShutdown = TRUE;
|
Connection->ReceiveShutdown = TRUE;
|
||||||
Connection->ReceiveShutdownStatus = TCPTranslateError(err);
|
Connection->ReceiveShutdownStatus = TCPTranslateError(err);
|
||||||
|
|
||||||
TCPRecvEventHandler(arg);
|
TCPRecvEventHandler(arg);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -633,7 +633,12 @@ LibTCPShutdownCallback(void *arg)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These need to be called separately, otherwise we get a tcp_close() */
|
/* LwIP makes the (questionable) assumption that SHUTDOWN_RDWR is equivalent to tcp_close().
|
||||||
|
* This assumption holds even if the shutdown calls are done separately (even through multiple
|
||||||
|
* WinSock shutdown() calls). This assumption means that lwIP has the right to deallocate our
|
||||||
|
* PCB without telling us if we shutdown TX and RX. To avoid these problems, we'll clear the
|
||||||
|
* socket context if we have called shutdown for TX and RX.
|
||||||
|
*/
|
||||||
if (msg->Input.Shutdown.shut_rx) {
|
if (msg->Input.Shutdown.shut_rx) {
|
||||||
msg->Output.Shutdown.Error = tcp_shutdown(pcb, TRUE, FALSE);
|
msg->Output.Shutdown.Error = tcp_shutdown(pcb, TRUE, FALSE);
|
||||||
}
|
}
|
||||||
|
@ -651,6 +656,14 @@ LibTCPShutdownCallback(void *arg)
|
||||||
|
|
||||||
if (msg->Input.Shutdown.shut_tx)
|
if (msg->Input.Shutdown.shut_tx)
|
||||||
msg->Input.Shutdown.Connection->SendShutdown = TRUE;
|
msg->Input.Shutdown.Connection->SendShutdown = TRUE;
|
||||||
|
|
||||||
|
if (msg->Input.Shutdown.Connection->ReceiveShutdown &&
|
||||||
|
msg->Input.Shutdown.Connection->SendShutdown)
|
||||||
|
{
|
||||||
|
/* The PCB is not ours anymore */
|
||||||
|
msg->Input.Shutdown.Connection->SocketContext = NULL;
|
||||||
|
tcp_arg(pcb, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -697,37 +710,43 @@ LibTCPCloseCallback(void *arg)
|
||||||
/* Empty the queue even if we're already "closed" */
|
/* Empty the queue even if we're already "closed" */
|
||||||
LibTCPEmptyQueue(msg->Input.Close.Connection);
|
LibTCPEmptyQueue(msg->Input.Close.Connection);
|
||||||
|
|
||||||
if (!msg->Input.Close.Connection->SocketContext)
|
/* Check if we've already been closed */
|
||||||
|
if (msg->Input.Close.Connection->Closing)
|
||||||
{
|
{
|
||||||
msg->Output.Close.Error = ERR_OK;
|
msg->Output.Close.Error = ERR_OK;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the PCB pointer */
|
/* Enter "closing" mode if we're doing a normal close */
|
||||||
msg->Input.Close.Connection->SocketContext = NULL;
|
if (msg->Input.Close.Callback)
|
||||||
|
msg->Input.Close.Connection->Closing = TRUE;
|
||||||
|
|
||||||
switch (pcb->state)
|
/* Check if the PCB was already "closed" but the client doesn't know it yet */
|
||||||
|
if (!msg->Input.Close.Connection->SocketContext)
|
||||||
{
|
{
|
||||||
case CLOSED:
|
if (msg->Input.Close.Callback)
|
||||||
case LISTEN:
|
|
||||||
case SYN_SENT:
|
|
||||||
msg->Output.Close.Error = tcp_close(pcb);
|
|
||||||
|
|
||||||
if (!msg->Output.Close.Error && msg->Input.Close.Callback)
|
|
||||||
TCPFinEventHandler(msg->Input.Close.Connection, ERR_CLSD);
|
TCPFinEventHandler(msg->Input.Close.Connection, ERR_CLSD);
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Abort the socket */
|
|
||||||
tcp_abort(pcb);
|
|
||||||
msg->Output.Close.Error = ERR_OK;
|
msg->Output.Close.Error = ERR_OK;
|
||||||
break;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear the PCB pointer and stop callbacks */
|
||||||
|
msg->Input.Close.Connection->SocketContext = NULL;
|
||||||
|
tcp_arg(pcb, NULL);
|
||||||
|
|
||||||
|
/* This may generate additional callbacks but we don't care,
|
||||||
|
* because they're too inconsistent to rely on */
|
||||||
|
msg->Output.Close.Error = tcp_close(pcb);
|
||||||
|
|
||||||
if (msg->Output.Close.Error)
|
if (msg->Output.Close.Error)
|
||||||
{
|
{
|
||||||
/* Restore the PCB pointer */
|
/* Restore the PCB pointer */
|
||||||
msg->Input.Close.Connection->SocketContext = pcb;
|
msg->Input.Close.Connection->SocketContext = pcb;
|
||||||
|
msg->Input.Close.Connection->Closing = FALSE;
|
||||||
|
}
|
||||||
|
else if (msg->Input.Close.Callback)
|
||||||
|
{
|
||||||
|
TCPFinEventHandler(msg->Input.Close.Connection, ERR_CLSD);
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue