* Sync with recent trunk (r52669).
[reactos.git] / lib / drivers / ip / transport / tcp / accept.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/accept.c
5 * PURPOSE: Transmission Control Protocol Listen/Accept code
6 * PROGRAMMERS: Art Yerkes (arty@users.sf.net)
7 * REVISIONS:
8 * arty 12/21/2004 Created
9 */
10
11 #include "precomp.h"
12
13 /* Listener->Lock MUST be acquired */
14 NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
15 PCONNECTION_ENDPOINT Connection,
16 PTDI_REQUEST_KERNEL Request ) {
17 NTSTATUS Status;
18 SOCKADDR_IN OutAddr;
19 OSK_UINT OutAddrLen;
20 PTA_IP_ADDRESS RequestAddressReturn;
21 PTDI_CONNECTION_INFORMATION WhoIsConnecting;
22
23 /* Unpack TDI info -- We need the return connection information
24 * struct to return the address so it can be filtered if needed
25 * by WSAAccept -- The returned address will be passed on to
26 * userland after we complete this irp */
27 WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)
28 Request->ReturnConnectionInformation;
29
30 Status = TCPTranslateError
31 ( OskitTCPAccept( Listener->SocketContext,
32 &Connection->SocketContext,
33 Connection,
34 &OutAddr,
35 sizeof(OutAddr),
36 &OutAddrLen,
37 Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) );
38
39 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
40
41 if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) {
42 RequestAddressReturn = WhoIsConnecting->RemoteAddress;
43
44 TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n",
45 RequestAddressReturn, WhoIsConnecting));
46
47 RequestAddressReturn->TAAddressCount = 1;
48 RequestAddressReturn->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
49 RequestAddressReturn->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
50 RequestAddressReturn->Address[0].Address[0].sin_port = OutAddr.sin_port;
51 RequestAddressReturn->Address[0].Address[0].in_addr = OutAddr.sin_addr.s_addr;
52 RtlZeroMemory(RequestAddressReturn->Address[0].Address[0].sin_zero, 8);
53
54 TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
55 }
56
57 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
58
59 return Status;
60 }
61
62 /* This listen is on a socket we keep as internal. That socket has the same
63 * lifetime as the address file */
64 NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
65 NTSTATUS Status = STATUS_SUCCESS;
66 SOCKADDR_IN AddressToBind;
67 KIRQL OldIrql;
68 TA_IP_ADDRESS LocalAddress;
69
70 ASSERT(Connection);
71
72 LockObject(Connection, &OldIrql);
73
74 ASSERT_KM_POINTER(Connection->AddressFile);
75
76 TI_DbgPrint(DEBUG_TCP,("TCPListen started\n"));
77
78 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
79 Connection->SocketContext));
80
81 if (Connection->AddressFile->Port)
82 {
83 AddressToBind.sin_family = AF_INET;
84 memcpy( &AddressToBind.sin_addr,
85 &Connection->AddressFile->Address.Address.IPv4Address,
86 sizeof(AddressToBind.sin_addr) );
87 AddressToBind.sin_port = Connection->AddressFile->Port;
88 TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
89
90 /* Perform an explicit bind */
91 Status = TCPTranslateError(OskitTCPBind(Connection->SocketContext,
92 &AddressToBind,
93 sizeof(AddressToBind)));
94 }
95 else
96 {
97 /* An implicit bind will be performed */
98 Status = STATUS_SUCCESS;
99 }
100
101 if (NT_SUCCESS(Status))
102 Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
103
104 if (NT_SUCCESS(Status))
105 {
106 /* Check if we had an unspecified port */
107 if (!Connection->AddressFile->Port)
108 {
109 /* We did, so we need to copy back the port */
110 if (NT_SUCCESS(TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE)))
111 {
112 /* Allocate the port in the port bitmap */
113 Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
114
115 /* This should never fail */
116 ASSERT(Connection->AddressFile->Port != 0xFFFF);
117 }
118 }
119 }
120
121 UnlockObject(Connection, OldIrql);
122
123 TI_DbgPrint(DEBUG_TCP,("TCPListen finished %x\n", Status));
124
125 return Status;
126 }
127
128 BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
129 PCONNECTION_ENDPOINT Connection ) {
130 PLIST_ENTRY ListEntry;
131 PTDI_BUCKET Bucket;
132 KIRQL OldIrql;
133 BOOLEAN Found = FALSE;
134
135 LockObject(Listener, &OldIrql);
136
137 ListEntry = Listener->ListenRequest.Flink;
138 while ( ListEntry != &Listener->ListenRequest ) {
139 Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
140
141 if( Bucket->AssociatedEndpoint == Connection ) {
142 DereferenceObject(Bucket->AssociatedEndpoint);
143 RemoveEntryList( &Bucket->Entry );
144 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
145 Found = TRUE;
146 break;
147 }
148
149 ListEntry = ListEntry->Flink;
150 }
151
152 UnlockObject(Listener, OldIrql);
153
154 return Found;
155 }
156
157 NTSTATUS TCPAccept ( PTDI_REQUEST Request,
158 PCONNECTION_ENDPOINT Listener,
159 PCONNECTION_ENDPOINT Connection,
160 PTCP_COMPLETION_ROUTINE Complete,
161 PVOID Context )
162 {
163 NTSTATUS Status;
164 PTDI_BUCKET Bucket;
165 KIRQL OldIrql;
166
167 TI_DbgPrint(DEBUG_TCP,("TCPAccept started\n"));
168
169 LockObject(Listener, &OldIrql);
170
171 Status = TCPServiceListeningSocket( Listener, Connection,
172 (PTDI_REQUEST_KERNEL)Request );
173
174 if( Status == STATUS_PENDING ) {
175 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
176 TDI_BUCKET_TAG );
177
178 if( Bucket ) {
179 ReferenceObject(Connection);
180 Bucket->AssociatedEndpoint = Connection;
181 Bucket->Request.RequestNotifyObject = Complete;
182 Bucket->Request.RequestContext = Context;
183 InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
184 } else
185 Status = STATUS_NO_MEMORY;
186 }
187
188 UnlockObject(Listener, OldIrql);
189
190 TI_DbgPrint(DEBUG_TCP,("TCPAccept finished %x\n", Status));
191 return Status;
192 }