ReactOS  0.4.14-dev-384-g5b37caa
event.c
Go to the documentation of this file.
1 /*
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)
7  */
8 
9 #include "precomp.h"
10 
11 #include "lwip/err.h"
12 #include "lwip/sys.h"
13 #include "lwip/pbuf.h"
14 #include "lwip/tcp.h"
15 #include "lwip/api.h"
16 
17 #include "rosip.h"
18 
20 
21 static
22 VOID
24 {
26  PTCP_COMPLETION_ROUTINE Complete;
27 
29 
30  Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information);
31 
33 
34  ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket);
35 }
36 
37 VOID
38 CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous)
39 {
40  ReferenceObject(Connection);
41  Bucket->AssociatedEndpoint = Connection;
42  if (Synchronous)
43  {
44  BucketCompletionWorker(Bucket);
45  }
46  else
47  {
49  }
50 }
51 
52 VOID
53 FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
54 {
55  PTDI_BUCKET Bucket;
57 
58  ReferenceObject(Connection);
59 
60  if (interlocked)
61  {
62  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
63  {
65 
67  ("Completing Receive request: %x %x\n",
68  Bucket->Request, Status));
69 
70  Bucket->Status = Status;
71  Bucket->Information = 0;
72 
73  CompleteBucket(Connection, Bucket, FALSE);
74  }
75  }
76  else
77  {
78  while (!IsListEmpty(&Connection->ReceiveRequest))
79  {
80  Entry = RemoveHeadList(&Connection->ReceiveRequest);
81 
83 
84  Bucket->Information = 0;
85  Bucket->Status = Status;
86 
87  CompleteBucket(Connection, Bucket, FALSE);
88  }
89  }
90 
91  DereferenceObject(Connection);
92 }
93 
94 VOID
95 FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
96 {
97  PTDI_BUCKET Bucket;
99 
100  ReferenceObject(Connection);
101 
102  if (interlocked)
103  {
104  while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
105  {
106  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
107 
109  ("Completing Send request: %x %x\n",
110  Bucket->Request, Status));
111 
112  Bucket->Status = Status;
113  Bucket->Information = 0;
114 
115  CompleteBucket(Connection, Bucket, FALSE);
116  }
117  }
118  else
119  {
120  while (!IsListEmpty(&Connection->SendRequest))
121  {
122  Entry = RemoveHeadList(&Connection->SendRequest);
123 
125 
126  Bucket->Information = 0;
127  Bucket->Status = Status;
128 
129  CompleteBucket(Connection, Bucket, FALSE);
130  }
131  }
132 
133  DereferenceObject(Connection);
134 }
135 
136 VOID
137 FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
138 {
139  PTDI_BUCKET Bucket;
141 
142  ReferenceObject(Connection);
143 
144  if (interlocked)
145  {
146  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ShutdownRequest, &Connection->Lock)))
147  {
148  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
149 
150  Bucket->Status = Status;
151  Bucket->Information = 0;
152 
153  CompleteBucket(Connection, Bucket, FALSE);
154  }
155  }
156  else
157  {
158  while (!IsListEmpty(&Connection->ShutdownRequest))
159  {
160  Entry = RemoveHeadList(&Connection->ShutdownRequest);
161 
163 
164  Bucket->Information = 0;
165  Bucket->Status = Status;
166 
167  CompleteBucket(Connection, Bucket, FALSE);
168  }
169  }
170 
171  DereferenceObject(Connection);
172 }
173 
174 VOID
176 {
177  PTDI_BUCKET Bucket;
179 
180  ReferenceObject(Connection);
181 
182  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
183  {
184  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
185 
186  Bucket->Status = Status;
187  Bucket->Information = 0;
188 
189  CompleteBucket(Connection, Bucket, FALSE);
190  }
191 
192  DereferenceObject(Connection);
193 }
194 
195 VOID
197 {
198  PTDI_BUCKET Bucket;
200 
201  ReferenceObject(Connection);
202 
203  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
204  {
205  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
206 
207  Bucket->Status = Status;
208  Bucket->Information = 0;
209 
211  CompleteBucket(Connection, Bucket, FALSE);
212  }
213 
214  DereferenceObject(Connection);
215 }
216 
217 VOID
219 {
220  ReferenceObject(Connection);
221 
222  // flush receive queue
223  FlushReceiveQueue(Connection, Status, TRUE);
224 
225  /* We completed the reads successfully but we need to return failure now */
226  if (Status == STATUS_SUCCESS)
227  {
229  }
230 
231  // flush listen queue
232  FlushListenQueue(Connection, Status);
233 
234  // flush send queue
235  FlushSendQueue(Connection, Status, TRUE);
236 
237  // flush connect queue
238  FlushConnectQueue(Connection, Status);
239 
240  // flush shutdown queue
241  FlushShutdownQueue(Connection, Status, TRUE);
242 
243  DereferenceObject(Connection);
244 }
245 
246 VOID
248 {
249  PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection;
251  KIRQL OldIrql;
252 
253  ASSERT(Connection->SocketContext == NULL);
254  ASSERT(Connection->AddressFile);
255  ASSERT(err != ERR_OK);
256 
257  /* Complete all outstanding requests now */
258  FlushAllQueues(Connection, Status);
259 
260  LockObject(Connection, &OldIrql);
261 
262  LockObjectAtDpcLevel(Connection->AddressFile);
263 
264  /* Unlink this connection from the address file */
265  if (Connection->AddressFile->Connection == Connection)
266  {
267  Connection->AddressFile->Connection = Connection->Next;
268  DereferenceObject(Connection);
269  }
270  else if (Connection->AddressFile->Listener == Connection)
271  {
272  Connection->AddressFile->Listener = NULL;
273  DereferenceObject(Connection);
274  }
275  else
276  {
277  LastConnection = Connection->AddressFile->Connection;
278  while (LastConnection->Next != Connection && LastConnection->Next != NULL)
279  LastConnection = LastConnection->Next;
280  if (LastConnection->Next == Connection)
281  {
282  LastConnection->Next = Connection->Next;
283  DereferenceObject(Connection);
284  }
285  }
286 
288 
289  /* Remove the address file from this connection */
290  DereferenceObject(Connection->AddressFile);
291  Connection->AddressFile = NULL;
292 
293  UnlockObject(Connection, OldIrql);
294 }
295 
296 VOID
298 {
300  PTDI_BUCKET Bucket;
302  PIRP Irp;
304  KIRQL OldIrql;
305 
306  ReferenceObject(Connection);
307 
308  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock)))
309  {
311 
312  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
313 
314  Irp = Bucket->Request.RequestContext;
316 
317  TI_DbgPrint(DEBUG_TCP,("[IP, TCPAcceptEventHandler] Getting the socket\n"));
318 
319  Status = TCPCheckPeerForAccept(newpcb,
321 
322  TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n", Status));
323 
324  Bucket->Status = Status;
325  Bucket->Information = 0;
326 
327  if (Status == STATUS_SUCCESS)
328  {
330 
331  /* sanity assert...this should never be in anything else but a CLOSED state */
332  ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED );
333 
334  /* free socket context created in FileOpenConnection, as we're using a new one */
336 
337  /* free previously created socket context (we don't use it, we use newpcb) */
338  Bucket->AssociatedEndpoint->SocketContext = newpcb;
339 
340  LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint);
341 
343  }
344 
346 
347  CompleteBucket(Connection, Bucket, FALSE);
348 
349  if (Status == STATUS_SUCCESS)
350  {
351  break;
352  }
353  }
354 
355  DereferenceObject(Connection);
356 }
357 
358 VOID
360 {
362  PTDI_BUCKET Bucket;
364  PIRP Irp;
366  PMDL Mdl;
367  ULONG BytesSent;
368 
369  ReferenceObject(Connection);
370 
371  while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock)))
372  {
373  UINT SendLen = 0;
374  PVOID SendBuffer = 0;
375 
376  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
377 
378  Irp = Bucket->Request.RequestContext;
379  Mdl = Irp->MdlAddress;
380 
382  ("Getting the user buffer from %x\n", Mdl));
383 
384  NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
385 
387  ("Writing %d bytes to %x\n", SendLen, SendBuffer));
388 
389  TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
391  (DEBUG_TCP,
392  ("Connection->SocketContext: %x\n",
393  Connection->SocketContext));
394 
395  Status = TCPTranslateError(LibTCPSend(Connection,
396  SendBuffer,
397  SendLen, &BytesSent, TRUE));
398 
399  TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", BytesSent));
400 
401  if( Status == STATUS_PENDING )
402  {
404  &Bucket->Entry,
405  &Connection->Lock);
406  break;
407  }
408  else
409  {
411  ("Completing Send request: %x %x\n",
412  Bucket->Request, Status));
413 
414  Bucket->Status = Status;
415  Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? BytesSent : 0;
416 
417  CompleteBucket(Connection, Bucket, FALSE);
418  }
419  }
420 
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))
424  {
426 
427  if (KeCancelTimer(&Connection->DisconnectTimer))
428  {
429  DereferenceObject(Connection);
430  }
431  }
432 
433  DereferenceObject(Connection);
434 }
435 
436 VOID
438 {
440  PTDI_BUCKET Bucket;
442  PIRP Irp;
443  PMDL Mdl;
444  UINT Received;
445  UINT RecvLen;
446  PUCHAR RecvBuffer;
448 
449  ReferenceObject(Connection);
450 
451  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock)))
452  {
453  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
454 
455  Irp = Bucket->Request.RequestContext;
456  Mdl = Irp->MdlAddress;
457 
458  NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen );
459 
460  Status = LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer, RecvLen, &Received);
461  if (Status == STATUS_PENDING)
462  {
464  &Bucket->Entry,
465  &Connection->Lock);
466  break;
467  }
468 
469  Bucket->Status = Status;
470  Bucket->Information = Received;
471 
472  CompleteBucket(Connection, Bucket, FALSE);
473  }
474 
475  DereferenceObject(Connection);
476 }
477 
478 VOID
480 {
482  PTDI_BUCKET Bucket;
484 
485  ReferenceObject(Connection);
486 
487  while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock)))
488  {
489 
490  Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
491 
492  Bucket->Status = TCPTranslateError(err);
493  Bucket->Information = 0;
494 
495  CompleteBucket(Connection, Bucket, FALSE);
496  }
497 
498  DereferenceObject(Connection);
499 }
#define TI_DbgPrint(_t_, _x_)
Definition: debug.h:45
VOID FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
Definition: event.c:196
#define TRUE
Definition: types.h:120
struct LOOKASIDE_ALIGN _NPAGED_LOOKASIDE_LIST NPAGED_LOOKASIDE_LIST
PVOID RequestContext
Definition: tdi.h:55
static VOID BucketCompletionWorker(PVOID Context)
Definition: event.c:23
KSPIN_LOCK Lock
Definition: titypes.h:265
struct _Entry Entry
Definition: kefuncs.h:640
_In_ PIRP Irp
Definition: csq.h:116
VOID TCPFinEventHandler(void *arg, const err_t err)
Definition: event.c:247
unsigned char * PUCHAR
Definition: retypes.h:3
err_t LibTCPSend(PCONNECTION_ENDPOINT Connection, void *const dataptr, const u16_t len, u32_t *sent, const int safe)
Definition: rostcp.c:536
LONG NTSTATUS
Definition: precomp.h:26
struct _CONNECTION_ENDPOINT * PCONNECTION_ENDPOINT
VOID TCPRecvEventHandler(void *arg)
Definition: event.c:437
#define LockObjectAtDpcLevel(Object)
Definition: titypes.h:44
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
NTSTATUS TCPCheckPeerForAccept(PVOID Context, PTDI_REQUEST_KERNEL Request)
Definition: accept.c:17
#define DEBUG_TCP
Definition: debug.h:28
#define DereferenceObject(Object)
Definition: titypes.h:24
struct _CONNECTION_ENDPOINT * Next
Definition: titypes.h:289
#define LockObject(Object, Irql)
Definition: titypes.h:34
PADDRESS_FILE AddressFile
Definition: titypes.h:268
UCHAR KIRQL
Definition: env_spec_w32.h:591
VOID TCPConnectEventHandler(void *arg, const err_t err)
Definition: event.c:479
PLIST_ENTRY NTAPI ExInterlockedInsertHeadList(IN OUT PLIST_ENTRY ListHead, IN OUT PLIST_ENTRY ListEntry, IN OUT PKSPIN_LOCK Lock)
Definition: interlocked.c:114
PVOID RequestNotifyObject
Definition: tdi.h:54
#define UnlockObject(Object, OldIrql)
Definition: titypes.h:54
PLIST_ENTRY NTAPI ExInterlockedRemoveHeadList(IN OUT PLIST_ENTRY ListHead, IN OUT PKSPIN_LOCK Lock)
Definition: interlocked.c:166
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
s8_t err_t
Definition: err.h:47
VOID TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb)
Definition: event.c:297
err_t LibTCPClose(PCONNECTION_ENDPOINT Connection, const int safe, const int callback)
Definition: rostcp.c:764
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
VOID(* PTCP_COMPLETION_ROUTINE)(PVOID Context, NTSTATUS Status, ULONG Count)
Definition: tcp.h:11
BOOLEAN ChewCreate(VOID(*Worker)(PVOID), PVOID WorkerContext)
Definition: workqueue.c:65
#define ERR_OK
Definition: err.h:52
NPAGED_LOOKASIDE_LIST TdiBucketLookasideList
Definition: tcp.c:26
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
#define STATUS_PENDING
Definition: ntstatus.h:82
struct tcp_pcb * PTCP_PCB
Definition: rosip.h:15
HRESULT Next([in] ULONG celt, [out, size_is(celt), length_is(*pceltFetched)] STATPROPSETSTG *rgelt, [out] ULONG *pceltFetched)
VOID FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
Definition: event.c:137
LIST_ENTRY ShutdownRequest
Definition: titypes.h:275
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define UnlockObjectFromDpcLevel(Object)
Definition: titypes.h:63
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
KTIMER DisconnectTimer
Definition: titypes.h:280
LIST_ENTRY ReceiveRequest
Definition: titypes.h:273
#define ReferenceObject(Object)
Definition: titypes.h:14
Definition: typedefs.h:117
LIST_ENTRY Entry
Definition: titypes.h:250
#define err(...)
struct _CONNECTION_ENDPOINT * Listener
Definition: titypes.h:153
VOID FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status)
Definition: event.c:218
VOID FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status)
Definition: event.c:175
Status
Definition: gdiplustypes.h:24
NTSTATUS TCPTranslateError(const INT8 err)
Definition: tcp.c:242
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetCurrentIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2745
NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHAR RecvBuffer, UINT RecvLen, UINT *Received)
Definition: rostcp.c:101
struct _CONNECTION_ENDPOINT * AssociatedEndpoint
Definition: titypes.h:251
_In_ PIO_STACK_LOCATION IrpSp
Definition: create.c:4157
LIST_ENTRY ConnectRequest
Definition: titypes.h:271
VOID FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
Definition: event.c:53
LIST_ENTRY ListenRequest
Definition: titypes.h:272
unsigned int UINT
Definition: ndis.h:50
VOID FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked)
Definition: event.c:95
LIST_ENTRY SendRequest
Definition: titypes.h:274
VOID EXPORT NdisQueryBuffer(IN PNDIS_BUFFER Buffer, OUT PVOID *VirtualAddress OPTIONAL, OUT PUINT Length)
Definition: buffer.c:953
NTSTATUS Status
Definition: titypes.h:253
unsigned int ULONG
Definition: retypes.h:1
void LibTCPAccept(PTCP_PCB pcb, struct tcp_pcb *listen_pcb, void *arg)
Definition: rostcp.c:796
struct _TDI_BUCKET * PTDI_BUCKET
TDI_REQUEST Request
Definition: titypes.h:252
struct _CONNECTION_ENDPOINT * Connection
Definition: titypes.h:151
unsigned short u16_t
Definition: cc.h:24
VOID TCPSendEventHandler(void *arg, const u16_t space)
Definition: event.c:359
struct _NAMED_PIPE_CREATE_PARAMETERS * Parameters
Definition: iotypes.h:2772
return STATUS_SUCCESS
Definition: btrfs.c:2938
UINT Received
Definition: arping.c:40
base of all file and directory entries
Definition: entries.h:82
VOID CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous)
Definition: event.c:38
ULONG Information
Definition: titypes.h:254
#define STATUS_FILE_CLOSED
Definition: ntstatus.h:518