static void InternalErrorEventHandler(void *arg, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; KIRQL OldIrql; /* Make sure the socket didn't get closed */ if (!arg) return; /* Check if data is left to be read */ LockObject(Connection, &OldIrql); 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 */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = TCPTranslateError(err); TCPRecvEventHandler(arg); } }
NTSTATUS TCPSendData ( PCONNECTION_ENDPOINT Connection, PCHAR BufferData, ULONG SendLength, PULONG BytesSent, ULONG Flags, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; PTDI_BUCKET Bucket; KIRQL OldIrql; LockObject(Connection, &OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Called for %d bytes (on socket %x)\n", SendLength, Connection->SocketContext)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection = %x\n", Connection)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Connection->SocketContext = %x\n", Connection->SocketContext)); Status = TCPTranslateError(LibTCPSend(Connection, BufferData, SendLength, BytesSent, FALSE)); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Send: %x, %d\n", Status, SendLength)); /* Keep this request around ... there was no data yet */ if (Status == STATUS_PENDING) { /* Freed in TCPSocketState */ Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Failed to allocate bucket\n")); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->SendRequest, &Bucket->Entry ); TI_DbgPrint(DEBUG_TCP,("[IP, TCPSendData] Queued write irp\n")); } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP, ("[IP, TCPSendData] Leaving. Status = %x\n", Status)); return Status; }
NTSTATUS TCPGetSockAddress ( PCONNECTION_ENDPOINT Connection, PTRANSPORT_ADDRESS Address, BOOLEAN GetRemote ) { PTA_IP_ADDRESS AddressIP = (PTA_IP_ADDRESS)Address; struct ip_addr ipaddr; NTSTATUS Status; KIRQL OldIrql; AddressIP->TAAddressCount = 1; AddressIP->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP; AddressIP->Address[0].AddressType = TDI_ADDRESS_TYPE_IP; LockObject(Connection, &OldIrql); if (GetRemote) { Status = TCPTranslateError(LibTCPGetPeerName(Connection->SocketContext, &ipaddr, &AddressIP->Address[0].Address[0].sin_port)); } else { Status = TCPTranslateError(LibTCPGetHostName(Connection->SocketContext, &ipaddr, &AddressIP->Address[0].Address[0].sin_port)); } UnlockObject(Connection, OldIrql); AddressIP->Address[0].Address[0].in_addr = ipaddr.addr; RtlZeroMemory(&AddressIP->Address[0].Address[0].sin_zero, sizeof(AddressIP->Address[0].Address[0].sin_zero)); return Status; }
VOID NTAPI DisconnectTimeoutDpc(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) { PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)DeferredContext; PLIST_ENTRY Entry; PTDI_BUCKET Bucket; LockObjectAtDpcLevel(Connection); /* We timed out waiting for pending sends so force it to shutdown */ TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); while (!IsListEmpty(&Connection->SendRequest)) { Entry = RemoveHeadList(&Connection->SendRequest); Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); Bucket->Information = 0; Bucket->Status = STATUS_FILE_CLOSED; CompleteBucket(Connection, Bucket, FALSE); } while (!IsListEmpty(&Connection->ShutdownRequest)) { Entry = RemoveHeadList( &Connection->ShutdownRequest ); Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); Bucket->Status = STATUS_TIMEOUT; Bucket->Information = 0; CompleteBucket(Connection, Bucket, FALSE); } UnlockObjectFromDpcLevel(Connection); DereferenceObject(Connection); }
static void InternalErrorEventHandler(void *arg, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; /* Make sure the socket didn't get closed */ if (!arg || Connection->SocketContext == NULL) return; /* The PCB is dead now */ Connection->SocketContext = NULL; /* Give them one shot to receive the remaining data */ Connection->ReceiveShutdown = TRUE; Connection->ReceiveShutdownStatus = TCPTranslateError(err); TCPRecvEventHandler(Connection); /* Terminate the connection */ TCPFinEventHandler(Connection, err); }
NTSTATUS TCPDisconnect ( PCONNECTION_ENDPOINT Connection, UINT Flags, PLARGE_INTEGER Timeout, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status = STATUS_INVALID_PARAMETER; PTDI_BUCKET Bucket; KIRQL OldIrql; LARGE_INTEGER ActualTimeout; TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Called\n")); LockObject(Connection, &OldIrql); if (Connection->SocketContext) { if (Flags & TDI_DISCONNECT_RELEASE) { if (IsListEmpty(&Connection->SendRequest)) { Status = TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); } else if (Timeout && Timeout->QuadPart == 0) { FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); TCPTranslateError(LibTCPShutdown(Connection, 0, 1)); Status = STATUS_TIMEOUT; } else { /* Use the timeout specified or 1 second if none was specified */ if (Timeout) { ActualTimeout = *Timeout; } else { ActualTimeout.QuadPart = -1000000; } /* We couldn't complete the request now because we need to wait for outstanding I/O */ Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = (PVOID)Complete; Bucket->Request.RequestContext = Context; InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry); ReferenceObject(Connection); if (KeCancelTimer(&Connection->DisconnectTimer)) { DereferenceObject(Connection); } KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc); Status = STATUS_PENDING; } } if ((Flags & TDI_DISCONNECT_ABORT) || !Flags) { FlushReceiveQueue(Connection, STATUS_FILE_CLOSED, FALSE); FlushSendQueue(Connection, STATUS_FILE_CLOSED, FALSE); FlushShutdownQueue(Connection, STATUS_FILE_CLOSED, FALSE); Status = TCPTranslateError(LibTCPShutdown(Connection, 1, 1)); } } else { /* We already got closed by the other side so just return success */ Status = STATUS_SUCCESS; } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPDisconnect] Leaving. Status = 0x%x\n", Status)); return Status; }
NTSTATUS TCPConnect ( PCONNECTION_ENDPOINT Connection, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, PVOID Context ) { NTSTATUS Status; struct ip_addr bindaddr, connaddr; IP_ADDRESS RemoteAddress; USHORT RemotePort; TA_IP_ADDRESS LocalAddress; PTDI_BUCKET Bucket; PNEIGHBOR_CACHE_ENTRY NCE; KIRQL OldIrql; TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Called\n")); Status = AddrBuildAddress ((PTRANSPORT_ADDRESS)ConnInfo->RemoteAddress, &RemoteAddress, &RemotePort); if (!NT_SUCCESS(Status)) { TI_DbgPrint(DEBUG_TCP, ("Could not AddrBuildAddress in TCPConnect\n")); return Status; } /* Freed in TCPSocketState */ TI_DbgPrint(DEBUG_TCP, ("Connecting to address %x:%x\n", RemoteAddress.Address.IPv4Address, RemotePort)); LockObject(Connection, &OldIrql); if (!Connection->AddressFile) { UnlockObject(Connection, OldIrql); return STATUS_INVALID_PARAMETER; } if (AddrIsUnspecified(&Connection->AddressFile->Address)) { if (!(NCE = RouteGetRouteToDestination(&RemoteAddress))) { UnlockObject(Connection, OldIrql); return STATUS_NETWORK_UNREACHABLE; } bindaddr.addr = NCE->Interface->Unicast.Address.IPv4Address; } else { bindaddr.addr = Connection->AddressFile->Address.Address.IPv4Address; } Status = TCPTranslateError(LibTCPBind(Connection, &bindaddr, Connection->AddressFile->Port)); if (NT_SUCCESS(Status)) { /* Check if we had an unspecified port */ if (!Connection->AddressFile->Port) { /* We did, so we need to copy back the port */ Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE); if (NT_SUCCESS(Status)) { /* Allocate the port in the port bitmap */ Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port); /* This should never fail */ ASSERT(Connection->AddressFile->Port != 0xFFFF); } } if (NT_SUCCESS(Status)) { connaddr.addr = RemoteAddress.Address.IPv4Address; Bucket = ExAllocateFromNPagedLookasideList(&TdiBucketLookasideList); if (!Bucket) { UnlockObject(Connection, OldIrql); return STATUS_NO_MEMORY; } Bucket->Request.RequestNotifyObject = (PVOID)Complete; Bucket->Request.RequestContext = Context; InsertTailList( &Connection->ConnectRequest, &Bucket->Entry ); Status = TCPTranslateError(LibTCPConnect(Connection, &connaddr, RemotePort)); } } UnlockObject(Connection, OldIrql); TI_DbgPrint(DEBUG_TCP,("[IP, TCPConnect] Leaving. Status = 0x%x\n", Status)); return Status; }