1838054da263857c35f900c6819c1c2309075116
[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         IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_DUPLICATING_OLD );\r
219 \r
220         /* We changed the state - remove from connection map. */\r
221         ibsp_conn_remove( socket_info );\r
222 \r
223         cl_spinlock_release( &socket_info->mutex );\r
224 \r
225         /* Create a GUID to use as unique identifier for this duplication. */\r
226         UuidCreate( &guid );\r
227         create_name( fname, dwProcessId, &guid );\r
228 \r
229         h_dup_info = CreateFileMapping( INVALID_HANDLE_VALUE, NULL,\r
230                 PAGE_READWRITE, 0, sizeof(struct ibsp_duplicate_info), fname );\r
231         if( !h_dup_info )\r
232         {\r
233                 IBSP_ERROR_EXIT(\r
234                         ("CreateFileMapping for %s failed with %d\n",\r
235                         fname, GetLastError()) );\r
236                 *lpErrno = WSAENETDOWN;\r
237                 return SOCKET_ERROR;\r
238         }\r
239 \r
240         /* Get a pointer to the file-mapped shared memory. */\r
241         dup_info = MapViewOfFile( h_dup_info, FILE_MAP_WRITE, 0, 0, 0 );\r
242         if( !dup_info )\r
243         {\r
244                 IBSP_ERROR_EXIT(\r
245                         ("MapViewOfFile failed with %d\n", GetLastError()) );\r
246                 CloseHandle( h_dup_info );\r
247                 *lpErrno = WSAENETDOWN;\r
248                 return SOCKET_ERROR;\r
249         }\r
250 \r
251         /* \r
252          * Store addressing information so that the duplicating\r
253          * process can reconnect.\r
254          */\r
255         dup_info->identifier = guid;\r
256         dup_info->socket_options = socket_info->socket_options;\r
257         dup_info->peer_addr = socket_info->peer_addr;\r
258         dup_info->local_addr = socket_info->local_addr;\r
259         dup_info->dwProcessId = dwProcessId;\r
260 \r
261         /* Release the reference on the underlying file */\r
262         UnmapViewOfFile( dup_info );\r
263 \r
264         /* Open the target process. */\r
265         h_target_process = OpenProcess( PROCESS_DUP_HANDLE, FALSE, dwProcessId );\r
266         if( !h_target_process )\r
267         {\r
268                 IBSP_ERROR_EXIT(\r
269                         ("OpenProcess failed with %d\n", GetLastError()) );\r
270                 CloseHandle( h_dup_info );\r
271                 *lpErrno = WSAENETDOWN;\r
272                 return SOCKET_ERROR;\r
273         }\r
274 \r
275         if( !DuplicateHandle( GetCurrentProcess(), h_dup_info,\r
276                 h_target_process, &h_target_dup_info, 0, TRUE,\r
277                 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS ) )\r
278         {\r
279                 IBSP_ERROR_EXIT(\r
280                         ("DuplicateHandle failed with %d\n", GetLastError()) );\r
281                 CloseHandle( h_target_process );\r
282                 *lpErrno = WSAENETDOWN;\r
283                 return SOCKET_ERROR;\r
284         }\r
285 \r
286         CloseHandle( h_target_process );\r
287 \r
288         CL_ASSERT( !((ULONG_PTR)h_target_dup_info >> 32) );\r
289         lpProtocolInfo->dwProviderReserved = (DWORD)(ULONG_PTR)h_target_dup_info;\r
290 \r
291         socket_info->duplicate.identifier = guid;\r
292 \r
293         memset( &reason, 0, sizeof(reason) );\r
294         reason.type = DISC_DUPLICATING;\r
295         reason.duplicating.identifier = guid;\r
296         reason.duplicating.dwProcessId = dwProcessId;\r
297 \r
298         /*\r
299          * Flush all the receive buffers. There should be no\r
300          * send/rdma buffers left.\r
301          */\r
302         ib_disconnect( socket_info, &reason );\r
303 \r
304         wait_cq_drain( socket_info );\r
305 \r
306         cl_spinlock_acquire( &socket_info->mutex );\r
307         ib_destroy_socket( socket_info );\r
308         cl_spinlock_release( &socket_info->mutex );\r
309 \r
310         /* And that's it */\r
311         IBSP_EXIT( IBSP_DBG_DUP );\r
312         *lpErrno = 0;\r
313         return 0;\r
314 }\r