2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS TCP/IP protocol driver
4 * FILE: transport/tcp/event.c
5 * PURPOSE: Transmission Control Protocol
6 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org)
13 #include "lwip/pbuf.h"
19 extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList
;
23 BucketCompletionWorker(PVOID Context
)
25 PTDI_BUCKET Bucket
= (PTDI_BUCKET
)Context
;
26 PTCP_COMPLETION_ROUTINE Complete
;
28 Complete
= (PTCP_COMPLETION_ROUTINE
)Bucket
->Request
.RequestNotifyObject
;
30 Complete(Bucket
->Request
.RequestContext
, Bucket
->Status
, Bucket
->Information
);
32 DereferenceObject(Bucket
->AssociatedEndpoint
);
34 ExFreeToNPagedLookasideList(&TdiBucketLookasideList
, Bucket
);
38 CompleteBucket(PCONNECTION_ENDPOINT Connection
, PTDI_BUCKET Bucket
, const BOOLEAN Synchronous
)
40 ReferenceObject(Connection
);
41 Bucket
->AssociatedEndpoint
= Connection
;
44 BucketCompletionWorker(Bucket
);
48 ChewCreate(BucketCompletionWorker
, Bucket
);
53 FlushReceiveQueue(PCONNECTION_ENDPOINT Connection
, const NTSTATUS Status
, const BOOLEAN interlocked
)
58 ReferenceObject(Connection
);
62 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ReceiveRequest
, &Connection
->Lock
)))
64 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
66 TI_DbgPrint(DEBUG_TCP
,
67 ("Completing Receive request: %x %x\n",
68 Bucket
->Request
, Status
));
70 Bucket
->Status
= Status
;
71 Bucket
->Information
= 0;
73 CompleteBucket(Connection
, Bucket
, FALSE
);
78 while (!IsListEmpty(&Connection
->ReceiveRequest
))
80 Entry
= RemoveHeadList(&Connection
->ReceiveRequest
);
82 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
84 Bucket
->Information
= 0;
85 Bucket
->Status
= Status
;
87 CompleteBucket(Connection
, Bucket
, FALSE
);
91 DereferenceObject(Connection
);
95 FlushSendQueue(PCONNECTION_ENDPOINT Connection
, const NTSTATUS Status
, const BOOLEAN interlocked
)
100 ReferenceObject(Connection
);
104 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->SendRequest
, &Connection
->Lock
)))
106 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
108 TI_DbgPrint(DEBUG_TCP
,
109 ("Completing Send request: %x %x\n",
110 Bucket
->Request
, Status
));
112 Bucket
->Status
= Status
;
113 Bucket
->Information
= 0;
115 CompleteBucket(Connection
, Bucket
, FALSE
);
120 while (!IsListEmpty(&Connection
->SendRequest
))
122 Entry
= RemoveHeadList(&Connection
->SendRequest
);
124 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
126 Bucket
->Information
= 0;
127 Bucket
->Status
= Status
;
129 CompleteBucket(Connection
, Bucket
, FALSE
);
133 DereferenceObject(Connection
);
137 FlushShutdownQueue(PCONNECTION_ENDPOINT Connection
, const NTSTATUS Status
, const BOOLEAN interlocked
)
142 ReferenceObject(Connection
);
146 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ShutdownRequest
, &Connection
->Lock
)))
148 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
150 Bucket
->Status
= Status
;
151 Bucket
->Information
= 0;
153 CompleteBucket(Connection
, Bucket
, FALSE
);
158 while (!IsListEmpty(&Connection
->ShutdownRequest
))
160 Entry
= RemoveHeadList(&Connection
->ShutdownRequest
);
162 Bucket
= CONTAINING_RECORD(Entry
, TDI_BUCKET
, Entry
);
164 Bucket
->Information
= 0;
165 Bucket
->Status
= Status
;
167 CompleteBucket(Connection
, Bucket
, FALSE
);
171 DereferenceObject(Connection
);
175 FlushConnectQueue(PCONNECTION_ENDPOINT Connection
, const NTSTATUS Status
)
180 ReferenceObject(Connection
);
182 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ConnectRequest
, &Connection
->Lock
)))
184 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
186 Bucket
->Status
= Status
;
187 Bucket
->Information
= 0;
189 CompleteBucket(Connection
, Bucket
, FALSE
);
192 DereferenceObject(Connection
);
196 FlushListenQueue(PCONNECTION_ENDPOINT Connection
, const NTSTATUS Status
)
201 ReferenceObject(Connection
);
203 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ListenRequest
, &Connection
->Lock
)))
205 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
207 Bucket
->Status
= Status
;
208 Bucket
->Information
= 0;
210 DereferenceObject(Bucket
->AssociatedEndpoint
);
211 CompleteBucket(Connection
, Bucket
, FALSE
);
214 DereferenceObject(Connection
);
218 FlushAllQueues(PCONNECTION_ENDPOINT Connection
, NTSTATUS Status
)
220 ReferenceObject(Connection
);
222 // flush receive queue
223 FlushReceiveQueue(Connection
, Status
, TRUE
);
225 /* We completed the reads successfully but we need to return failure now */
226 if (Status
== STATUS_SUCCESS
)
228 Status
= STATUS_FILE_CLOSED
;
231 // flush listen queue
232 FlushListenQueue(Connection
, Status
);
235 FlushSendQueue(Connection
, Status
, TRUE
);
237 // flush connect queue
238 FlushConnectQueue(Connection
, Status
);
240 // flush shutdown queue
241 FlushShutdownQueue(Connection
, Status
, TRUE
);
243 DereferenceObject(Connection
);
247 TCPFinEventHandler(void *arg
, const err_t err
)
249 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)arg
, LastConnection
;
250 const NTSTATUS Status
= TCPTranslateError(err
);
253 ASSERT(Connection
->SocketContext
== NULL
);
254 ASSERT(Connection
->AddressFile
);
255 ASSERT(err
!= ERR_OK
);
257 /* Complete all outstanding requests now */
258 FlushAllQueues(Connection
, Status
);
260 LockObject(Connection
, &OldIrql
);
262 LockObjectAtDpcLevel(Connection
->AddressFile
);
264 /* Unlink this connection from the address file */
265 if (Connection
->AddressFile
->Connection
== Connection
)
267 Connection
->AddressFile
->Connection
= Connection
->Next
;
268 DereferenceObject(Connection
);
270 else if (Connection
->AddressFile
->Listener
== Connection
)
272 Connection
->AddressFile
->Listener
= NULL
;
273 DereferenceObject(Connection
);
277 LastConnection
= Connection
->AddressFile
->Connection
;
278 while (LastConnection
->Next
!= Connection
&& LastConnection
->Next
!= NULL
)
279 LastConnection
= LastConnection
->Next
;
280 if (LastConnection
->Next
== Connection
)
282 LastConnection
->Next
= Connection
->Next
;
283 DereferenceObject(Connection
);
287 UnlockObjectFromDpcLevel(Connection
->AddressFile
);
289 /* Remove the address file from this connection */
290 DereferenceObject(Connection
->AddressFile
);
291 Connection
->AddressFile
= NULL
;
293 UnlockObject(Connection
, OldIrql
);
297 TCPAcceptEventHandler(void *arg
, PTCP_PCB newpcb
)
299 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)arg
;
306 ReferenceObject(Connection
);
308 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ListenRequest
, &Connection
->Lock
)))
310 PIO_STACK_LOCATION IrpSp
;
312 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
314 Irp
= Bucket
->Request
.RequestContext
;
315 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
317 TI_DbgPrint(DEBUG_TCP
,("[IP, TCPAcceptEventHandler] Getting the socket\n"));
319 Status
= TCPCheckPeerForAccept(newpcb
,
320 (PTDI_REQUEST_KERNEL
)&IrpSp
->Parameters
);
322 TI_DbgPrint(DEBUG_TCP
,("Socket: Status: %x\n", Status
));
324 Bucket
->Status
= Status
;
325 Bucket
->Information
= 0;
327 if (Status
== STATUS_SUCCESS
)
329 LockObject(Bucket
->AssociatedEndpoint
, &OldIrql
);
331 /* sanity assert...this should never be in anything else but a CLOSED state */
332 ASSERT( ((PTCP_PCB
)Bucket
->AssociatedEndpoint
->SocketContext
)->state
== CLOSED
);
334 /* free socket context created in FileOpenConnection, as we're using a new one */
335 LibTCPClose(Bucket
->AssociatedEndpoint
, TRUE
, FALSE
);
337 /* free previously created socket context (we don't use it, we use newpcb) */
338 Bucket
->AssociatedEndpoint
->SocketContext
= newpcb
;
340 LibTCPAccept(newpcb
, (PTCP_PCB
)Connection
->SocketContext
, Bucket
->AssociatedEndpoint
);
342 UnlockObject(Bucket
->AssociatedEndpoint
, OldIrql
);
345 DereferenceObject(Bucket
->AssociatedEndpoint
);
347 CompleteBucket(Connection
, Bucket
, FALSE
);
349 if (Status
== STATUS_SUCCESS
)
355 DereferenceObject(Connection
);
359 TCPSendEventHandler(void *arg
, const u16_t space
)
361 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)arg
;
369 ReferenceObject(Connection
);
371 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->SendRequest
, &Connection
->Lock
)))
374 PVOID SendBuffer
= 0;
376 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
378 Irp
= Bucket
->Request
.RequestContext
;
379 Mdl
= Irp
->MdlAddress
;
381 TI_DbgPrint(DEBUG_TCP
,
382 ("Getting the user buffer from %x\n", Mdl
));
384 NdisQueryBuffer( Mdl
, &SendBuffer
, &SendLen
);
386 TI_DbgPrint(DEBUG_TCP
,
387 ("Writing %d bytes to %x\n", SendLen
, SendBuffer
));
389 TI_DbgPrint(DEBUG_TCP
, ("Connection: %x\n", Connection
));
392 ("Connection->SocketContext: %x\n",
393 Connection
->SocketContext
));
395 Status
= TCPTranslateError(LibTCPSend(Connection
,
397 SendLen
, &BytesSent
, TRUE
));
399 TI_DbgPrint(DEBUG_TCP
,("TCP Bytes: %d\n", BytesSent
));
401 if( Status
== STATUS_PENDING
)
403 ExInterlockedInsertHeadList(&Connection
->SendRequest
,
410 TI_DbgPrint(DEBUG_TCP
,
411 ("Completing Send request: %x %x\n",
412 Bucket
->Request
, Status
));
414 Bucket
->Status
= Status
;
415 Bucket
->Information
= (Bucket
->Status
== STATUS_SUCCESS
) ? BytesSent
: 0;
417 CompleteBucket(Connection
, Bucket
, FALSE
);
421 // If we completed all outstanding send requests then finish all pending shutdown requests,
422 // cancel the timer and dereference the connection
423 if (IsListEmpty(&Connection
->SendRequest
))
425 FlushShutdownQueue(Connection
, STATUS_SUCCESS
, FALSE
);
427 if (KeCancelTimer(&Connection
->DisconnectTimer
))
429 DereferenceObject(Connection
);
433 DereferenceObject(Connection
);
437 TCPRecvEventHandler(void *arg
)
439 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)arg
;
449 ReferenceObject(Connection
);
451 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ReceiveRequest
, &Connection
->Lock
)))
453 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
455 Irp
= Bucket
->Request
.RequestContext
;
456 Mdl
= Irp
->MdlAddress
;
458 NdisQueryBuffer( Mdl
, &RecvBuffer
, &RecvLen
);
460 Status
= LibTCPGetDataFromConnectionQueue(Connection
, RecvBuffer
, RecvLen
, &Received
);
461 if (Status
== STATUS_PENDING
)
463 ExInterlockedInsertHeadList(&Connection
->ReceiveRequest
,
469 Bucket
->Status
= Status
;
470 Bucket
->Information
= Received
;
472 CompleteBucket(Connection
, Bucket
, FALSE
);
475 DereferenceObject(Connection
);
479 TCPConnectEventHandler(void *arg
, const err_t err
)
481 PCONNECTION_ENDPOINT Connection
= (PCONNECTION_ENDPOINT
)arg
;
485 ReferenceObject(Connection
);
487 while ((Entry
= ExInterlockedRemoveHeadList(&Connection
->ConnectRequest
, &Connection
->Lock
)))
490 Bucket
= CONTAINING_RECORD( Entry
, TDI_BUCKET
, Entry
);
492 Bucket
->Status
= TCPTranslateError(err
);
493 Bucket
->Information
= 0;
495 CompleteBucket(Connection
, Bucket
, FALSE
);
498 DereferenceObject(Connection
);