059d109af73c65713a02534dbaf590b880802f9c
[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 = OutAddrLen;
49
50 /* BSD uses the first byte of the sockaddr struct as a length.
51 * Since windows doesn't do that we strip it */
52 RequestAddressReturn->Address[0].AddressType =
53 (OutAddr.sin_family >> 8) & 0xff;
54
55 RtlCopyMemory( &RequestAddressReturn->Address[0].Address,
56 ((PCHAR)&OutAddr) + sizeof(USHORT),
57 sizeof(RequestAddressReturn->Address[0].Address[0]) );
58
59 TI_DbgPrint(DEBUG_TCP,("Done copying\n"));
60 }
61
62 TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
63
64 return Status;
65 }
66
67 /* This listen is on a socket we keep as internal. That socket has the same
68 * lifetime as the address file */
69 NTSTATUS TCPListen( PCONNECTION_ENDPOINT Connection, UINT Backlog ) {
70 NTSTATUS Status = STATUS_SUCCESS;
71 SOCKADDR_IN AddressToBind;
72 KIRQL OldIrql;
73
74 ASSERT(Connection);
75 ASSERT_KM_POINTER(Connection->SocketContext);
76 ASSERT_KM_POINTER(Connection->AddressFile);
77
78 KeAcquireSpinLock(&Connection->Lock, &OldIrql);
79
80 TI_DbgPrint(DEBUG_TCP,("TCPListen started\n"));
81
82 TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext %x\n",
83 Connection->SocketContext));
84
85 AddressToBind.sin_family = AF_INET;
86 memcpy( &AddressToBind.sin_addr,
87 &Connection->AddressFile->Address.Address.IPv4Address,
88 sizeof(AddressToBind.sin_addr) );
89 AddressToBind.sin_port = Connection->AddressFile->Port;
90
91 TI_DbgPrint(DEBUG_TCP,("AddressToBind - %x:%x\n", AddressToBind.sin_addr, AddressToBind.sin_port));
92
93 Status = TCPTranslateError( OskitTCPBind( Connection->SocketContext,
94 &AddressToBind,
95 sizeof(AddressToBind) ) );
96
97 if (NT_SUCCESS(Status))
98 Status = TCPTranslateError( OskitTCPListen( Connection->SocketContext, Backlog ) );
99
100 KeReleaseSpinLock(&Connection->Lock, OldIrql);
101
102 TI_DbgPrint(DEBUG_TCP,("TCPListen finished %x\n", Status));
103
104 return Status;
105 }
106
107 BOOLEAN TCPAbortListenForSocket( PCONNECTION_ENDPOINT Listener,
108 PCONNECTION_ENDPOINT Connection ) {
109 PLIST_ENTRY ListEntry;
110 PTDI_BUCKET Bucket;
111 KIRQL OldIrql;
112 BOOLEAN Found = FALSE;
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 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
123 Found = TRUE;
124 break;
125 }
126
127 ListEntry = ListEntry->Flink;
128 }
129
130 KeReleaseSpinLock(&Listener->Lock, OldIrql);
131
132 return Found;
133 }
134
135 NTSTATUS TCPAccept ( PTDI_REQUEST Request,
136 PCONNECTION_ENDPOINT Listener,
137 PCONNECTION_ENDPOINT Connection,
138 PTCP_COMPLETION_ROUTINE Complete,
139 PVOID Context )
140 {
141 NTSTATUS Status;
142 PTDI_BUCKET Bucket;
143 KIRQL OldIrql;
144
145 TI_DbgPrint(DEBUG_TCP,("TCPAccept started\n"));
146
147 KeAcquireSpinLock(&Listener->Lock, &OldIrql);
148
149 Status = TCPServiceListeningSocket( Listener, Connection,
150 (PTDI_REQUEST_KERNEL)Request );
151
152 KeReleaseSpinLock(&Listener->Lock, OldIrql);
153
154 if( Status == STATUS_PENDING ) {
155 Bucket = ExAllocatePoolWithTag( NonPagedPool, sizeof(*Bucket),
156 TDI_BUCKET_TAG );
157
158 if( Bucket ) {
159 Bucket->AssociatedEndpoint = Connection;
160 Bucket->Request.RequestNotifyObject = Complete;
161 Bucket->Request.RequestContext = Context;
162 ExInterlockedInsertTailList( &Listener->ListenRequest, &Bucket->Entry,
163 &Listener->Lock );
164 } else
165 Status = STATUS_NO_MEMORY;
166 }
167
168 TI_DbgPrint(DEBUG_TCP,("TCPAccept finished %x\n", Status));
169 return Status;
170 }