8cac6bac1562e21fd1e101dc2bca82d33cc2a487
[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 http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/using_shared_memory_in_a_dynamic_link_library.asp\r
45 */\r
46 \r
47 \r
48 static void\r
49 create_name(\r
50                 OUT                     char                                            *fname,\r
51         IN              const   DWORD                                           dwProcessId,\r
52         IN              const   GUID                                            *p_guid )\r
53 {\r
54         sprintf( fname, "Global\\OpenIB-WSD-%08lx-"\r
55                 "%08lx-%04hx-%04hx-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",\r
56                 dwProcessId, p_guid->Data1, p_guid->Data2, p_guid->Data3,\r
57                 (int)p_guid->Data4[0], (int)p_guid->Data4[1],\r
58                 (int)p_guid->Data4[2], (int)p_guid->Data4[3],\r
59                 (int)p_guid->Data4[4], (int)p_guid->Data4[5],\r
60                 (int)p_guid->Data4[6], (int)p_guid->Data4[7] );\r
61 }\r
62 \r
63 \r
64 /* Create a duplicated socket. param is given by the other process through the \r
65  * lpProtocolInfo->dwProviderReserved field.\r
66  * This function is called by the next-controlling process. */\r
67 int\r
68 setup_duplicate_socket(\r
69         IN                              struct ibsp_socket_info         *socket_info,\r
70         IN                              HANDLE                                          h_dup_info )\r
71 {\r
72         int ret, err;\r
73         struct ibsp_duplicate_info *dup_info;\r
74         ib_net64_t dest_port_guid;\r
75         ib_path_rec_t path_rec;\r
76 \r
77         IBSP_ENTER( IBSP_DBG_DUP );\r
78 \r
79         CL_ASSERT( socket_info->socket_state == IBSP_CREATE );\r
80 \r
81         /* Get a pointer to the file-mapped shared memory. */\r
82         dup_info = MapViewOfFile( h_dup_info, FILE_MAP_READ, 0, 0, 0 );\r
83         if( dup_info == NULL )\r
84         {\r
85                 IBSP_ERROR( ("MapViewOfFile failed with %d\n", GetLastError()) );\r
86                 ret = WSAENETDOWN;\r
87                 goto err1;\r
88         }\r
89 \r
90         socket_info->peer_addr = dup_info->peer_addr;\r
91         socket_info->local_addr = dup_info->local_addr;\r
92         socket_info->socket_options = dup_info->socket_options;\r
93         socket_info->duplicate.dwProcessId = dup_info->dwProcessId;\r
94         socket_info->duplicate.identifier = dup_info->identifier;\r
95 \r
96         socket_info->port = get_port_from_ip_address( dup_info->local_addr.sin_addr );\r
97         if( socket_info->port == NULL )\r
98         {\r
99                 IBSP_ERROR( ("incoming destination IP address not local (%s)\n",\r
100                         inet_ntoa( dup_info->local_addr.sin_addr )) );\r
101                 ret = WSAENETDOWN;\r
102                 goto err1;\r
103         }\r
104 \r
105         /* Get the GUID for the remote IP address. */\r
106         ret = query_guid_address( socket_info->port,\r
107                 socket_info->peer_addr.sin_addr.S_un.S_addr, &dest_port_guid );\r
108         if( ret )\r
109         {\r
110                 IBSP_ERROR( ("query_guid_address failed for IP %08x\n",\r
111                         socket_info->peer_addr.sin_addr.s_addr) );\r
112                 ret = WSAENETDOWN;\r
113                 goto err1;\r
114         }\r
115 \r
116         /* Get the path record */\r
117         ret = query_pr( socket_info->port, dest_port_guid, &path_rec );\r
118         if( ret )\r
119         {\r
120                 IBSP_ERROR( ("query_pr failed for IP %08x\n",\r
121                         socket_info->peer_addr.sin_addr.s_addr) );\r
122                 ret = WSAENETDOWN;\r
123                 goto err1;\r
124         }\r
125 \r
126         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_NEW );\r
127         socket_info->h_event = CreateEvent( NULL, FALSE, FALSE, NULL );\r
128         if( !socket_info->h_event )\r
129         {\r
130                 IBSP_ERROR( ("CreateEvent failed (%d)\n", GetLastError()) );\r
131                 goto err1;\r
132         }\r
133 \r
134         ret = ib_create_socket( socket_info );\r
135         if( ret )\r
136         {\r
137                 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );\r
138                 goto err1;\r
139         }\r
140 \r
141         /* Connects the QP. */\r
142         ret = ib_connect( socket_info, &path_rec );\r
143         if( ret != WSAEWOULDBLOCK )\r
144         {\r
145                 IBSP_ERROR( ("ib_connect failed (%d)\n", ret) );\r
146                 goto err2;\r
147         }\r
148 \r
149         if( WaitForSingleObject( socket_info->h_event, INFINITE ) != WAIT_OBJECT_0 )\r
150                 IBSP_ERROR( ("WaitForSingleObject failed\n") );\r
151 \r
152         cl_spinlock_acquire( &socket_info->mutex1 );\r
153         if( socket_info->socket_state != IBSP_CONNECTED )\r
154         {\r
155                 cl_spinlock_release( &socket_info->mutex1 );\r
156                 IBSP_ERROR( ("Failed to connect\n") );\r
157                 ret = WSAENETDOWN;\r
158 err2:\r
159                 g_ibsp.up_call_table.lpWPUCloseSocketHandle(\r
160                         socket_info->switch_socket, &err );\r
161                 socket_info->switch_socket = INVALID_SOCKET;\r
162                 STAT_DEC( wpusocket_num );\r
163 \r
164                 ib_destroy_socket( socket_info );\r
165         }\r
166         else\r
167         {\r
168                 ret = 0;\r
169                 cl_spinlock_release( &socket_info->mutex1 );\r
170         }\r
171 \r
172 err1:\r
173         if( socket_info->h_event )\r
174         {\r
175                 CloseHandle( socket_info->h_event );\r
176                 socket_info->h_event = NULL;\r
177         }\r
178 \r
179         CloseHandle( h_dup_info );\r
180 \r
181         IBSP_EXIT( IBSP_DBG_DUP );\r
182         return ret;\r
183 }\r
184 \r
185 \r
186 /* Function: IBSPDuplicateSocket\r
187 \r
188  Description:\r
189     This function provides a WSAPROTOCOL_INFOW structure which can be passed\r
190     to another process to open a handle to the same socket. First we need\r
191     to translate the user socket into the provider socket and call the underlying\r
192     WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us\r
193     is an out parameter only!\r
194 */\r
195 int WSPAPI\r
196 IBSPDuplicateSocket(\r
197                                         SOCKET                                          s,\r
198                                         DWORD                                           dwProcessId,\r
199                                         LPWSAPROTOCOL_INFOW                     lpProtocolInfo,\r
200                                         LPINT                                           lpErrno )\r
201 {\r
202         struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;\r
203         struct ibsp_duplicate_info *dup_info = NULL;\r
204         char fname[100];\r
205         GUID guid;\r
206         HANDLE h_dup_info, h_target_process, h_target_dup_info;\r
207         struct disconnect_reason reason;\r
208 \r
209         IBSP_ENTER( IBSP_DBG_DUP );\r
210 \r
211         IBSP_PRINT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DUP,\r
212                 ("Duplicating socket=0x%p to dwProcessId=0x%x \n",\r
213                 socket_info, dwProcessId) );\r
214 \r
215         cl_spinlock_acquire( &socket_info->mutex1 );\r
216         if( socket_info->socket_state != IBSP_CONNECTED )\r
217         {\r
218                 cl_spinlock_release( &socket_info->mutex1 );\r
219                 IBSP_PRINT_EXIT(TRACE_LEVEL_INFORMATION, IBSP_DBG_DUP,\r
220                         ("Socket state not IBSP_CONNECTED, state=%s.\n",\r
221                         IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );\r
222                 *lpErrno = WSAENOTCONN;\r
223                 return SOCKET_ERROR;\r
224         }\r
225 \r
226         /* Create a GUID to use as unique identifier for this duplication. */\r
227         UuidCreate( &guid );\r
228         create_name( fname, dwProcessId, &guid );\r
229 \r
230         h_dup_info = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,\r
231                 PAGE_READWRITE, 0, sizeof(struct ibsp_duplicate_info), fname );\r
232         if( !h_dup_info )\r
233         {\r
234                 cl_spinlock_release( &socket_info->mutex1 );\r
235                 IBSP_ERROR_EXIT( ("CreateFileMapping for %s failed with %d\n",\r
236                         fname, GetLastError()) );\r
237                 *lpErrno = WSAENETDOWN;\r
238                 return SOCKET_ERROR;\r
239         }\r
240 \r
241         /* Get a pointer to the file-mapped shared memory. */\r
242         dup_info = MapViewOfFile( h_dup_info, FILE_MAP_WRITE, 0, 0, 0 );\r
243         if( !dup_info )\r
244         {\r
245                 cl_spinlock_release( &socket_info->mutex1 );\r
246                 IBSP_ERROR_EXIT( ("MapViewOfFile failed with %d\n", GetLastError()) );\r
247                 CloseHandle( h_dup_info );\r
248                 *lpErrno = WSAENETDOWN;\r
249                 return SOCKET_ERROR;\r
250         }\r
251 \r
252         /* \r
253          * Store addressing information so that the duplicating\r
254          * process can reconnect.\r
255          */\r
256         dup_info->identifier = guid;\r
257         dup_info->socket_options = socket_info->socket_options;\r
258         dup_info->peer_addr = socket_info->peer_addr;\r
259         dup_info->local_addr = socket_info->local_addr;\r
260         dup_info->dwProcessId = dwProcessId;\r
261 \r
262         /* Release the reference on the underlying file */\r
263         UnmapViewOfFile( dup_info );\r
264 \r
265         /* Open the target process. */\r
266         h_target_process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId );\r
267         if( !h_target_process )\r
268         {\r
269                 cl_spinlock_release( &socket_info->mutex1 );\r
270                 IBSP_ERROR_EXIT( ("OpenProcess failed with %d\n", GetLastError()) );\r
271                 CloseHandle( h_dup_info );\r
272                 *lpErrno = WSAENETDOWN;\r
273                 return SOCKET_ERROR;\r
274         }\r
275 \r
276         if( !DuplicateHandle( GetCurrentProcess(), h_dup_info,\r
277                 h_target_process, &h_target_dup_info, 0, TRUE,\r
278                 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ) )\r
279         {\r
280                 cl_spinlock_release( &socket_info->mutex1 );\r
281                 IBSP_ERROR_EXIT( ("DuplicateHandle failed with %d\n", GetLastError()) );\r
282                 CloseHandle( h_target_process );\r
283                 *lpErrno = WSAENETDOWN;\r
284                 return SOCKET_ERROR;\r
285         }\r
286 \r
287         CloseHandle( h_target_process );\r
288 \r
289         CL_ASSERT( !((ULONG_PTR)h_target_dup_info >> 32) );\r
290         lpProtocolInfo->dwProviderReserved = (DWORD)(ULONG_PTR)h_target_dup_info;\r
291 \r
292         socket_info->duplicate.identifier = guid;\r
293 \r
294         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_OLD );\r
295 \r
296         memset( &reason, 0, sizeof(reason) );\r
297         reason.type = DISC_DUPLICATING;\r
298         reason.duplicating.identifier = guid;\r
299         reason.duplicating.dwProcessId = dwProcessId;\r
300 \r
301         /*\r
302          * Flush all the receive buffers. There should be no\r
303          * send/rdma buffers left.\r
304          */\r
305         ib_disconnect( socket_info, &reason );\r
306 \r
307         /* We changed the state - remove from connection map. */\r
308         ibsp_conn_remove( socket_info );\r
309 \r
310         cl_spinlock_release( &socket_info->mutex1 );\r
311 \r
312         wait_cq_drain( socket_info );\r
313 \r
314         cl_spinlock_acquire( &socket_info->mutex1 );\r
315         ib_destroy_socket( socket_info );\r
316         cl_spinlock_release( &socket_info->mutex1 );\r
317 \r
318         /* And that's it */\r
319         IBSP_EXIT( IBSP_DBG_DUP );\r
320         *lpErrno = 0;\r
321         return 0;\r
322 }\r