mirror of
https://github.com/reactos/reactos.git
synced 2025-07-01 13:31:26 +00:00

- Fix binding to an unspecified port on a connect so that it works reliably by asking the TCP library for a free port instead of assuming that one we have is free - Fix binding to an unspecified port on a listen which previously would result in the address file not having information stored about the port number assigned - Fix a nasty bug which resulted in us binding to an arbitrary port during a connect even when the client wanted a specific port - Revert the hack that partially fixed this before svn path=/trunk/; revision=52501
184 lines
6 KiB
C
184 lines
6 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS TCP/IP protocol driver
|
|
* FILE: transport/tcp/accept.c
|
|
* PURPOSE: Transmission Control Protocol Listen/Accept code
|
|
* PROGRAMMERS: Art Yerkes (arty@users.sf.net)
|
|
* REVISIONS:
|
|
* arty 12/21/2004 Created
|
|
*/
|
|
|
|
#include "precomp.h"
|
|
|
|
/* Listener->Lock MUST be acquired */
|
|
NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
|
|
PCONNECTION_ENDPOINT Connection,
|
|
PTDI_REQUEST_KERNEL Request ) {
|
|
NTSTATUS Status;
|
|
SOCKADDR_IN OutAddr;
|
|
OSK_UINT OutAddrLen;
|
|
PTA_IP_ADDRESS RequestAddressReturn;
|
|
PTDI_CONNECTION_INFORMATION WhoIsConnecting;
|
|
|
|
/* Unpack TDI info -- We need the return connection information
|
|
* struct to return the address so it can be filtered if needed
|
|
* by WSAAccept -- The returned address will be passed on to
|
|
* userland after we complete this irp */
|
|
WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)
|
|
Request->ReturnConnectionInformation;
|
|
|
|
Status = TCPTranslateError
|
|
( OskitTCPAccept( Listener->SocketContext,
|
|
&Connection->SocketContext,
|
|
Connection,
|
|
&OutAddr,
|
|
sizeof(OutAddr),
|
|
&OutAddrLen,
|
|
Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) );
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
|
|
|
|
if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) {
|
|
RequestAddressReturn = WhoIsConnecting->RemoteAddress;
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n",
|
|
RequestAddressReturn, WhoIsConnecting));
|
|
|
|
RequestAddressReturn->TAAddressCount = 1;
|
|
RequestAddressReturn->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
|
|
RequestAddressReturn->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
|
|
RequestAddressReturn->Address[0].Address[0].sin_port = OutAddr.sin_port;
|
|
RequestAddressReturn->Address[0].Address[0].in_addr = OutAddr.sin_addr.s_addr;
|
|
RtlZeroMemory(RequestAddressReturn->Address[0].Address[0].sin_zero, 8);
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
|
|
}
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* 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 Status = STATUS_SUCCESS;
|
|
SOCKADDR_IN AddressToBind;
|
|
KIRQL OldIrql;
|
|
TA_IP_ADDRESS LocalAddress;
|
|
|
|
ASSERT(Connection);
|
|
|
|
LockObject(Connection, &OldIrql);
|
|
|
|
ASSERT_KM_POINTER(Connection->AddressFile);
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("TCPListen started\n"));
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
|
|
Connection->SocketContext));
|
|
|
|
AddressToBind.sin_family = AF_INET;
|
|
memcpy( &AddressToBind.sin_addr,
|
|
&Connection->AddressFile->Address.Address.IPv4Address,
|
|
sizeof(AddressToBind.sin_addr) );
|
|
AddressToBind.sin_port = Connection->AddressFile->Port;
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
|
|
|
|
Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext,
|
|
&AddressToBind,
|
|
sizeof(AddressToBind) ) );
|
|
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))
|
|
Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
|
|
|
|
UnlockObject(Connection, OldIrql);
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("TCPListen finished %x\n", Status));
|
|
|
|
return Status;
|
|
}
|
|
|
|
BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
|
|
PCONNECTION_ENDPOINT Connection ) {
|
|
PLIST_ENTRY ListEntry;
|
|
PTDI_BUCKET Bucket;
|
|
KIRQL OldIrql;
|
|
BOOLEAN Found = FALSE;
|
|
|
|
LockObject(Listener, &OldIrql);
|
|
|
|
ListEntry = Listener->ListenRequest.Flink;
|
|
while ( ListEntry != &Listener->ListenRequest ) {
|
|
Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
|
|
|
|
if( Bucket->AssociatedEndpoint == Connection ) {
|
|
DereferenceObject(Bucket->AssociatedEndpoint);
|
|
RemoveEntryList( &Bucket->Entry );
|
|
ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
|
|
Found = TRUE;
|
|
break;
|
|
}
|
|
|
|
ListEntry = ListEntry->Flink;
|
|
}
|
|
|
|
UnlockObject(Listener, OldIrql);
|
|
|
|
return Found;
|
|
}
|
|
|
|
NTSTATUS TCPAccept ( PTDI_REQUEST Request,
|
|
PCONNECTION_ENDPOINT Listener,
|
|
PCONNECTION_ENDPOINT Connection,
|
|
PTCP_COMPLETION_ROUTINE Complete,
|
|
PVOID Context )
|
|
{
|
|
NTSTATUS Status;
|
|
PTDI_BUCKET Bucket;
|
|
KIRQL OldIrql;
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("TCPAccept started\n"));
|
|
|
|
LockObject(Listener, &OldIrql);
|
|
|
|
Status = TCPServiceListeningSocket( Listener, Connection,
|
|
(PTDI_REQUEST_KERNEL)Request );
|
|
|
|
if( Status == STATUS_PENDING ) {
|
|
Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
|
|
TDI_BUCKET_TAG );
|
|
|
|
if( Bucket ) {
|
|
ReferenceObject(Connection);
|
|
Bucket->AssociatedEndpoint = Connection;
|
|
Bucket->Request.RequestNotifyObject = Complete;
|
|
Bucket->Request.RequestContext = Context;
|
|
InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
|
|
} else
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
UnlockObject(Listener, OldIrql);
|
|
|
|
TI_DbgPrint(DEBUG_TCP,("TCPAccept finished %x\n", Status));
|
|
return Status;
|
|
}
|