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