[TCPIP]
[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 #include "rosip.h"
14
15 NTSTATUS TCPCheckPeerForAccept(PVOID Context,
16 PTDI_REQUEST_KERNEL Request)
17 {
18 struct tcp_pcb *newpcb = (struct tcp_pcb*)Context;
19 NTSTATUS Status;
20 PTDI_CONNECTION_INFORMATION WhoIsConnecting;
21 PTA_IP_ADDRESS RemoteAddress;
22 struct ip_addr ipaddr;
23
24 if (Request->RequestFlags & TDI_QUERY_ACCEPT)
25 DbgPrint("TDI_QUERY_ACCEPT NOT SUPPORTED!!!\n");
26
27 WhoIsConnecting = (PTDI_CONNECTION_INFORMATION)Request->ReturnConnectionInformation;
28 RemoteAddress = (PTA_IP_ADDRESS)WhoIsConnecting->RemoteAddress;
29
30 RemoteAddress->TAAddressCount = 1;
31 RemoteAddress->Address[0].AddressLength = TDI_ADDRESS_LENGTH_IP;
32 RemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
33
34 Status = TCPTranslateError(LibTCPGetPeerName(newpcb,
35 &ipaddr,
36 &RemoteAddress->Address[0].Address[0].sin_port));
37
38 RemoteAddress->Address[0].Address[0].in_addr = ipaddr.addr;
39
40 return Status;
41 }
42
43 /* This listen is on a socket we keep as internal. That socket has the same
44 * lifetime as the address file */
45 NTSTATUS TCPListen(PCONNECTION_ENDPOINT Connection, UINT Backlog)
46 {
47 NTSTATUS Status = STATUS_SUCCESS;
48 struct ip_addr AddressToBind;
49 KIRQL OldIrql;
50 TA_IP_ADDRESS LocalAddress;
51
52 ASSERT(Connection);
53
54 LockObject(Connection, &OldIrql);
55
56 ASSERT_KM_POINTER(Connection->AddressFile);
57
58 TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Called\n"));
59
60 TI_DbgPrint(DEBUG_TCP, ("Connection->SocketContext %x\n",
61 Connection->SocketContext));
62
63 AddressToBind.addr = Connection->AddressFile->Address.Address.IPv4Address;
64
65 Status = TCPTranslateError(LibTCPBind(Connection,
66 &AddressToBind,
67 Connection->AddressFile->Port));
68
69 if (NT_SUCCESS(Status))
70 {
71 /* Check if we had an unspecified port */
72 if (!Connection->AddressFile->Port)
73 {
74 /* We did, so we need to copy back the port */
75 Status = TCPGetSockAddress(Connection, (PTRANSPORT_ADDRESS)&LocalAddress, FALSE);
76 if (NT_SUCCESS(Status))
77 {
78 /* Allocate the port in the port bitmap */
79 Connection->AddressFile->Port = TCPAllocatePort(LocalAddress.Address[0].Address[0].sin_port);
80
81 /* This should never fail */
82 ASSERT(Connection->AddressFile->Port != 0xFFFF);
83 }
84 }
85 }
86
87 if (NT_SUCCESS(Status))
88 {
89 Connection->SocketContext = LibTCPListen(Connection, Backlog);
90 if (!Connection->SocketContext)
91 Status = STATUS_UNSUCCESSFUL;
92 }
93
94 UnlockObject(Connection, OldIrql);
95
96 TI_DbgPrint(DEBUG_TCP,("[IP, TCPListen] Leaving. Status = %x\n", Status));
97
98 return Status;
99 }
100
101 BOOLEAN TCPAbortListenForSocket
102 ( PCONNECTION_ENDPOINT Listener,
103 PCONNECTION_ENDPOINT Connection)
104 {
105 PLIST_ENTRY ListEntry;
106 PTDI_BUCKET Bucket;
107 KIRQL OldIrql;
108 BOOLEAN Found = FALSE;
109
110 LockObject(Listener, &OldIrql);
111
112 ListEntry = Listener->ListenRequest.Flink;
113 while (ListEntry != &Listener->ListenRequest)
114 {
115 Bucket = CONTAINING_RECORD(ListEntry, TDI_BUCKET, Entry);
116
117 if (Bucket->AssociatedEndpoint == Connection)
118 {
119 DereferenceObject(Bucket->AssociatedEndpoint);
120 RemoveEntryList( &Bucket->Entry );
121 ExFreePoolWithTag( Bucket, TDI_BUCKET_TAG );
122 Found = TRUE;
123 break;
124 }
125
126 ListEntry = ListEntry->Flink;
127 }
128
129 UnlockObject(Listener, OldIrql);
130
131 return Found;
132 }
133
134 NTSTATUS TCPAccept ( PTDI_REQUEST Request,
135 PCONNECTION_ENDPOINT Listener,
136 PCONNECTION_ENDPOINT Connection,
137 PTCP_COMPLETION_ROUTINE Complete,
138 PVOID Context )
139 {
140 NTSTATUS Status;
141 PTDI_BUCKET Bucket;
142 KIRQL OldIrql;
143
144 LockObject(Listener, &OldIrql);
145
146 Bucket = (PTDI_BUCKET)ExAllocatePoolWithTag(NonPagedPool,
147 sizeof(*Bucket),
148 TDI_BUCKET_TAG );
149
150 if (Bucket)
151 {
152 Bucket->AssociatedEndpoint = Connection;
153 ReferenceObject(Bucket->AssociatedEndpoint);
154
155 Bucket->Request.RequestNotifyObject = Complete;
156 Bucket->Request.RequestContext = Context;
157 InsertTailList( &Listener->ListenRequest, &Bucket->Entry );
158 Status = STATUS_PENDING;
159 }
160 else
161 Status = STATUS_NO_MEMORY;
162
163 UnlockObject(Listener, OldIrql);
164
165 return Status;
166 }