Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenevent.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS TCP/IP protocol driver 00004 * FILE: transport/tcp/event.c 00005 * PURPOSE: Transmission Control Protocol 00006 * PROGRAMMERS: Cameron Gutman (cameron.gutman@reactos.org) 00007 */ 00008 00009 #include "precomp.h" 00010 00011 #include "lwip/err.h" 00012 #include "lwip/sys.h" 00013 #include "lwip/pbuf.h" 00014 #include "lwip/tcp.h" 00015 #include "lwip/api.h" 00016 00017 #include "rosip.h" 00018 00019 static const char * const tcp_state_str[] = { 00020 "CLOSED", 00021 "LISTEN", 00022 "SYN_SENT", 00023 "SYN_RCVD", 00024 "ESTABLISHED", 00025 "FIN_WAIT_1", 00026 "FIN_WAIT_2", 00027 "CLOSE_WAIT", 00028 "CLOSING", 00029 "LAST_ACK", 00030 "TIME_WAIT" 00031 }; 00032 00033 extern NPAGED_LOOKASIDE_LIST TdiBucketLookasideList; 00034 00035 static 00036 VOID 00037 BucketCompletionWorker(PVOID Context) 00038 { 00039 PTDI_BUCKET Bucket = (PTDI_BUCKET)Context; 00040 PTCP_COMPLETION_ROUTINE Complete; 00041 00042 Complete = (PTCP_COMPLETION_ROUTINE)Bucket->Request.RequestNotifyObject; 00043 00044 Complete(Bucket->Request.RequestContext, Bucket->Status, Bucket->Information); 00045 00046 DereferenceObject(Bucket->AssociatedEndpoint); 00047 00048 ExFreeToNPagedLookasideList(&TdiBucketLookasideList, Bucket); 00049 } 00050 00051 VOID 00052 CompleteBucket(PCONNECTION_ENDPOINT Connection, PTDI_BUCKET Bucket, const BOOLEAN Synchronous) 00053 { 00054 ReferenceObject(Connection); 00055 Bucket->AssociatedEndpoint = Connection; 00056 if (Synchronous) 00057 { 00058 BucketCompletionWorker(Bucket); 00059 } 00060 else 00061 { 00062 ChewCreate(BucketCompletionWorker, Bucket); 00063 } 00064 } 00065 00066 VOID 00067 FlushReceiveQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked) 00068 { 00069 PTDI_BUCKET Bucket; 00070 PLIST_ENTRY Entry; 00071 00072 ReferenceObject(Connection); 00073 00074 if (interlocked) 00075 { 00076 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) 00077 { 00078 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00079 00080 TI_DbgPrint(DEBUG_TCP, 00081 ("Completing Receive request: %x %x\n", 00082 Bucket->Request, Status)); 00083 00084 Bucket->Status = Status; 00085 Bucket->Information = 0; 00086 00087 CompleteBucket(Connection, Bucket, FALSE); 00088 } 00089 } 00090 else 00091 { 00092 while (!IsListEmpty(&Connection->ReceiveRequest)) 00093 { 00094 Entry = RemoveHeadList(&Connection->ReceiveRequest); 00095 00096 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); 00097 00098 Bucket->Information = 0; 00099 Bucket->Status = Status; 00100 00101 CompleteBucket(Connection, Bucket, FALSE); 00102 } 00103 } 00104 00105 DereferenceObject(Connection); 00106 } 00107 00108 VOID 00109 FlushSendQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked) 00110 { 00111 PTDI_BUCKET Bucket; 00112 PLIST_ENTRY Entry; 00113 00114 ReferenceObject(Connection); 00115 00116 if (interlocked) 00117 { 00118 while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) 00119 { 00120 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00121 00122 TI_DbgPrint(DEBUG_TCP, 00123 ("Completing Send request: %x %x\n", 00124 Bucket->Request, Status)); 00125 00126 Bucket->Status = Status; 00127 Bucket->Information = 0; 00128 00129 CompleteBucket(Connection, Bucket, FALSE); 00130 } 00131 } 00132 else 00133 { 00134 while (!IsListEmpty(&Connection->SendRequest)) 00135 { 00136 Entry = RemoveHeadList(&Connection->SendRequest); 00137 00138 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); 00139 00140 Bucket->Information = 0; 00141 Bucket->Status = Status; 00142 00143 CompleteBucket(Connection, Bucket, FALSE); 00144 } 00145 } 00146 00147 DereferenceObject(Connection); 00148 } 00149 00150 VOID 00151 FlushShutdownQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status, const BOOLEAN interlocked) 00152 { 00153 PTDI_BUCKET Bucket; 00154 PLIST_ENTRY Entry; 00155 00156 ReferenceObject(Connection); 00157 00158 if (interlocked) 00159 { 00160 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ShutdownRequest, &Connection->Lock))) 00161 { 00162 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00163 00164 Bucket->Status = Status; 00165 Bucket->Information = 0; 00166 00167 CompleteBucket(Connection, Bucket, FALSE); 00168 } 00169 } 00170 else 00171 { 00172 while (!IsListEmpty(&Connection->ShutdownRequest)) 00173 { 00174 Entry = RemoveHeadList(&Connection->ShutdownRequest); 00175 00176 Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); 00177 00178 Bucket->Information = 0; 00179 Bucket->Status = Status; 00180 00181 CompleteBucket(Connection, Bucket, FALSE); 00182 } 00183 } 00184 00185 DereferenceObject(Connection); 00186 } 00187 00188 VOID 00189 FlushConnectQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status) 00190 { 00191 PTDI_BUCKET Bucket; 00192 PLIST_ENTRY Entry; 00193 00194 ReferenceObject(Connection); 00195 00196 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) 00197 { 00198 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00199 00200 Bucket->Status = Status; 00201 Bucket->Information = 0; 00202 00203 CompleteBucket(Connection, Bucket, FALSE); 00204 } 00205 00206 DereferenceObject(Connection); 00207 } 00208 00209 VOID 00210 FlushListenQueue(PCONNECTION_ENDPOINT Connection, const NTSTATUS Status) 00211 { 00212 PTDI_BUCKET Bucket; 00213 PLIST_ENTRY Entry; 00214 00215 ReferenceObject(Connection); 00216 00217 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) 00218 { 00219 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00220 00221 Bucket->Status = Status; 00222 Bucket->Information = 0; 00223 00224 DereferenceObject(Bucket->AssociatedEndpoint); 00225 CompleteBucket(Connection, Bucket, FALSE); 00226 } 00227 00228 DereferenceObject(Connection); 00229 } 00230 00231 VOID 00232 FlushAllQueues(PCONNECTION_ENDPOINT Connection, NTSTATUS Status) 00233 { 00234 ReferenceObject(Connection); 00235 00236 // flush receive queue 00237 FlushReceiveQueue(Connection, Status, TRUE); 00238 00239 /* We completed the reads successfully but we need to return failure now */ 00240 if (Status == STATUS_SUCCESS) 00241 { 00242 Status = STATUS_FILE_CLOSED; 00243 } 00244 00245 // flush listen queue 00246 FlushListenQueue(Connection, Status); 00247 00248 // flush send queue 00249 FlushSendQueue(Connection, Status, TRUE); 00250 00251 // flush connect queue 00252 FlushConnectQueue(Connection, Status); 00253 00254 // flush shutdown queue 00255 FlushShutdownQueue(Connection, Status, TRUE); 00256 00257 DereferenceObject(Connection); 00258 } 00259 00260 VOID 00261 TCPFinEventHandler(void *arg, const err_t err) 00262 { 00263 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg, LastConnection; 00264 const NTSTATUS Status = TCPTranslateError(err); 00265 KIRQL OldIrql; 00266 00267 ASSERT(Connection->AddressFile); 00268 00269 /* Check if this was a partial socket closure */ 00270 if (err == ERR_OK && Connection->SocketContext) 00271 { 00272 /* Just flush the receive queue and get out of here */ 00273 FlushReceiveQueue(Connection, STATUS_SUCCESS, TRUE); 00274 } 00275 else 00276 { 00277 /* First off all, remove the PCB pointer */ 00278 Connection->SocketContext = NULL; 00279 00280 /* Complete all outstanding requests now */ 00281 FlushAllQueues(Connection, Status); 00282 00283 LockObject(Connection, &OldIrql); 00284 00285 LockObjectAtDpcLevel(Connection->AddressFile); 00286 00287 /* Unlink this connection from the address file */ 00288 if (Connection->AddressFile->Connection == Connection) 00289 { 00290 Connection->AddressFile->Connection = Connection->Next; 00291 DereferenceObject(Connection); 00292 } 00293 else if (Connection->AddressFile->Listener == Connection) 00294 { 00295 Connection->AddressFile->Listener = NULL; 00296 DereferenceObject(Connection); 00297 } 00298 else 00299 { 00300 LastConnection = Connection->AddressFile->Connection; 00301 while (LastConnection->Next != Connection && LastConnection->Next != NULL) 00302 LastConnection = LastConnection->Next; 00303 if (LastConnection->Next == Connection) 00304 { 00305 LastConnection->Next = Connection->Next; 00306 DereferenceObject(Connection); 00307 } 00308 } 00309 00310 UnlockObjectFromDpcLevel(Connection->AddressFile); 00311 00312 /* Remove the address file from this connection */ 00313 DereferenceObject(Connection->AddressFile); 00314 Connection->AddressFile = NULL; 00315 00316 UnlockObject(Connection, OldIrql); 00317 } 00318 } 00319 00320 VOID 00321 TCPAcceptEventHandler(void *arg, PTCP_PCB newpcb) 00322 { 00323 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg; 00324 PTDI_BUCKET Bucket; 00325 PLIST_ENTRY Entry; 00326 PIRP Irp; 00327 NTSTATUS Status; 00328 KIRQL OldIrql; 00329 00330 ReferenceObject(Connection); 00331 00332 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ListenRequest, &Connection->Lock))) 00333 { 00334 PIO_STACK_LOCATION IrpSp; 00335 00336 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00337 00338 Irp = Bucket->Request.RequestContext; 00339 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 00340 00341 TI_DbgPrint(DEBUG_TCP,("[IP, TCPAcceptEventHandler] Getting the socket\n")); 00342 00343 Status = TCPCheckPeerForAccept(newpcb, 00344 (PTDI_REQUEST_KERNEL)&IrpSp->Parameters); 00345 00346 TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n", Status)); 00347 00348 Bucket->Status = Status; 00349 Bucket->Information = 0; 00350 00351 if (Status == STATUS_SUCCESS) 00352 { 00353 LockObject(Bucket->AssociatedEndpoint, &OldIrql); 00354 00355 /* sanity assert...this should never be in anything else but a CLOSED state */ 00356 ASSERT( ((PTCP_PCB)Bucket->AssociatedEndpoint->SocketContext)->state == CLOSED ); 00357 00358 /* free socket context created in FileOpenConnection, as we're using a new one */ 00359 LibTCPClose(Bucket->AssociatedEndpoint, TRUE, FALSE); 00360 00361 /* free previously created socket context (we don't use it, we use newpcb) */ 00362 Bucket->AssociatedEndpoint->SocketContext = newpcb; 00363 00364 LibTCPAccept(newpcb, (PTCP_PCB)Connection->SocketContext, Bucket->AssociatedEndpoint); 00365 00366 UnlockObject(Bucket->AssociatedEndpoint, OldIrql); 00367 } 00368 00369 DereferenceObject(Bucket->AssociatedEndpoint); 00370 00371 CompleteBucket(Connection, Bucket, FALSE); 00372 } 00373 00374 DereferenceObject(Connection); 00375 } 00376 00377 VOID 00378 TCPSendEventHandler(void *arg, u16_t space) 00379 { 00380 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg; 00381 PTDI_BUCKET Bucket; 00382 PLIST_ENTRY Entry; 00383 PIRP Irp; 00384 NTSTATUS Status; 00385 PMDL Mdl; 00386 00387 ReferenceObject(Connection); 00388 00389 while ((Entry = ExInterlockedRemoveHeadList(&Connection->SendRequest, &Connection->Lock))) 00390 { 00391 UINT SendLen = 0; 00392 PVOID SendBuffer = 0; 00393 00394 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00395 00396 Irp = Bucket->Request.RequestContext; 00397 Mdl = Irp->MdlAddress; 00398 00399 TI_DbgPrint(DEBUG_TCP, 00400 ("Getting the user buffer from %x\n", Mdl)); 00401 00402 NdisQueryBuffer( Mdl, &SendBuffer, &SendLen ); 00403 00404 TI_DbgPrint(DEBUG_TCP, 00405 ("Writing %d bytes to %x\n", SendLen, SendBuffer)); 00406 00407 TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection)); 00408 TI_DbgPrint 00409 (DEBUG_TCP, 00410 ("Connection->SocketContext: %x\n", 00411 Connection->SocketContext)); 00412 00413 Status = TCPTranslateError(LibTCPSend(Connection, 00414 SendBuffer, 00415 SendLen, TRUE)); 00416 00417 TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", SendLen)); 00418 00419 if( Status == STATUS_PENDING ) 00420 { 00421 ExInterlockedInsertHeadList(&Connection->SendRequest, 00422 &Bucket->Entry, 00423 &Connection->Lock); 00424 break; 00425 } 00426 else 00427 { 00428 TI_DbgPrint(DEBUG_TCP, 00429 ("Completing Send request: %x %x\n", 00430 Bucket->Request, Status)); 00431 00432 Bucket->Status = Status; 00433 Bucket->Information = (Bucket->Status == STATUS_SUCCESS) ? SendLen : 0; 00434 00435 CompleteBucket(Connection, Bucket, FALSE); 00436 } 00437 } 00438 00439 // If we completed all outstanding send requests then finish all pending shutdown requests, 00440 // cancel the timer and dereference the connection 00441 if (IsListEmpty(&Connection->SendRequest)) 00442 { 00443 FlushShutdownQueue(Connection, STATUS_SUCCESS, FALSE); 00444 00445 if (KeCancelTimer(&Connection->DisconnectTimer)) 00446 { 00447 DereferenceObject(Connection); 00448 } 00449 } 00450 00451 DereferenceObject(Connection); 00452 } 00453 00454 VOID 00455 TCPRecvEventHandler(void *arg) 00456 { 00457 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg; 00458 PTDI_BUCKET Bucket; 00459 PLIST_ENTRY Entry; 00460 PIRP Irp; 00461 PMDL Mdl; 00462 UINT Received; 00463 UINT RecvLen; 00464 PUCHAR RecvBuffer; 00465 NTSTATUS Status; 00466 00467 ReferenceObject(Connection); 00468 00469 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ReceiveRequest, &Connection->Lock))) 00470 { 00471 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00472 00473 Irp = Bucket->Request.RequestContext; 00474 Mdl = Irp->MdlAddress; 00475 00476 NdisQueryBuffer( Mdl, &RecvBuffer, &RecvLen ); 00477 00478 Status = LibTCPGetDataFromConnectionQueue(Connection, RecvBuffer, RecvLen, &Received); 00479 if (Status == STATUS_PENDING) 00480 { 00481 ExInterlockedInsertHeadList(&Connection->ReceiveRequest, 00482 &Bucket->Entry, 00483 &Connection->Lock); 00484 break; 00485 } 00486 00487 Bucket->Status = Status; 00488 Bucket->Information = Received; 00489 00490 CompleteBucket(Connection, Bucket, FALSE); 00491 } 00492 00493 DereferenceObject(Connection); 00494 } 00495 00496 VOID 00497 TCPConnectEventHandler(void *arg, err_t err) 00498 { 00499 PCONNECTION_ENDPOINT Connection = (PCONNECTION_ENDPOINT)arg; 00500 PTDI_BUCKET Bucket; 00501 PLIST_ENTRY Entry; 00502 00503 ReferenceObject(Connection); 00504 00505 while ((Entry = ExInterlockedRemoveHeadList(&Connection->ConnectRequest, &Connection->Lock))) 00506 { 00507 00508 Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); 00509 00510 Bucket->Status = TCPTranslateError(err); 00511 Bucket->Information = 0; 00512 00513 CompleteBucket(Connection, Bucket, FALSE); 00514 } 00515 00516 DereferenceObject(Connection); 00517 } Generated on Fri May 25 2012 04:22:53 for ReactOS by
1.7.6.1
|