Visual C++ backend for rbuild (for now just a hacked mingw backend) and related compi...
[reactos.git] / drivers / network / afd / afd / connect.c
1 /* $Id$
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/net/afd/afd/connect.c
5 * PURPOSE: Ancillary functions driver
6 * PROGRAMMER: Art Yerkes (ayerkes@speakeasy.net)
7 * UPDATE HISTORY:
8 * 20040708 Created
9 */
10 #include "afd.h"
11 #include "tdi_proto.h"
12 #include "tdiconn.h"
13 #include "debug.h"
14
15 NTSTATUS WarmSocketForConnection( PAFD_FCB FCB ) {
16 NTSTATUS Status;
17
18 if( !FCB->TdiDeviceName.Length || !FCB->TdiDeviceName.Buffer ) {
19 AFD_DbgPrint(MID_TRACE,("Null Device\n"));
20 return STATUS_NO_SUCH_DEVICE;
21 }
22
23 Status = TdiOpenConnectionEndpointFile(&FCB->TdiDeviceName,
24 &FCB->Connection.Handle,
25 &FCB->Connection.Object );
26
27 if( NT_SUCCESS(Status) ) {
28 Status = TdiAssociateAddressFile( FCB->AddressFile.Handle,
29 FCB->Connection.Object );
30 }
31
32 return Status;
33 }
34
35 NTSTATUS MakeSocketIntoConnection( PAFD_FCB FCB ) {
36 NTSTATUS Status;
37
38 /* Allocate the receive area and start receiving */
39 FCB->Recv.Window =
40 ExAllocatePool( NonPagedPool, FCB->Recv.Size );
41
42 if( !FCB->Recv.Window ) return STATUS_NO_MEMORY;
43
44 FCB->Send.Window =
45 ExAllocatePool( NonPagedPool, FCB->Send.Size );
46
47 if( !FCB->Send.Window ) {
48 ExFreePool( FCB->Recv.Window );
49 return STATUS_NO_MEMORY;
50 }
51
52 FCB->State = SOCKET_STATE_CONNECTED;
53
54 Status = TdiReceive( &FCB->ReceiveIrp.InFlightRequest,
55 FCB->Connection.Object,
56 TDI_RECEIVE_NORMAL,
57 FCB->Recv.Window,
58 FCB->Recv.Size,
59 &FCB->ReceiveIrp.Iosb,
60 ReceiveComplete,
61 FCB );
62
63 if( Status == STATUS_PENDING ) Status = STATUS_SUCCESS;
64
65 return Status;
66 }
67
68 static NTSTATUS NTAPI StreamSocketConnectComplete
69 ( PDEVICE_OBJECT DeviceObject,
70 PIRP Irp,
71 PVOID Context ) {
72 NTSTATUS Status = Irp->IoStatus.Status;
73 PAFD_FCB FCB = (PAFD_FCB)Context;
74 PLIST_ENTRY NextIrpEntry;
75 PIRP NextIrp;
76
77 AFD_DbgPrint(MID_TRACE,("Called: FCB %x, FO %x\n",
78 Context, FCB->FileObject));
79
80 /* I was wrong about this before as we can have pending writes to a not
81 * yet connected socket */
82 if( !SocketAcquireStateLock( FCB ) ) return STATUS_FILE_CLOSED;
83
84 AFD_DbgPrint(MID_TRACE,("Irp->IoStatus.Status = %x\n",
85 Irp->IoStatus.Status));
86
87 FCB->ConnectIrp.InFlightRequest = NULL;
88
89 if( Irp->Cancel ) {
90 SocketStateUnlock( FCB );
91 return STATUS_CANCELLED;
92 }
93
94 if( NT_SUCCESS(Irp->IoStatus.Status) ) {
95 FCB->PollState |= AFD_EVENT_CONNECT | AFD_EVENT_SEND;
96 AFD_DbgPrint(MID_TRACE,("Going to connected state %d\n", FCB->State));
97 FCB->State = SOCKET_STATE_CONNECTED;
98 } else {
99 FCB->PollState |= AFD_EVENT_CONNECT_FAIL | AFD_EVENT_RECEIVE;
100 AFD_DbgPrint(MID_TRACE,("Going to bound state\n"));
101 FCB->State = SOCKET_STATE_BOUND;
102 }
103
104 PollReeval( FCB->DeviceExt, FCB->FileObject );
105
106 /* Succeed pending irps on the FUNCTION_CONNECT list */
107 while( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_CONNECT] ) ) {
108 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_CONNECT]);
109 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
110 AFD_DbgPrint(MID_TRACE,("Completing connect %x\n", NextIrp));
111 NextIrp->IoStatus.Status = Status;
112 NextIrp->IoStatus.Information = 0;
113 if( NextIrp->MdlAddress ) UnlockRequest( NextIrp, IoGetCurrentIrpStackLocation( NextIrp ) );
114 IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
115 }
116
117 if( NT_SUCCESS(Status) ) {
118 Status = MakeSocketIntoConnection( FCB );
119
120 if( !NT_SUCCESS(Status) ) {
121 SocketStateUnlock( FCB );
122 return Status;
123 }
124
125 if( !IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) ) {
126 NextIrpEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
127 NextIrp = CONTAINING_RECORD(NextIrpEntry, IRP,
128 Tail.Overlay.ListEntry);
129 AFD_DbgPrint(MID_TRACE,("Launching send request %x\n", NextIrp));
130 Status = AfdConnectedSocketWriteData
131 ( DeviceObject,
132 NextIrp,
133 IoGetCurrentIrpStackLocation( NextIrp ),
134 FALSE );
135 }
136
137 if( Status == STATUS_PENDING )
138 Status = STATUS_SUCCESS;
139 }
140
141 SocketStateUnlock( FCB );
142
143 AFD_DbgPrint(MID_TRACE,("Returning %x\n", Status));
144
145 return Status;
146 }
147
148 /* Return the socket object for ths request only if it is a connected or
149 stream type. */
150 NTSTATUS STDCALL
151 AfdStreamSocketConnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
152 PIO_STACK_LOCATION IrpSp) {
153 NTSTATUS Status = STATUS_INVALID_PARAMETER;
154 PTDI_CONNECTION_INFORMATION TargetAddress;
155 PFILE_OBJECT FileObject = IrpSp->FileObject;
156 PAFD_FCB FCB = FileObject->FsContext;
157 PAFD_CONNECT_INFO ConnectReq;
158 AFD_DbgPrint(MID_TRACE,("Called on %x\n", FCB));
159
160 if( !SocketAcquireStateLock( FCB ) ) return LostSocket( Irp );
161 if( !(ConnectReq = LockRequest( Irp, IrpSp )) )
162 return UnlockAndMaybeComplete( FCB, STATUS_NO_MEMORY, Irp,
163 0, NULL );
164
165 AFD_DbgPrint(MID_TRACE,("Connect request:\n"));
166 #if 0
167 OskitDumpBuffer
168 ( (PCHAR)ConnectReq,
169 IrpSp->Parameters.DeviceIoControl.InputBufferLength );
170 #endif
171
172 switch( FCB->State ) {
173 case SOCKET_STATE_CONNECTED:
174 Status = STATUS_SUCCESS;
175 break;
176
177 case SOCKET_STATE_CONNECTING:
178 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
179
180 case SOCKET_STATE_CREATED:
181 if( FCB->LocalAddress ) ExFreePool( FCB->LocalAddress );
182 FCB->LocalAddress =
183 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
184
185 if( FCB->LocalAddress ) {
186 RtlZeroMemory( FCB->LocalAddress,
187 TaLengthOfTransportAddress
188 ( &ConnectReq->RemoteAddress ) );
189
190 FCB->LocalAddress->TAAddressCount = 1;
191 FCB->LocalAddress->Address[0].AddressType =
192 ConnectReq->RemoteAddress.Address[0].AddressType;
193 FCB->LocalAddress->Address[0].AddressLength =
194 ConnectReq->RemoteAddress.Address[0].AddressLength;
195
196 Status = WarmSocketForBind( FCB );
197
198 if( NT_SUCCESS(Status) )
199 FCB->State = SOCKET_STATE_BOUND;
200 else
201 return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL );
202 } else
203 return UnlockAndMaybeComplete
204 ( FCB, STATUS_NO_MEMORY, Irp, 0, NULL );
205
206 /* Drop through to SOCKET_STATE_BOUND */
207
208 case SOCKET_STATE_BOUND:
209 if( FCB->RemoteAddress ) ExFreePool( FCB->RemoteAddress );
210 FCB->RemoteAddress =
211 TaCopyTransportAddress( &ConnectReq->RemoteAddress );
212
213 if( !FCB->RemoteAddress ) {
214 Status = STATUS_NO_MEMORY;
215 break;
216 }
217
218 if( FCB->Flags & AFD_ENDPOINT_CONNECTIONLESS )
219 {
220 Status = STATUS_SUCCESS;
221 break;
222 }
223
224 Status = WarmSocketForConnection( FCB );
225
226 if( !NT_SUCCESS(Status) )
227 break;
228
229 FCB->State = SOCKET_STATE_CONNECTING;
230
231 TdiBuildConnectionInfo
232 ( &TargetAddress,
233 &ConnectReq->RemoteAddress );
234
235 if( TargetAddress ) {
236 Status = TdiConnect( &FCB->ConnectIrp.InFlightRequest,
237 FCB->Connection.Object,
238 TargetAddress,
239 &FCB->ConnectIrp.Iosb,
240 StreamSocketConnectComplete,
241 FCB );
242
243 ExFreePool( TargetAddress );
244
245 AFD_DbgPrint(MID_TRACE,("Queueing IRP %x\n", Irp));
246
247 if( Status == STATUS_PENDING )
248 return LeaveIrpUntilLater( FCB, Irp, FUNCTION_CONNECT );
249 } else Status = STATUS_NO_MEMORY;
250 break;
251
252 default:
253 AFD_DbgPrint(MID_TRACE,("Inappropriate socket state %d for connect\n",
254 FCB->State));
255 break;
256 }
257
258 return UnlockAndMaybeComplete( FCB, Status, Irp, 0, NULL );
259 }