e7108f5d5cb2f48b7ed04c327dbaadf409b8c841
[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   DWORD                                           identifier )\r
45 {\r
46         sprintf( fname, "SilverStorm-WSD-%08lx-%08lx", dwProcessId, identifier );\r
47 }\r
48 \r
49 \r
50 /* Create a duplicated socket. param is given by the other process through the \r
51  * lpProtocolInfo->dwProviderReserved field.\r
52  * This function is called by the next-controlling process. */\r
53 int\r
54 setup_duplicate_socket(\r
55         IN                              struct ibsp_socket_info         *socket_info,\r
56         IN                              DWORD                                           identifier )\r
57 {\r
58         char fname[100];\r
59         HANDLE h = NULL;\r
60         int ret;\r
61         struct ibsp_duplicate_info *dup_info;\r
62         ib_net64_t dest_port_guid;\r
63         ib_path_rec_t path_rec;\r
64 \r
65         CL_ASSERT( socket_info->socket_state == IBSP_CREATE );\r
66 \r
67         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p dwProcessId=0x%x\n", __FUNCTION__,\r
68                          __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));\r
69 \r
70 \r
71         /* Find the info created and shared by the previous controlling socket. */\r
72         create_name( fname, GetCurrentProcessId(), identifier );\r
73 \r
74         h = CreateFileMapping( INVALID_HANDLE_VALUE,    // use paging file\r
75                                                   NULL, // default security attributes\r
76                                                   PAGE_READWRITE,       // read access\r
77                                                   0,    // size: high 32-bits\r
78                                                   sizeof(struct ibsp_duplicate_info),   // size: low 32-bits\r
79                                                   fname );      // name of map object\r
80         if( h == NULL )\r
81         {\r
82                 IBSP_ERROR(\r
83                         ("CreateFileMapping failed with %d\n", GetLastError()) );\r
84                 ret = WSAENETDOWN;\r
85                 goto done;\r
86         }\r
87 \r
88         /* Make sure this file already existed. */\r
89         if( GetLastError() != ERROR_ALREADY_EXISTS )\r
90         {\r
91                 CloseHandle( h );\r
92                 IBSP_ERROR( ("not mapping for socket duplicate info\n") );\r
93                 ret = WSAENETDOWN;\r
94                 goto done;\r
95         }\r
96 \r
97         /* Get a pointer to the file-mapped shared memory. */\r
98         dup_info = MapViewOfFile( h,    // object to map view of\r
99                                                          FILE_MAP_WRITE,        // read/write access\r
100                                                          0,     // high offset:  map from\r
101                                                          0,     // low offset:   beginning\r
102                                                          0 );   // default: map entire file\r
103         if( dup_info == NULL )\r
104         {\r
105                 IBSP_ERROR(\r
106                         ("MapViewOfFile failed with %d\n", GetLastError()) );\r
107                 ret = WSAENETDOWN;\r
108                 goto done;\r
109         }\r
110 \r
111         /* Check if we already have a switch socket handle. We can have both cases \r
112          * if the two processes are calling IBSPDuplicate back and forth. */\r
113         if( socket_info->switch_socket == INVALID_SOCKET )\r
114         {\r
115                 socket_info->switch_socket =\r
116                         g_ibsp.up_call_table.lpWPUCreateSocketHandle(0,\r
117                                                                                                                  (DWORD_PTR) socket_info, &ret );\r
118 \r
119                 if( socket_info->switch_socket == INVALID_SOCKET )\r
120                 {\r
121                         IBSP_ERROR(\r
122                                 ("WPUCreateSocketHandle() failed: %d", ret) );\r
123                         goto done;\r
124                 }\r
125                 else\r
126                 {\r
127                         fzprint(("%s():%d:0x%x:0x%x: socket_info=0x%p switch_socket=0x%p \n",\r
128                                          __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),\r
129                                          socket_info, socket_info->switch_socket));\r
130 \r
131                         STAT_INC( wpusocket_num );\r
132                 }\r
133         }\r
134 \r
135         socket_info->peer_addr = dup_info->peer_addr;\r
136         socket_info->local_addr = dup_info->local_addr;\r
137         socket_info->socket_options = dup_info->socket_options;\r
138         socket_info->duplicate.dwProcessId = dup_info->dwProcessId;\r
139         socket_info->duplicate.identifier = identifier;\r
140 \r
141         /* Get the port info */\r
142         /* Find the destination IP address */\r
143         socket_info->port = get_port_from_ip_address( dup_info->local_addr.sin_addr );\r
144         if( socket_info->port == NULL )\r
145         {\r
146                 IBSP_ERROR(\r
147                         ("incoming destination IP address not local (%s)\n",\r
148                         inet_ntoa( dup_info->local_addr.sin_addr )) );\r
149                 ret = WSAENETDOWN;\r
150                 goto done;\r
151         }\r
152 \r
153         ret = ib_create_socket( socket_info );\r
154         if( ret )\r
155         {\r
156                 IBSP_ERROR_EXIT(\r
157                         ("ib_create socket failed with %d\n", ret) );\r
158                 ret = WSAENOBUFS;\r
159                 goto done;\r
160         }\r
161 \r
162         /* Get the GUID for the remote IP address. */\r
163         ret = query_guid_address( socket_info->port,\r
164                                                          socket_info->peer_addr.sin_addr.S_un.S_addr,\r
165                                                          &dest_port_guid );\r
166         if( ret )\r
167         {\r
168                 IBSP_ERROR( ("query_guid_address failed for IP %08x\n",\r
169                         socket_info->peer_addr.sin_addr.s_addr) );\r
170                 ret = WSAEHOSTUNREACH;\r
171                 goto done;\r
172         }\r
173 \r
174         /* Get the path record */\r
175         ret = query_pr( socket_info->port, dest_port_guid, &path_rec );\r
176         if( ret )\r
177         {\r
178                 IBSP_ERROR( ("query_pr failed for IP %08x\n",\r
179                         socket_info->peer_addr.sin_addr.s_addr) );\r
180                 ret = WSAEHOSTUNREACH;\r
181                 goto done;\r
182         }\r
183 \r
184         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_NEW );\r
185         socket_info->h_event = CreateEvent( NULL, FALSE, FALSE, NULL );\r
186 \r
187         /* Connects the QP. */\r
188         ret = ib_connect( socket_info, &path_rec );\r
189         if( ret != WSAEWOULDBLOCK )\r
190         {\r
191                 IBSP_ERROR( ("ib_connect failed (%d)\n", ret) );\r
192                 goto done;\r
193         }\r
194 \r
195         if( WaitForSingleObject( socket_info->h_event, INFINITE ) != WAIT_OBJECT_0 )\r
196         {\r
197                 IBSP_ERROR( ("WaitForSingleObject failed\n") );\r
198         }\r
199 \r
200         cl_spinlock_acquire( &socket_info->mutex );\r
201         if( socket_info->socket_state != IBSP_CONNECTED )\r
202         {\r
203                 cl_spinlock_release( &socket_info->mutex );\r
204                 IBSP_ERROR( ("Failed to connect\n") );\r
205                 ret = WSAEHOSTUNREACH;\r
206                 goto done;\r
207         }\r
208         cl_spinlock_release( &socket_info->mutex );\r
209 \r
210         ret = 0;\r
211 \r
212 done:\r
213         if( h )\r
214                 CloseHandle( h );\r
215 \r
216         if( socket_info->h_event )\r
217         {\r
218                 CloseHandle( socket_info->h_event );\r
219                 socket_info->h_event = NULL;\r
220         }\r
221 \r
222         IBSP_EXIT( IBSP_DBG_CONN );\r
223 \r
224         return ret;\r
225 }\r
226 \r
227 \r
228 /*\r
229  * This function is called by the previous controlling process.\r
230  * Called with the socket_info->mutex held.\r
231  */\r
232 int\r
233 prepare_duplicate_socket(\r
234         IN                              struct ibsp_socket_info         *socket_info,\r
235         IN                              DWORD                                           dwProcessId )\r
236 {\r
237         struct ibsp_duplicate_info *dup_info = NULL;\r
238         int i;\r
239         DWORD identifier = 0;\r
240         struct disconnect_reason reason;\r
241 \r
242         fzprint(("%s():%d:0x%x:0x%x: socket=0x%p dwProcessId=0x%x \n", __FUNCTION__,\r
243                          __LINE__, GetCurrentProcessId(),\r
244                          GetCurrentThreadId(), socket_info, dwProcessId));\r
245 \r
246         /* First, flush all the receive buffers. There should be no send/rdma buffers left. */\r
247         CL_ASSERT( socket_info->socket_state == IBSP_CONNECTED );\r
248         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_OLD );\r
249 \r
250         /* We changed the state - remove from connection map. */\r
251         ibsp_conn_remove( socket_info );\r
252 \r
253         /* We might have a left-over from the previous duplicate. */\r
254         if( socket_info->duplicate.mmap_handle != NULL )\r
255         {\r
256                 CloseHandle( socket_info->duplicate.mmap_handle );\r
257                 socket_info->duplicate.mmap_handle = NULL;\r
258         }\r
259 \r
260         /* \r
261          * Share this socket_info so the next-controlling process can get the necessary\r
262          * information to create the duplicated socket. Ensure a unique identifier. \r
263          */\r
264         for( i = 0; i < 50; i++ )\r
265         {\r
266                 char fname[100];\r
267                 GUID guid;\r
268 \r
269                 /* Create a GUID and collapse it into 32 bits. */\r
270                 UuidCreate( &guid );\r
271                 identifier = guid.Data1 ^ (guid.Data2 << 16 | guid.Data3) ^\r
272                         (guid.Data4[7] << 24 | guid.Data4[6] << 16 | guid.Data4[5] << 8 | guid.\r
273                          Data4[4]) ^ (guid.Data4[3] << 24 | guid.Data4[2] << 16 | guid.\r
274                                                   Data4[1] << 8 | guid.Data4[0]);\r
275 \r
276                 create_name( fname, dwProcessId, identifier );\r
277 \r
278                 socket_info->duplicate.mmap_handle = CreateFileMapping( INVALID_HANDLE_VALUE,   // use paging file\r
279                                                                                                                            NULL,        // default security attributes\r
280                                                                                                                            PAGE_READWRITE,      // read access\r
281                                                                                                                            0,   // size: high 32-bits\r
282                                                                                                                            sizeof(struct ibsp_duplicate_info),  // size: low 32-bits\r
283                                                                                                                            fname );     // name of map object\r
284 \r
285                 if( socket_info->duplicate.mmap_handle == NULL )\r
286                 {\r
287                         IBSP_ERROR_EXIT(\r
288                                 ("CreateFileMapping failed with %d\n", GetLastError()) );\r
289                         return WSAENETDOWN;\r
290                 }\r
291 \r
292                 /* Make sure this identifier is unique for that process.  */\r
293                 if( GetLastError() == ERROR_ALREADY_EXISTS )\r
294                 {\r
295                         CloseHandle( socket_info->duplicate.mmap_handle );\r
296                         socket_info->duplicate.mmap_handle = NULL;\r
297 \r
298                         /* Try again. */\r
299                         continue;\r
300                 }\r
301 \r
302                 /* Get a pointer to the file-mapped shared memory. */\r
303                 dup_info = MapViewOfFile( socket_info->duplicate.mmap_handle,   // object to map view of\r
304                                                                  FILE_MAP_WRITE,        // read/write access\r
305                                                                  0,     // high offset:  map from\r
306                                                                  0,     // low offset:   beginning\r
307                                                                  0 );   // default: map entire file\r
308                 if( dup_info == NULL )\r
309                 {\r
310                         IBSP_ERROR_EXIT(\r
311                                 ("MapViewOfFile failed with %d\n", GetLastError()) );\r
312                         CloseHandle( socket_info->duplicate.mmap_handle );\r
313                         socket_info->duplicate.mmap_handle = NULL;\r
314                         return WSAENETDOWN;\r
315                 }\r
316         }\r
317 \r
318         if( dup_info == NULL )\r
319         {\r
320                 IBSP_ERROR_EXIT( ("failed to get a unique identifier\n") );\r
321                 CloseHandle( socket_info->duplicate.mmap_handle );\r
322                 socket_info->duplicate.mmap_handle = NULL;\r
323                 return WSAENETDOWN;\r
324         }\r
325 \r
326         socket_info->duplicate.identifier = identifier;\r
327 \r
328         memset( &reason, 0, sizeof(reason) );\r
329         reason.type = DISC_DUPLICATING;\r
330         reason.duplicating.identifier = identifier;\r
331         reason.duplicating.dwProcessId = dwProcessId;\r
332 \r
333         cl_spinlock_release( &socket_info->mutex );\r
334         ib_disconnect( socket_info, &reason );\r
335         cl_spinlock_acquire( &socket_info->mutex );\r
336 \r
337         wait_cq_drain( socket_info );\r
338 \r
339         ib_destroy_socket( socket_info );\r
340 \r
341         /* Put enough info in dup_info so that the remote socket can recreate the connection. */\r
342         dup_info->port_guid = socket_info->port->guid;\r
343         dup_info->socket_options = socket_info->socket_options;\r
344         dup_info->peer_addr = socket_info->peer_addr;\r
345         dup_info->local_addr = socket_info->local_addr;\r
346         dup_info->dwProcessId = dwProcessId;\r
347 \r
348         /* And that's it */\r
349         IBSP_EXIT( IBSP_DBG_CONN );\r
350         return 0;\r
351 }\r