[WSD] Fix error flow in IBSPDuplicateSocket.
[mirror/winof/.git] / ulp / wsd / user / ibsp_duplicate.c
1 /*\r
2  * Copyright (c) 2005 SilverStorm Technologies.  All rights reserved.\r
3  *\r
4  * This software is available to you under the OpenIB.org BSD license\r
5  * below:\r
6  *\r
7  *     Redistribution and use in source and binary forms, with or\r
8  *     without modification, are permitted provided that the following\r
9  *     conditions are met:\r
10  *\r
11  *      - Redistributions of source code must retain the above\r
12  *        copyright notice, this list of conditions and the following\r
13  *        disclaimer.\r
14  *\r
15  *      - Redistributions in binary form must reproduce the above\r
16  *        copyright notice, this list of conditions and the following\r
17  *        disclaimer in the documentation and/or other materials\r
18  *        provided with the distribution.\r
19  *\r
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
21  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
22  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
23  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\r
24  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\r
25  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\r
26  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\r
27  * SOFTWARE.\r
28  *\r
29  * $Id$\r
30  */\r
31 \r
32 #include "ibspdll.h"\r
33 #include "rpc.h"\r
34 \r
35 /* \r
36 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_shared_memory_in_a_dynamic_link_library.asp\r
37 */\r
38 \r
39 \r
40 static void\r
41 create_name(\r
42                 OUT                     char                                            *fname,\r
43         IN              const   DWORD                                           dwProcessId,\r
44         IN              const   GUID                                            *p_guid )\r
45 {\r
46         sprintf( fname, "Global\\OpenIB-WSD-%08lx-"\r
47                 "%08lx-%04hx-%04hx-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",\r
48                 dwProcessId, p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
49                 (int)p_guid->Data4[0], (int)p_guid->Data4[1],\r
50                 (int)p_guid->Data4[2], (int)p_guid->Data4[3],\r
51                 (int)p_guid->Data4[4], (int)p_guid->Data4[5],\r
52                 (int)p_guid->Data4[6], (int)p_guid->Data4[7] );\r
53 }\r
54 \r
55 \r
56 /* Create a duplicated socket. param is given by the other process through the \r
57  * lpProtocolInfo->dwProviderReserved field.\r
58  * This function is called by the next-controlling process. */\r
59 int\r
60 setup_duplicate_socket(\r
61         IN                              struct ibsp_socket_info         *socket_info,\r
62         IN                              HANDLE                                          h_dup_info )\r
63 {\r
64         int ret, err;\r
65         struct ibsp_duplicate_info *dup_info;\r
66         ib_net64_t dest_port_guid;\r
67         ib_path_rec_t path_rec;\r
68 \r
69         IBSP_ENTER( IBSP_DBG_DUP );\r
70 \r
71         CL_ASSERT( socket_info->socket_state == IBSP_CREATE );\r
72 \r
73         /* Get a pointer to the file-mapped shared memory. */\r
74         dup_info = MapViewOfFile( h_dup_info, FILE_MAP_READ, 0, 0, 0 );\r
75         if( dup_info == NULL )\r
76         {\r
77                 IBSP_ERROR( ("MapViewOfFile failed with %d\n", GetLastError()) );\r
78                 ret = WSAENETDOWN;\r
79                 goto err1;\r
80         }\r
81 \r
82         socket_info->peer_addr = dup_info->peer_addr;\r
83         socket_info->local_addr = dup_info->local_addr;\r
84         socket_info->socket_options = dup_info->socket_options;\r
85         socket_info->duplicate.dwProcessId = dup_info->dwProcessId;\r
86         socket_info->duplicate.identifier = dup_info->identifier;\r
87 \r
88         socket_info->port = get_port_from_ip_address( dup_info->local_addr.sin_addr );\r
89         if( socket_info->port == NULL )\r
90         {\r
91                 IBSP_ERROR( ("incoming destination IP address not local (%s)\n",\r
92                         inet_ntoa( dup_info->local_addr.sin_addr )) );\r
93                 ret = WSAENETDOWN;\r
94                 goto err1;\r
95         }\r
96 \r
97         /* Get the GUID for the remote IP address. */\r
98         ret = query_guid_address( socket_info->port,\r
99                 socket_info->peer_addr.sin_addr.S_un.S_addr, &dest_port_guid );\r
100         if( ret )\r
101         {\r
102                 IBSP_ERROR( ("query_guid_address failed for IP %08x\n",\r
103                         socket_info->peer_addr.sin_addr.s_addr) );\r
104                 ret = WSAENETDOWN;\r
105                 goto err1;\r
106         }\r
107 \r
108         /* Get the path record */\r
109         ret = query_pr( socket_info->port, dest_port_guid, &path_rec );\r
110         if( ret )\r
111         {\r
112                 IBSP_ERROR( ("query_pr failed for IP %08x\n",\r
113                         socket_info->peer_addr.sin_addr.s_addr) );\r
114                 ret = WSAENETDOWN;\r
115                 goto err1;\r
116         }\r
117 \r
118         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_NEW );\r
119         socket_info->h_event = CreateEvent( NULL, FALSE, FALSE, NULL );\r
120         if( !socket_info->h_event )\r
121         {\r
122                 IBSP_ERROR( ("CreateEvent failed (%d)\n", GetLastError()) );\r
123                 goto err1;\r
124         }\r
125 \r
126         ret = ib_create_socket( socket_info );\r
127         if( ret )\r
128         {\r
129                 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );\r
130                 goto err1;\r
131         }\r
132 \r
133         /* Connects the QP. */\r
134         ret = ib_connect( socket_info, &path_rec );\r
135         if( ret != WSAEWOULDBLOCK )\r
136         {\r
137                 IBSP_ERROR( ("ib_connect failed (%d)\n", ret) );\r
138                 goto err2;\r
139         }\r
140 \r
141         if( WaitForSingleObject( socket_info->h_event, INFINITE ) != WAIT_OBJECT_0 )\r
142                 IBSP_ERROR( ("WaitForSingleObject failed\n") );\r
143 \r
144         cl_spinlock_acquire( &socket_info->mutex );\r
145         if( socket_info->socket_state != IBSP_CONNECTED )\r
146         {\r
147                 cl_spinlock_release( &socket_info->mutex );\r
148                 IBSP_ERROR( ("Failed to connect\n") );\r
149                 ret = WSAENETDOWN;\r
150 err2:\r
151                 g_ibsp.up_call_table.lpWPUCloseSocketHandle(\r
152                         socket_info->switch_socket, &err );\r
153                 socket_info->switch_socket = INVALID_SOCKET;\r
154                 STAT_DEC( wpusocket_num );\r
155 \r
156                 ib_destroy_socket( socket_info );\r
157         }\r
158         else\r
159         {\r
160                 ret = 0;\r
161                 cl_spinlock_release( &socket_info->mutex );\r
162         }\r
163 \r
164 err1:\r
165         if( socket_info->h_event )\r
166         {\r
167                 CloseHandle( socket_info->h_event );\r
168                 socket_info->h_event = NULL;\r
169         }\r
170 \r
171         CloseHandle( h_dup_info );\r
172 \r
173         IBSP_EXIT( IBSP_DBG_DUP );\r
174         return ret;\r
175 }\r
176 \r
177 \r
178 /* Function: IBSPDuplicateSocket\r
179 \r
180  Description:\r
181     This function provides a WSAPROTOCOL_INFOW structure which can be passed\r
182     to another process to open a handle to the same socket. First we need\r
183     to translate the user socket into the provider socket and call the underlying\r
184     WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us\r
185     is an out parameter only!\r
186 */\r
187 int WSPAPI\r
188 IBSPDuplicateSocket(\r
189                                         SOCKET                                          s,\r
190                                         DWORD                                           dwProcessId,\r
191                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
192                                         LPINT                                           lpErrno )\r
193 {\r
194         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
195         struct ibsp_duplicate_info *dup_info = NULL;\r
196         char fname[100];\r
197         GUID guid;\r
198         HANDLE h_dup_info, h_target_process, h_target_dup_info;\r
199         struct disconnect_reason reason;\r
200 \r
201         IBSP_ENTER( IBSP_DBG_DUP );\r
202 \r
203         IBSP_TRACE4( IBSP_DBG_DUP,\r
204                 ("Duplicating socket=0x%p to dwProcessId=0x%x \n",\r
205                 socket_info, dwProcessId) );\r
206 \r
207         cl_spinlock_acquire( &socket_info->mutex );\r
208         if( socket_info->socket_state != IBSP_CONNECTED )\r
209         {\r
210                 cl_spinlock_release( &socket_info->mutex );\r
211                 IBSP_TRACE_EXIT( IBSP_DBG_DUP,\r
212                         ("Socket state not IBSP_CONNECTED, state=%s.\n",\r
213                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
214                 *lpErrno = WSAENOTCONN;\r
215                 return SOCKET_ERROR;\r
216         }\r
217 \r
218         /* Create a GUID to use as unique identifier for this duplication. */\r
219         UuidCreate( &guid );\r
220         create_name( fname, dwProcessId, &guid );\r
221 \r
222         h_dup_info = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,\r
223                 PAGE_READWRITE, 0, sizeof(struct ibsp_duplicate_info), fname );\r
224         if( !h_dup_info )\r
225         {\r
226                 cl_spinlock_release( &socket_info->mutex );\r
227                 IBSP_ERROR_EXIT(\r
228                         ("CreateFileMapping for %s failed with %d\n",\r
229                         fname, GetLastError()) );\r
230                 *lpErrno = WSAENETDOWN;\r
231                 return SOCKET_ERROR;\r
232         }\r
233 \r
234         /* Get a pointer to the file-mapped shared memory. */\r
235         dup_info = MapViewOfFile( h_dup_info, FILE_MAP_WRITE, 0, 0, 0 );\r
236         if( !dup_info )\r
237         {\r
238                 cl_spinlock_release( &socket_info->mutex );\r
239                 IBSP_ERROR_EXIT(\r
240                         ("MapViewOfFile failed with %d\n", GetLastError()) );\r
241                 CloseHandle( h_dup_info );\r
242                 *lpErrno = WSAENETDOWN;\r
243                 return SOCKET_ERROR;\r
244         }\r
245 \r
246         /* \r
247          * Store addressing information so that the duplicating\r
248          * process can reconnect.\r
249          */\r
250         dup_info->identifier = guid;\r
251         dup_info->socket_options = socket_info->socket_options;\r
252         dup_info->peer_addr = socket_info->peer_addr;\r
253         dup_info->local_addr = socket_info->local_addr;\r
254         dup_info->dwProcessId = dwProcessId;\r
255 \r
256         /* Release the reference on the underlying file */\r
257         UnmapViewOfFile( dup_info );\r
258 \r
259         /* Open the target process. */\r
260         h_target_process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId );\r
261         if( !h_target_process )\r
262         {\r
263                 cl_spinlock_release( &socket_info->mutex );\r
264                 IBSP_ERROR_EXIT(\r
265                         ("OpenProcess failed with %d\n", GetLastError()) );\r
266                 CloseHandle( h_dup_info );\r
267                 *lpErrno = WSAENETDOWN;\r
268                 return SOCKET_ERROR;\r
269         }\r
270 \r
271         if( !DuplicateHandle( GetCurrentProcess(), h_dup_info,\r
272                 h_target_process, &h_target_dup_info, 0, TRUE,\r
273                 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ) )\r
274         {\r
275                 cl_spinlock_release( &socket_info->mutex );\r
276                 IBSP_ERROR_EXIT(\r
277                         ("DuplicateHandle failed with %d\n", GetLastError()) );\r
278                 CloseHandle( h_target_process );\r
279                 CloseHandle( h_dup_info );\r
280                 *lpErrno = WSAENETDOWN;\r
281                 return SOCKET_ERROR;\r
282         }\r
283 \r
284         CloseHandle( h_target_process );\r
285         CloseHandle( h_dup_info );\r
286 \r
287         CL_ASSERT( !((ULONG_PTR)h_target_dup_info >> 32) );\r
288         lpProtocolInfo->dwProviderReserved = (DWORD)(ULONG_PTR)h_target_dup_info;\r
289 \r
290         socket_info->duplicate.identifier = guid;\r
291 \r
292         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_OLD );\r
293 \r
294         memset( &reason, 0, sizeof(reason) );\r
295         reason.type = DISC_DUPLICATING;\r
296         reason.duplicating.identifier = guid;\r
297         reason.duplicating.dwProcessId = dwProcessId;\r
298 \r
299         /*\r
300          * Flush all the receive buffers. There should be no\r
301          * send/rdma buffers left.\r
302          */\r
303         ib_disconnect( socket_info, &reason );\r
304 \r
305         /* We changed the state - remove from connection map. */\r
306         ibsp_conn_remove( socket_info );\r
307 \r
308         cl_spinlock_release( &socket_info->mutex );\r
309 \r
310         wait_cq_drain( socket_info );\r
311 \r
312         cl_spinlock_acquire( &socket_info->mutex );\r
313         ib_destroy_socket( socket_info );\r
314         cl_spinlock_release( &socket_info->mutex );\r
315 \r
316         /* And that's it */\r
317         IBSP_EXIT( IBSP_DBG_DUP );\r
318         *lpErrno = 0;\r
319         return 0;\r
320 }\r