f44c0c918ec0efd80499e5855003146dcb4d08a0
[reactos.git] / reactos / 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 NTSTATUS TCPServiceListeningSocket( PCONNECTION_ENDPOINT Listener,
14 PCONNECTION_ENDPOINT Connection,
15 PTDI_REQUEST_KERNEL Request ) {
16 NTSTATUS Status;
17 SOCKADDR_IN OutAddr;
18 OSK_UINT OutAddrLen;
19 PTA_IP_ADDRESS RequestAddressReturn;
20 PTDI_CONNECTION_INFORMATION WhoIsConnecting;
21
22 /* Unpack TDI info -- We need the return connection information
23 * struct to return the address so it can be filtered if needed
24 * by WSAAccept -- The returned address will be passed on to
25 * userland after we complete this irp */
26 WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)
27 Request->ReturnConnectionInformation;
28
29 TcpipRecursiveMutexEnter(&TCPLock);
30
31 Status = TCPTranslateError
32 ( OskitTCPAccept( Listener->SocketContext,
33 &Connection->SocketContext,
34 &OutAddr,
35 sizeof(OutAddr),
36 &OutAddrLen,
37 Request->RequestFlags & TDI_QUERY_ACCEPT ? 0 : 1 ) );
38
39 TcpipRecursiveMutexLeave(&TCPLock);
40
41 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
42
43 if( NT_SUCCESS(Status) && Status != STATUS_PENDING ) {
44 RequestAddressReturn = WhoIsConnecting->RemoteAddress;
45
46 TI_DbgPrint(DEBUG_TCP,("Copying address to %x (Who %x)\n",
47 RequestAddressReturn, WhoIsConnecting));
48
49 RequestAddressReturn->TAAddressCount = 1;
50 RequestAddressReturn->Address[0].AddressLength = OutAddrLen;
51
52 /* BSD uses the first byte of the sockaddr struct as a length.
53 * Since windows doesn't do that we strip it */
54 RequestAddressReturn->Address[0].AddressType =
55 (OutAddr.sin_family >> 8) & 0xff;
56
57 RtlCopyMemory( &RequestAddressReturn->Address[0].Address,
58 ((PCHAR)&OutAddr) + sizeof(USHORT),
59 sizeof(RequestAddressReturn->Address[0].Address[0]) );
60
61 TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
62 }
63
64 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
65
66 return Status;
67 }
68
69 /* This listen is on a socket we keep as internal. That socket has the same
70 * lifetime as the address file */
71 NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
72 NTSTATUS Status = STATUS_SUCCESS;
73 SOCKADDR_IN AddressToBind;
74
75 ASSERT(Connection);
76 ASSERT_KM_POINTER(Connection->SocketContext);
77 ASSERT_KM_POINTER(Connection->AddressFile);
78
79 TI_DbgPrint(DEBUG_TCP,("TCPListen started\n"));
80
81 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
82 Connection->SocketContext));
83
84 AddressToBind.sin_family = AF_INET;
85 memcpy( &AddressToBind.sin_addr,
86 &Connection->AddressFile->Address.Address.IPv4Address,
87 sizeof(AddressToBind.sin_addr) );
88 AddressToBind.sin_port = Connection->AddressFile->Port;
89
90 TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
91
92 TcpipRecursiveMutexEnter( &TCPLock );
93
94 Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext,
95 &AddressToBind,
96 sizeof(AddressToBind) ) );
97
98 if (NT_SUCCESS(Status))
99 Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
100
101 TcpipRecursiveMutexLeave( &TCPLock );
102
103 TI_DbgPrint(DEBUG_TCP,("TCPListen finished %x\n", Status));
104
105 return Status;
106 }
107
108 VOID TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
109 PCONNECTION_ENDPOINT Connection ) {
110 PLIST_ENTRY ListEntry;
111 PTDI_BUCKET Bucket;
112 KIRQL OldIrql;
113
114 KeAcquireSpinLock(&Listener->Lock, &OldIrql);
115
116 ListEntry = Listener->ListenRequest.Flink;
117 while ( ListEntry != &Listener->ListenRequest ) {
118 Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
119
120 if( Bucket->AssociatedEndpoint == Connection ) {
121 RemoveEntryList( &Bucket->Entry );
122 exFreePool( Bucket );
123 break;
124 }
125
126 ListEntry = ListEntry->Flink;
127 }
128
129 KeReleaseSpinLock(&Listener->Lock, OldIrql);
130 }
131
132 NTSTATUS TCPAccept ( PTDI_REQUEST Request,
133 PCONNECTION_ENDPOINT Listener,
134 PCONNECTION_ENDPOINT Connection,
135 PTCP_COMPLETION_ROUTINE Complete,
136 PVOID Context )
137 {
138 NTSTATUS Status;
139 PTDI_BUCKET Bucket;
140
141 TI_DbgPrint(DEBUG_TCP,("TCPAccept started\n"));
142
143 Status = TCPServiceListeningSocket( Listener, Connection,
144 (PTDI_REQUEST_KERNEL)Request );
145
146 if( Status == STATUS_PENDING ) {
147 Bucket = exAllocatePool( NonPagedPool, sizeof(*Bucket) );
148
149 if( Bucket ) {
150 Bucket->AssociatedEndpoint = Connection;
151 Bucket->Request.RequestNotifyObject = Complete;
152 Bucket->Request.RequestContext = Context;
153 IoMarkIrpPending((PIRP)Context);
154 ExInterlockedInsertTailList( &Listener->ListenRequest, &Bucket->Entry, &Listener->Lock );
155 } else
156 Status = STATUS_NO_MEMORY;
157 }
158
159 TI_DbgPrint(DEBUG_TCP,("TCPAccept finished %x\n", Status));
160 return Status;
161 }