2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
4 * This software is available to you under the OpenIB.org BSD license
\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
11 * - Redistributions of source code must retain the above
\r
12 * copyright notice, this list of conditions and the following
\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
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
34 #include "ibspdll.h"
\r
37 struct ibspdll_globals g_ibsp;
\r
40 static const WCHAR *Description = L"Winsock Service Provider for Infiniband Transport";
\r
42 /* Unique provider GUID generated with "uuidgen -s". Same as in installsp.c. */
\r
43 static const GUID provider_guid = {
\r
44 /* c943654d-2c84-4db7-af3e-fdf1c5322458 */
\r
45 0xc943654d, 0x2c84, 0x4db7,
\r
46 {0xaf, 0x3e, 0xfd, 0xf1, 0xc5, 0x32, 0x24, 0x58}
\r
49 static DWORD no_read = 0;
\r
55 * Provides initialization when the ibspdll DLL is loaded.
\r
59 IN HINSTANCE hinstDll,
\r
61 IN LPVOID lpvReserved )
\r
64 TCHAR dbg_lvl_str[16];
\r
68 CL_ENTER( IBSP_DBG_DLL, gdbg_lvl );
\r
70 UNUSED_PARAM( hinstDll );
\r
71 UNUSED_PARAM( lpvReserved );
\r
73 fzprint(("%s():%d:0x%x:0x%x: hinstDll=%d dwReason=%d lpvReserved=0x%p\n",
\r
75 __LINE__, GetCurrentProcessId(),
\r
76 GetCurrentThreadId(), hinstDll, dwReason, lpvReserved));
\r
82 if( GetEnvironmentVariable( "IBSPLOAD", buf, sizeof(buf) ) == 0 )
\r
84 CL_EXIT_ERROR( IBSP_DBG_DLL, gdbg_lvl, ("IBSPLOAD not defined:\n") );
\r
93 case DLL_PROCESS_ATTACH:
\r
94 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_PROCESS_ATTACH\n") );
\r
97 i = GetEnvironmentVariable( "IBWSD_DBG", dbg_lvl_str, 16 );
\r
100 gdbg_lvl = _tcstoul( dbg_lvl_str, NULL, 16 );
\r
101 IBSP_TRACE( IBSP_DBG_DLL,
\r
102 ("Given IBWSD_DBG debug level:0x%X\n",
\r
107 /* See if the user wants to disable RDMA reads. */
\r
108 no_read = GetEnvironmentVariable( "IBWSD_NO_READ", NULL, 0 );
\r
110 if( init_globals() )
\r
114 case DLL_THREAD_ATTACH:
\r
115 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_THREAD_ATTACH\n") );
\r
118 case DLL_THREAD_DETACH:
\r
119 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_THREAD_DETACH\n") );
\r
122 case DLL_PROCESS_DETACH:
\r
123 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_PROCESS_DETACH\n") );
\r
127 cl_list_item_t *socket_item = NULL;
\r
129 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
131 for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list );
\r
132 socket_item != cl_qlist_end( &g_ibsp.socket_info_list );
\r
133 socket_item = cl_qlist_next( socket_item ) )
\r
135 struct ibsp_socket_info *socket_info = NULL;
\r
136 socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item);
\r
139 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
141 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl, ("Statistics:\n") );
\r
142 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
143 (" overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );
\r
144 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
145 (" max_comp_count = %d\n", g_ibsp.max_comp_count) );
\r
146 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
147 (" overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );
\r
149 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl, (" send_count = %d\n", g_ibsp.send_count) );
\r
151 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
152 (" number of QPs left = %d\n", g_ibsp.qp_num) );
\r
153 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
154 (" number of CQs left = %d\n", g_ibsp.cq_num) );
\r
155 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
156 (" number of PDs left = %d\n", g_ibsp.pd_num) );
\r
157 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
158 (" number of ALs left = %d\n", g_ibsp.al_num) );
\r
159 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
160 (" number of MRs left = %d\n", g_ibsp.mr_num) );
\r
161 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
162 (" number of listens left = %d\n", g_ibsp.listen_num) );
\r
163 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
164 (" number of PNPs left = %d\n", g_ibsp.pnp_num) );
\r
165 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
166 (" number of threads left = %d\n", g_ibsp.thread_num) );
\r
167 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
168 (" number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );
\r
170 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
171 (" CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );
\r
179 CL_EXIT( IBSP_DBG_DLL, gdbg_lvl );
\r
185 extern BOOL APIENTRY
\r
186 _DllMainCRTStartupForGS(
\r
187 IN HINSTANCE h_module,
\r
188 IN DWORD ul_reason_for_call,
\r
189 IN LPVOID lp_reserved );
\r
194 IN HINSTANCE h_module,
\r
195 IN DWORD ul_reason_for_call,
\r
196 IN LPVOID lp_reserved )
\r
198 switch( ul_reason_for_call )
\r
200 case DLL_PROCESS_ATTACH:
\r
201 if( !_DllMainCRTStartupForGS(
\r
202 h_module, ul_reason_for_call, lp_reserved ) )
\r
207 return _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
209 case DLL_PROCESS_DETACH:
\r
210 _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
212 return _DllMainCRTStartupForGS(
\r
213 h_module, ul_reason_for_call, lp_reserved );
\r
219 /* Function: IBSPAccept
\r
222 * Handle the WSAAccept function. The only special consideration here
\r
223 * is the conditional accept callback. You can choose to intercept
\r
224 * this by substituting your own callback (you'll need to keep track
\r
225 * of the user supplied callback so you can trigger that once your
\r
226 * substituted function is triggered).
\r
228 static SOCKET WSPAPI
\r
231 OUT struct sockaddr FAR *addr,
\r
232 IN OUT LPINT addrlen,
\r
233 IN LPCONDITIONPROC lpfnCondition,
\r
234 IN DWORD_PTR dwCallbackData,
\r
235 OUT LPINT lpErrno )
\r
237 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
238 struct ibsp_socket_info *new_socket_info;
\r
240 SOCKET new_socket = INVALID_SOCKET;
\r
243 struct listen_incoming *incoming;
\r
244 struct ibsp_port *port;
\r
247 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
249 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
250 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
252 CL_ASSERT( lpfnCondition );
\r
254 if( *addrlen < sizeof(struct sockaddr_in) )
\r
256 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
257 ("invalid addrlen (%d, %d)\n", *addrlen, sizeof(struct sockaddr_in)) );
\r
258 *lpErrno = WSAEFAULT;
\r
259 return INVALID_SOCKET;
\r
262 /* Check if there is any pending connection for this socket. If
\r
263 * there is one, create a socket, and then query the switch about
\r
264 * the pending connection */
\r
266 cl_spinlock_acquire( &socket_info->mutex );
\r
268 /* Verify the state of the socket */
\r
269 if( socket_info->socket_state != IBSP_LISTEN )
\r
271 cl_spinlock_release( &socket_info->mutex );
\r
272 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
273 ("Socket is not in right socket_state (%s)\n",
\r
274 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
275 *lpErrno = WSAEINVAL;
\r
276 return INVALID_SOCKET;
\r
279 if( cl_qlist_count( &socket_info->info.listen.list ) == 0 )
\r
281 cl_spinlock_release( &socket_info->mutex );
\r
283 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
284 ("No pending connection found for this socket\n") );
\r
285 *lpErrno = WSAEWOULDBLOCK;
\r
286 return INVALID_SOCKET;
\r
289 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl,
\r
290 ("IBSPAccept: Found pending connection on this socket\n") );
\r
292 incoming = PARENT_STRUCT(cl_qlist_head( &socket_info->info.listen.list ),
\r
293 struct listen_incoming, item);
\r
294 port = socket_info->port;
\r
298 /* Find the destination IP address */
\r
301 /* The socket was bound to INADDR_ANY. We must find the correct port
\r
302 * for the new socket. */
\r
303 port = get_port_from_ip_address( incoming->params.dest.sin_addr );
\r
306 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
307 ("incoming destination IP address not local (%s)\n",
\r
308 inet_ntoa( incoming->params.dest.sin_addr )) );
\r
313 /* Cross-check with the path info to make sure we are conectiong correctly */
\r
314 if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) )
\r
316 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
317 ("GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n",
\r
319 ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) );
\r
326 /* The request is invalid. Remove it from the list and reject it. */
\r
327 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
328 cl_spinlock_release( &socket_info->mutex );
\r
330 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
332 HeapFree( g_ibsp.heap, 0, incoming );
\r
333 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("bad incoming parameter\n") );
\r
334 *lpErrno = WSAECONNREFUSED;
\r
335 return INVALID_SOCKET;
\r
339 * Check against the conditional routine if socket can be created
\r
343 /* Set the caller and callee data buffer */
\r
344 caller_id.buf = (char *)&incoming->params.source;
\r
345 caller_id.len = sizeof(incoming->params.source);
\r
347 callee_id.buf = (char *)&incoming->params.dest;
\r
348 callee_id.len = sizeof(incoming->params.dest);
\r
354 p += sprintf( p, "got incoming connection from %s/%d-%d to",
\r
355 inet_ntoa( incoming->params.source.sin_addr ),
\r
356 cl_ntoh16( incoming->params.source.sin_port ),
\r
357 incoming->params.source.sin_family );
\r
358 p += sprintf( p, " %s/%d-%d",
\r
359 inet_ntoa( incoming->params.dest.sin_addr ),
\r
360 cl_ntoh16( incoming->params.dest.sin_port ),
\r
361 incoming->params.dest.sin_family );
\r
363 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, (buf) );
\r
367 /* Call the conditional function */
\r
368 ret = lpfnCondition( &caller_id, NULL,
\r
369 NULL, NULL, &callee_id, NULL, NULL, dwCallbackData );
\r
374 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
375 cl_spinlock_release( &socket_info->mutex );
\r
377 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
379 HeapFree( g_ibsp.heap, 0, incoming );
\r
380 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
381 ("Conditional routine rejected connection\n") );
\r
382 *lpErrno = WSAECONNREFUSED;
\r
383 return INVALID_SOCKET;
\r
387 cl_spinlock_release( &socket_info->mutex );
\r
389 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Conditional routine returned defer\n") );
\r
390 /* TODO: Send MRA */
\r
391 *lpErrno = WSATRY_AGAIN;
\r
392 return INVALID_SOCKET;
\r
399 /* Should never happen */
\r
400 cl_spinlock_release( &socket_info->mutex );
\r
401 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
402 ("lpfnCondition returned undocumented code (%d)\n", ret) );
\r
404 *lpErrno = WSAECONNREFUSED;
\r
405 return INVALID_SOCKET;
\r
408 /* Create a new socket here */
\r
409 new_socket_info = create_socket_info();
\r
410 if( new_socket_info == NULL )
\r
412 cl_spinlock_release( &socket_info->mutex );
\r
414 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("create_socket_info return NULL\n") );
\r
415 *lpErrno = WSAENOBUFS;
\r
416 return INVALID_SOCKET;
\r
419 new_socket = g_ibsp.up_call_table.lpWPUCreateSocketHandle(
\r
420 0, (DWORD_PTR)new_socket_info, lpErrno );
\r
422 if( new_socket == INVALID_SOCKET )
\r
424 cl_spinlock_release( &socket_info->mutex );
\r
426 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
427 ("WPUCreateSocketHandle() failed: %d", *lpErrno) );
\r
428 free_socket_info( new_socket_info );
\r
429 return INVALID_SOCKET;
\r
432 STAT_INC( wpusocket_num );
\r
434 fzprint(("%s():%d:0x%x:0x%x: new_socket_info=0x%p new_socket=0x%p \n", __FUNCTION__,
\r
435 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), new_socket_info,
\r
438 /* Time to allocate our IB QP */
\r
439 new_socket_info->port = port;
\r
440 ret = ib_create_socket( new_socket_info );
\r
443 cl_spinlock_release( &socket_info->mutex );
\r
445 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
446 ("ib_create socket failed with %d\n", ret) );
\r
447 *lpErrno = WSAENOBUFS;
\r
448 return INVALID_SOCKET;
\r
451 /* Store the IP address and port number in the socket context */
\r
452 new_socket_info->local_addr = incoming->params.dest;
\r
454 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
456 cl_spinlock_release( &socket_info->mutex );
\r
458 /* Update the state of the socket context */
\r
459 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_ACCEPT );
\r
461 /* Copy the socket context info from parent socket context */
\r
462 new_socket_info->socket_options = socket_info->socket_options;
\r
464 /* Store the client socket address information */
\r
465 memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) );
\r
466 *addrlen = sizeof(struct sockaddr_in);
\r
468 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("The socket address of connecting entity is\n") );
\r
469 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, &incoming->params.source );
\r
471 new_socket_info->peer_addr = incoming->params.source;
\r
472 new_socket_info->switch_socket = new_socket;
\r
474 new_socket_info->info.accept.event = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
476 ret = ib_accept( new_socket_info, &incoming->cm_req_received, lpErrno );
\r
480 /* Free the socket descriptor */
\r
481 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p calling lpWPUCloseSocketHandle=0x%p\n",
\r
482 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
483 socket_info, socket_info->switch_socket));
\r
485 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
486 new_socket_info->switch_socket, lpErrno ) == SOCKET_ERROR )
\r
488 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
489 ("WPUCloseSocketHandle failed: %d\n", *lpErrno) );
\r
493 STAT_DEC( wpusocket_num );
\r
496 CloseHandle( new_socket_info->info.accept.event );
\r
498 ib_destroy_socket( new_socket_info );
\r
500 free_socket_info( new_socket_info );
\r
502 /* Be nice and reject that connection. */
\r
503 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
505 HeapFree( g_ibsp.heap, 0, incoming );
\r
506 *lpErrno = WSAEACCES;
\r
508 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_accept failed (%d)\n", ret) );
\r
510 return INVALID_SOCKET;
\r
514 HeapFree( g_ibsp.heap, 0, incoming );
\r
516 if( WaitForSingleObject( new_socket_info->info.accept.event, INFINITE ) == WAIT_OBJECT_0 )
\r
518 CloseHandle( new_socket_info->info.accept.event );
\r
520 cl_spinlock_acquire( &new_socket_info->mutex );
\r
522 if( new_socket_info->socket_state == IBSP_CONNECTED )
\r
524 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
525 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &new_socket_info->item );
\r
526 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
528 cl_spinlock_release( &new_socket_info->mutex );
\r
532 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
533 ("ib_accept failed - socket state is %s\n",
\r
534 IBSP_SOCKET_STATE_STR( new_socket_info->socket_state )) );
\r
536 cl_spinlock_release( &new_socket_info->mutex );
\r
538 /* The accept failed (by a REJ for instance). */
\r
540 /* Free the socket descriptor */
\r
541 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p calling lpWPUCloseSocketHandle=0x%p\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info, socket_info->switch_socket));
\r
543 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
544 new_socket_info->switch_socket, lpErrno ) == SOCKET_ERROR )
\r
546 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
547 ("WPUCloseSocketHandle failed: %d\n", *lpErrno) );
\r
551 STAT_DEC( wpusocket_num );
\r
554 ib_destroy_socket( new_socket_info );
\r
555 free_socket_info( new_socket_info );
\r
557 *lpErrno = WSAEACCES;
\r
559 new_socket_info = (struct ibsp_socket_info *)INVALID_SOCKET;
\r
562 CL_TRACE_EXIT(IBSP_DBG_CONN, gdbg_lvl,
\r
563 ("returns new SocketID (0x%x)\n", new_socket) );
\r
565 return (SOCKET) new_socket_info;
\r
570 CloseHandle( new_socket_info->info.accept.event );
\r
572 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("wait for ib_accept failed\n") );
\r
574 *lpErrno = WSAEACCES;
\r
575 return INVALID_SOCKET;
\r
583 /* Function: IBSPBind
\r
586 * Bind the socket to a local address.
\r
592 IN const struct sockaddr FAR *name,
\r
594 OUT LPINT lpErrno )
\r
596 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
597 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
598 struct ibsp_port *port;
\r
601 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
603 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
604 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
606 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("Address to bind to:\n") );
\r
607 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );
\r
609 fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));
\r
611 /* Sanity checks */
\r
612 if( namelen != sizeof(struct sockaddr_in) )
\r
614 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
615 ("invalid namelen (%d instead of %d)\n",
\r
616 namelen, sizeof(struct sockaddr_in)) );
\r
617 *lpErrno = WSAEFAULT;
\r
621 if( addr->sin_family != AF_INET )
\r
623 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("bad family for socket\n") );
\r
624 *lpErrno = WSAEFAULT;
\r
628 /* Check if the ip address is assigned to one of our IBoIB HCA. */
\r
629 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
631 port = get_port_from_ip_address( addr->sin_addr );
\r
634 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
635 ("This IP address does not belong to that host (%08x)\n",
\r
636 addr->sin_addr.S_un.S_addr) );
\r
637 *lpErrno = WSAEADDRNOTAVAIL;
\r
646 /* We are going to take this mutex for some time,
\r
647 * but at this stage, it shouldn't impact anything. */
\r
648 cl_spinlock_acquire( &socket_info->event_mutex );
\r
650 /* Verify the state of the socket */
\r
651 if( socket_info->socket_state != IBSP_CREATE )
\r
653 cl_spinlock_release( &socket_info->event_mutex );
\r
654 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
655 ("Invalid socket state (%s)\n",
\r
656 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
657 *lpErrno = WSAEINVAL;
\r
661 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
663 /* Time to allocate our IB QP */
\r
664 socket_info->port = port;
\r
665 ret = ib_create_socket( socket_info );
\r
668 socket_info->port = NULL;
\r
669 cl_spinlock_release( &socket_info->event_mutex );
\r
670 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_create socket failed with %d\n", ret) );
\r
671 *lpErrno = WSAENOBUFS;
\r
677 socket_info->local_addr = *addr;
\r
679 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
681 cl_spinlock_release( &socket_info->event_mutex );
\r
683 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
687 CL_ASSERT( *lpErrno != 0 );
\r
688 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl, ("failed with error %d\n", *lpErrno) );
\r
689 return SOCKET_ERROR;
\r
693 /* Function: IBSPCloseSocket
\r
696 * Close the socket handle of the app socket as well as the provider socket.
\r
697 * However, if there are outstanding async IO requests on the app socket
\r
698 * we only close the provider socket. Only when all the IO requests complete
\r
699 * (with error) will we then close the app socket.
\r
706 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
709 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
711 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
712 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
714 if( s == INVALID_SOCKET )
\r
716 CL_EXIT_ERROR( IBSP_DBG_WQ, gdbg_lvl, ("invalid socket handle %x\n", s) );
\r
717 *lpErrno = WSAENOTSOCK;
\r
718 return SOCKET_ERROR;
\r
721 cl_atomic_inc( &g_ibsp.CloseSocket_count );
\r
724 cl_spinlock_acquire( &socket_info->event_mutex );
\r
727 old_state = socket_info->socket_state;
\r
728 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CLOSING );
\r
730 cl_spinlock_release( &socket_info->event_mutex );
\r
732 shutdown_and_destroy_socket_info( socket_info, old_state );
\r
734 cl_spinlock_acquire( &socket_info->event_mutex );
\r
735 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CLOSED );
\r
736 cl_spinlock_release( &socket_info->event_mutex );
\r
738 /* Take off socket_info_list and put on closed_socket_info_list */
\r
739 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
740 cl_qlist_remove_item( &g_ibsp.socket_info_list, &socket_info->item );
\r
741 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
743 cl_spinlock_acquire( &g_ibsp.closed_socket_info_mutex );
\r
744 cl_qlist_insert_tail( &g_ibsp.closed_socket_info_list, &socket_info->item );
\r
745 cl_spinlock_release( &g_ibsp.closed_socket_info_mutex );
\r
747 /* Notify ib_cleanup_thread() to free this */
\r
748 SetEvent( g_ibsp.ib_cleanup_event );
\r
751 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
758 /* Function: IBSPConnect
\r
761 * Performs a connect call. The only thing we need to do is translate
\r
762 * the socket handle.
\r
767 const struct sockaddr FAR *name,
\r
769 LPWSABUF lpCallerData,
\r
770 LPWSABUF lpCalleeData,
\r
775 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
776 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
778 ib_net64_t dest_port_guid;
\r
779 ib_path_rec_t path_rec;
\r
781 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
783 UNUSED_PARAM( lpCalleeData );
\r
784 UNUSED_PARAM( lpSQOS );
\r
785 UNUSED_PARAM( lpGQOS );
\r
787 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
788 __LINE__, GetCurrentProcessId(),
\r
789 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
791 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl,
\r
792 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );
\r
794 /* Sanity checks */
\r
797 /* We don't support that. The current switch does not use it. */
\r
798 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("lpCallerData.len=%d\n", lpCallerData->len) );
\r
799 *lpErrno = WSAEINVAL;
\r
803 if( namelen < sizeof(struct sockaddr_in) )
\r
805 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
806 ("invalid remote address (%d)\n", socket_info->socket_state) );
\r
807 *lpErrno = WSAEFAULT;
\r
811 /* Check if the name (actually address) of peer entity is correct */
\r
812 if( addr->sin_family != AF_INET ||
\r
813 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )
\r
815 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
816 ("peer entity address is invalid (%d, %d, %x)\n",
\r
817 addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );
\r
818 *lpErrno = WSAEADDRNOTAVAIL;
\r
822 if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )
\r
824 /* Loopback - let the regular stack take care of that. */
\r
825 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Loopback!\n") );
\r
826 *lpErrno = WSAEADDRNOTAVAIL;
\r
830 /* Get the GUID for that IP address. */
\r
831 ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );
\r
834 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
835 ("query_guid_address failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
836 *lpErrno = WSAEADDRNOTAVAIL;
\r
840 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("got GUID %I64x for IP %s\n",
\r
841 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );
\r
843 /* Get the path record */
\r
844 ret = query_pr( socket_info->port, dest_port_guid, &path_rec );
\r
847 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
848 ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
849 *lpErrno = WSAEADDRNOTAVAIL;
\r
853 cl_spinlock_acquire( &socket_info->mutex );
\r
855 /* Verify the state of the socket */
\r
856 switch( socket_info->socket_state )
\r
859 /* Good. That's the only valid state we want. */
\r
862 case IBSP_CONNECTED:
\r
863 cl_spinlock_release( &socket_info->mutex );
\r
864 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Socket is already connected\n") );
\r
865 *lpErrno = WSAEISCONN;
\r
870 cl_spinlock_release( &socket_info->mutex );
\r
871 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Socket is a listening socket\n") );
\r
872 *lpErrno = WSAEINVAL;
\r
876 cl_spinlock_release( &socket_info->mutex );
\r
877 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
878 ("Socket is not in the bound state (%s)\n",
\r
879 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
880 *lpErrno = WSAEINVAL;
\r
885 /* Store the peer entity's address in socket context */
\r
886 socket_info->peer_addr = *addr;
\r
888 /* Update the socket state */
\r
889 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );
\r
891 cl_spinlock_release( &socket_info->mutex );
\r
894 ret = ib_connect( socket_info, &path_rec, lpErrno );
\r
897 cl_spinlock_acquire( &socket_info->mutex );
\r
899 if( socket_info->socket_state == IBSP_CONNECT )
\r
901 /* We must be sure none destroyed our socket */
\r
902 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
903 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );
\r
906 cl_spinlock_release( &socket_info->mutex );
\r
908 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_connect failed (%d)\n", ret) );
\r
910 *lpErrno = WSAEHOSTUNREACH;
\r
914 /* Operation is pending */
\r
915 *lpErrno = WSAEWOULDBLOCK;
\r
918 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
919 return SOCKET_ERROR;
\r
923 /* Function: IBSPDuplicateSocket
\r
926 This function provides a WSAPROTOCOL_INFOW structure which can be passed
\r
927 to another process to open a handle to the same socket. First we need
\r
928 to translate the user socket into the provider socket and call the underlying
\r
929 WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us
\r
930 is an out parameter only!
\r
933 IBSPDuplicateSocket(
\r
936 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
939 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
942 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
944 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
945 __LINE__, GetCurrentProcessId(),
\r
946 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
948 cl_spinlock_acquire( &socket_info->mutex );
\r
949 if( socket_info->socket_state != IBSP_CONNECTED )
\r
951 cl_spinlock_release( &socket_info->mutex );
\r
952 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl,
\r
953 ("Socket state not IBSP_CONNECTED, state=%s.\n",
\r
954 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
955 *lpErrno = WSAENOTCONN;
\r
956 return SOCKET_ERROR;
\r
958 cl_spinlock_release( &socket_info->mutex );
\r
960 ret = prepare_duplicate_socket( socket_info, dwProcessId );
\r
963 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl,
\r
964 ("prepare_duplicate_socket failed with %d\n", ret) );
\r
966 return SOCKET_ERROR;
\r
970 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
971 lpProtocolInfo->dwProviderReserved = socket_info->duplicate.identifier;
\r
978 /* Function: IBSPEnumNetworkEvents
\r
981 * Enumerate the network events for a socket. We only need to
\r
982 * translate the socket handle.
\r
985 IBSPEnumNetworkEvents(
\r
987 WSAEVENT hEventObject,
\r
988 LPWSANETWORKEVENTS lpNetworkEvents,
\r
991 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
993 CL_ENTER( IBSP_DBG_NEV, gdbg_lvl );
\r
995 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
996 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
998 cl_spinlock_acquire( &socket_info->event_mutex );
\r
1000 lpNetworkEvents->lNetworkEvents = 0;
\r
1002 if( socket_info->network_events & FD_ACCEPT )
\r
1004 CL_TRACE( IBSP_DBG_NEV, gdbg_lvl, ("FD_ACCEPT\n") );
\r
1005 lpNetworkEvents->lNetworkEvents |= FD_ACCEPT;
\r
1006 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = socket_info->errno_accept;
\r
1009 if( socket_info->network_events & FD_CONNECT )
\r
1011 CL_TRACE( IBSP_DBG_NEV, gdbg_lvl, ("FD_CONNECT\n") );
\r
1012 lpNetworkEvents->lNetworkEvents |= FD_CONNECT;
\r
1013 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;
\r
1016 socket_info->network_events = 0;
\r
1018 ResetEvent( hEventObject );
\r
1020 cl_spinlock_release( &socket_info->event_mutex );
\r
1022 CL_TRACE_EXIT( IBSP_DBG_NEV, gdbg_lvl,
\r
1023 ("returning %x, accept=%d, connect=%d\n",
\r
1024 lpNetworkEvents->lNetworkEvents,
\r
1025 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT],
\r
1026 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT]) );
\r
1033 /* Function: IBSPEventSelect
\r
1036 * Register the specified events on the socket with the given event handle.
\r
1037 * All we need to do is translate the socket handle.
\r
1042 WSAEVENT hEventObject,
\r
1043 long lNetworkEvents,
\r
1046 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1048 CL_ENTER( IBSP_DBG_NEV, gdbg_lvl );
\r
1050 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1051 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1053 if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )
\r
1055 CL_TRACE_EXIT(IBSP_DBG_NEV, gdbg_lvl,
\r
1056 ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );
\r
1057 *lpErrno = WSAEINVAL;
\r
1058 return SOCKET_ERROR;
\r
1061 CL_ASSERT( (hEventObject == NULL && socket_info->event_select != NULL) ||
\r
1062 (hEventObject != NULL && socket_info->event_select == NULL) );
\r
1063 CL_ASSERT( lpErrno );
\r
1065 if( hEventObject )
\r
1066 socket_info->event_select = hEventObject;
\r
1067 socket_info->event_mask = lNetworkEvents;
\r
1069 CL_EXIT( IBSP_DBG_NEV, gdbg_lvl );
\r
1074 /* Function: IBSPGetOverlappedResult
\r
1077 * This function reports whether the specified overlapped call has
\r
1078 * completed. If it has, return the requested information. If not,
\r
1079 * and fWait is true, wait until completion. Otherwise return an
\r
1080 * error immediately.
\r
1082 static BOOL WSPAPI
\r
1083 IBSPGetOverlappedResult(
\r
1085 IN LPWSAOVERLAPPED lpOverlapped,
\r
1086 OUT LPDWORD lpcbTransfer,
\r
1088 OUT LPDWORD lpdwFlags,
\r
1089 OUT LPINT lpErrno )
\r
1091 struct ibsp_socket_info *p_socket_info;
\r
1094 IBSP_ENTER( IBSP_DBG_IO );
\r
1096 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p Internal=%d InternalHigh=%d OffsetHigh=%d hEvent=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, lpOverlapped->Internal, lpOverlapped->InternalHigh, lpOverlapped->OffsetHigh, lpOverlapped->hEvent));
\r
1098 CL_ASSERT( fWait == FALSE );
\r
1099 if( fWait == TRUE )
\r
1101 IBSP_ERROR_EXIT( ("fWait not supported\n") );
\r
1102 *lpErrno = WSAENETDOWN;
\r
1106 if( s == INVALID_SOCKET )
\r
1108 /* Seen in real life with overlap/client test.
\r
1109 * The switch closes a socket then calls this. Why? */
\r
1110 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1111 *lpErrno = WSAENOTSOCK;
\r
1112 return SOCKET_ERROR;
\r
1115 if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )
\r
1117 p_socket_info = (struct ibsp_socket_info*)s;
\r
1118 /* Poll just in case it's done. */
\r
1119 ib_cq_comp( p_socket_info->cq_tinfo );
\r
1122 if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )
\r
1124 /* Operation has completed, perhaps with error */
\r
1125 *lpdwFlags = lpOverlapped->Offset;
\r
1126 *lpErrno = lpOverlapped->OffsetHigh;
\r
1129 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )
\r
1131 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1133 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1134 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
1135 lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1136 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1139 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p completed overlap=0x%x overlap_h0_count=%d overlap_h1_count=%d\n", __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count));
\r
1141 IBSP_TRACE1( IBSP_DBG_IO,
\r
1142 ("socket=%p completed ov=%p\n", s, lpOverlapped) );
\r
1146 /* Operation is still in progress */
\r
1147 *lpErrno = WSA_IO_INCOMPLETE;
\r
1148 IBSP_TRACE1( IBSP_DBG_IO,
\r
1149 ("socket=%p ov=%p hEvent=%p, operation in progress\n",
\r
1150 s, lpOverlapped, lpOverlapped->hEvent));
\r
1153 *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;
\r
1155 if( *lpErrno == 0 )
\r
1160 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",
\r
1161 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1162 lpOverlapped, *lpErrno, rc));
\r
1164 IBSP_EXIT( IBSP_DBG_IO );
\r
1169 /* Function: IBSPGetSockOpt
\r
1172 * Get the specified socket option. All we need to do is translate the
\r
1184 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1186 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
1188 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1189 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1191 if( level != SOL_SOCKET )
\r
1193 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid level %d", level) );
\r
1194 *lpErrno = WSAENOPROTOOPT;
\r
1195 return SOCKET_ERROR;
\r
1198 if( optval == NULL || optlen == NULL )
\r
1200 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1201 ("invalid optval=%p or optlen=%p", optval, optlen) );
\r
1202 *lpErrno = WSAEFAULT;
\r
1203 return SOCKET_ERROR;
\r
1209 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_DEBUG\n") );
\r
1210 if( *optlen < sizeof(BOOL) )
\r
1212 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1213 ("option len is invalid (0x%x)\n", *optlen) );
\r
1214 *optlen = sizeof(BOOL);
\r
1215 *lpErrno = WSAEFAULT;
\r
1216 return SOCKET_ERROR;
\r
1219 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );
\r
1220 *optlen = sizeof(BOOL);
\r
1224 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_ID\n") );
\r
1225 if( *optlen < sizeof(GROUP) )
\r
1227 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1228 ("option len is invalid (0x%x)\n", *optlen) );
\r
1229 *optlen = sizeof(GROUP);
\r
1230 *lpErrno = WSAEFAULT;
\r
1231 return SOCKET_ERROR;
\r
1234 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );
\r
1235 *optlen = sizeof(GROUP);
\r
1238 case SO_GROUP_PRIORITY:
\r
1239 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_PRIORITY\n") );
\r
1241 if( *optlen < sizeof(int) )
\r
1243 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1244 ("option len is invalid (0x%x)\n", *optlen) );
\r
1245 *optlen = sizeof(int);
\r
1246 *lpErrno = WSAEFAULT;
\r
1247 return SOCKET_ERROR;
\r
1250 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );
\r
1251 *optlen = sizeof(int);
\r
1254 case SO_MAX_MSG_SIZE:
\r
1255 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_MAX_MSG_SIZE\n") );
\r
1257 if( *optlen < sizeof(unsigned int) )
\r
1259 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1260 ("option len is invalid (0x%x)\n", *optlen) );
\r
1261 *optlen = sizeof(unsigned int);
\r
1262 *lpErrno = WSAEFAULT;
\r
1263 return SOCKET_ERROR;
\r
1266 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );
\r
1267 *optlen = sizeof(unsigned int);
\r
1270 case SO_MAX_RDMA_SIZE:
\r
1271 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_MAX_RDMA_SIZE\n") );
\r
1273 if( *optlen < sizeof(unsigned int) )
\r
1275 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1276 ("option len is invalid (0x%x)\n", *optlen) );
\r
1277 *optlen = sizeof(unsigned int);
\r
1278 *lpErrno = WSAEFAULT;
\r
1279 return SOCKET_ERROR;
\r
1282 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );
\r
1283 *optlen = sizeof(unsigned int);
\r
1286 case SO_RDMA_THRESHOLD_SIZE:
\r
1287 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );
\r
1289 if( *optlen < sizeof(unsigned int) )
\r
1291 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1292 ("option len is invalid (0x%x)\n", *optlen) );
\r
1293 *optlen = sizeof(unsigned int);
\r
1294 *lpErrno = WSAEFAULT;
\r
1295 return SOCKET_ERROR;
\r
1298 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,
\r
1299 sizeof(unsigned int) );
\r
1300 *optlen = sizeof(unsigned int);
\r
1304 *lpErrno = WSAENOPROTOOPT;
\r
1306 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("unknown option 0x%x\n", optname) );
\r
1308 return SOCKET_ERROR;
\r
1312 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
1317 /* Function: IBSPGetQOSByName
\r
1320 * Get a QOS template by name. All we need to do is translate the socket
\r
1323 static BOOL WSPAPI
\r
1326 LPWSABUF lpQOSName,
\r
1330 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
1332 UNUSED_PARAM( s );
\r
1333 UNUSED_PARAM( lpQOSName );
\r
1334 UNUSED_PARAM( lpQOS );
\r
1336 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1337 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1339 *lpErrno = WSAEOPNOTSUPP;
\r
1341 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("not supported\n") );
\r
1347 /* Function: IBSPIoctl
\r
1350 * Invoke an ioctl. In most cases, we just need to translate the socket
\r
1351 * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,
\r
1352 * we'll need to intercept this and return our own function pointers.
\r
1357 IN DWORD dwIoControlCode,
\r
1358 IN LPVOID lpvInBuffer,
\r
1359 IN DWORD cbInBuffer,
\r
1360 OUT LPVOID lpvOutBuffer,
\r
1361 IN DWORD cbOutBuffer,
\r
1362 OUT LPDWORD lpcbBytesReturned,
\r
1363 IN LPWSAOVERLAPPED lpOverlapped,
\r
1364 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1365 IN LPWSATHREADID lpThreadId,
\r
1366 OUT LPINT lpErrno )
\r
1368 struct ibsp_socket_info *socket_info;
\r
1369 GUID SANRegisterMemory = WSAID_REGISTERMEMORY;
\r
1370 GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;
\r
1371 GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;
\r
1372 GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;
\r
1373 GUID SANRDMAWrite = WSAID_RDMAWRITE;
\r
1374 GUID SANRDMARead = WSAID_RDMAREAD;
\r
1375 GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;
\r
1377 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
1379 UNUSED_PARAM( cbInBuffer );
\r
1380 UNUSED_PARAM( lpOverlapped );
\r
1381 UNUSED_PARAM( lpCompletionRoutine );
\r
1382 UNUSED_PARAM( lpThreadId );
\r
1384 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p\n", __FUNCTION__,
\r
1385 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1387 if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )
\r
1389 /* This a special case. The socket handle passed is not valid. */
\r
1390 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Get extension function pointer\n") );
\r
1392 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )
\r
1394 /* Return a pointer to our intermediate extension function */
\r
1395 *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;
\r
1397 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )
\r
1399 /* Return a pointer to our intermediate extension function */
\r
1400 *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;
\r
1402 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1404 /* Return a pointer to our intermediate extension function */
\r
1405 *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;
\r
1407 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1409 /* Return a pointer to our intermediate extension function */
\r
1410 *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;
\r
1412 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )
\r
1414 /* Return a pointer to our intermediate extension function */
\r
1415 *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;
\r
1417 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )
\r
1421 *lpErrno = WSAEOPNOTSUPP;
\r
1422 return SOCKET_ERROR;
\r
1426 /* Return a pointer to our intermediate extension function */
\r
1427 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;
\r
1430 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,
\r
1431 sizeof(GUID) ) == 0 )
\r
1433 /* Return a pointer to our intermediate extension function */
\r
1434 *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =
\r
1435 IBSPMemoryRegistrationCacheCallback;
\r
1439 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid extension GUID\n") );
\r
1440 *lpErrno = WSAEINVAL;
\r
1441 return SOCKET_ERROR;
\r
1446 socket_info = (struct ibsp_socket_info *)s;
\r
1448 /* Verify the state of the socket */
\r
1449 /* Not sure which state socket should be in to receive this call */
\r
1450 DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,
\r
1455 cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );
\r
1457 switch( dwIoControlCode )
\r
1460 case SIO_GET_GROUP_QOS:
\r
1462 case SIO_SET_GROUP_QOS:
\r
1463 /* We don't support that. dwServiceFlags1 in installSP
\r
1465 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1466 ("unsupported dwIoControlCode %d\n", dwIoControlCode) );
\r
1467 *lpErrno = WSAENOPROTOOPT;
\r
1468 return SOCKET_ERROR;
\r
1471 case SIO_ADDRESS_LIST_QUERY:
\r
1475 *lpcbBytesReturned = cbOutBuffer;
\r
1476 ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,
\r
1477 lpcbBytesReturned, lpErrno );
\r
1479 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
1485 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1486 ("invalid dwIoControlCode %d\n", dwIoControlCode) );
\r
1488 *lpErrno = WSAENOPROTOOPT;
\r
1489 return SOCKET_ERROR;
\r
1497 /* Function: IBSPListen
\r
1500 * This function establishes a socket to listen for incoming connections. It sets
\r
1501 * the backlog value on a listening socket.
\r
1509 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1512 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
1514 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1515 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1517 cl_spinlock_acquire( &socket_info->mutex );
\r
1519 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("socket_state is %s\n",
\r
1520 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1522 /* Verify the state of the socket */
\r
1523 switch( socket_info->socket_state )
\r
1527 /* Store the backlog value in the context */
\r
1528 socket_info->info.listen.backlog = backlog;
\r
1529 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );
\r
1531 socket_info->info.listen.listen_req_param.dwProcessId = 0;
\r
1532 socket_info->info.listen.listen_req_param.identifier = 0;
\r
1534 ret = ib_listen( socket_info, lpErrno );
\r
1537 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
1538 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_listen failed with %d\n", ret) );
\r
1548 /* Change the backlog */
\r
1549 socket_info->info.listen.backlog = backlog;
\r
1554 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
1555 ("Invalid socket_state (%s)\n",
\r
1556 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1557 *lpErrno = WSAEINVAL;
\r
1561 cl_spinlock_release( &socket_info->mutex );
\r
1563 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
1566 return SOCKET_ERROR;
\r
1572 /* Function: IBSPRecv
\r
1575 * This function receives data on a given socket and also allows for asynchronous
\r
1576 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1577 * handle and then make the receive call. If called with overlap, post the operation
\r
1578 * to our IOCP or completion routine.
\r
1583 LPWSABUF lpBuffers,
\r
1584 DWORD dwBufferCount,
\r
1585 LPDWORD lpNumberOfBytesRecvd,
\r
1587 LPWSAOVERLAPPED lpOverlapped,
\r
1588 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1589 LPWSATHREADID lpThreadId,
\r
1592 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1593 ib_api_status_t status;
\r
1594 struct memory_node *node;
\r
1595 struct _recv_wr *wr;
\r
1598 IBSP_ENTER( IBSP_DBG_IO );
\r
1600 UNUSED_PARAM( lpNumberOfBytesRecvd );
\r
1601 UNUSED_PARAM( lpCompletionRoutine );
\r
1602 UNUSED_PARAM( lpThreadId );
\r
1604 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1605 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1607 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1608 CL_ASSERT( lpOverlapped != NULL );
\r
1610 if( s == INVALID_SOCKET )
\r
1612 /* Seen in real life with overlap/client test.
\r
1613 * The switch closes a socket then calls this. Why? */
\r
1614 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1615 *lpErrno = WSAENOTSOCK;
\r
1616 return SOCKET_ERROR;
\r
1619 /* Check the state of the socket */
\r
1620 if( socket_info->socket_state != IBSP_CONNECTED )
\r
1623 ("Socket is not in connected socket_state state=%s\n",
\r
1624 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1625 *lpErrno = WSAENOTCONN;
\r
1626 return SOCKET_ERROR;
\r
1629 if( socket_info->qp_error != 0 )
\r
1632 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1633 *lpErrno = socket_info->qp_error;
\r
1634 return SOCKET_ERROR;
\r
1637 /* This function only works for that case. Right now the switch is
\r
1638 * only using that. */
\r
1639 if( dwBufferCount > QP_ATTRIB_RQ_SGE )
\r
1641 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );
\r
1643 ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );
\r
1644 *lpErrno = WSAEINVAL;
\r
1645 return SOCKET_ERROR;
\r
1648 cl_spinlock_acquire( &socket_info->recv_lock );
\r
1649 if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )
\r
1651 /* This should never happen */
\r
1652 cl_spinlock_release( &socket_info->recv_lock );
\r
1653 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1654 *lpErrno = WSAENETDOWN;
\r
1655 return SOCKET_ERROR;
\r
1658 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
1660 wr->wr.lpOverlapped = lpOverlapped;
\r
1661 wr->wr.socket_info = socket_info;
\r
1663 /* Looks good. Post the receive buffer. */
\r
1664 wr->recv.p_next = NULL;
\r
1665 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
1666 wr->recv.num_ds = dwBufferCount;
\r
1667 wr->recv.ds_array = wr->ds_array;
\r
1669 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1671 /* Get the memory region node */
\r
1672 node = lookup_partial_mr( &socket_info->buf_mem_list, IB_AC_LOCAL_WRITE,
\r
1673 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1676 cl_spinlock_release( &socket_info->recv_lock );
\r
1678 * No mr fits. This should never happen. This error is not
\r
1679 * official, but seems to be the closest.
\r
1681 IBSP_ERROR_EXIT( ("no MR found\n") );
\r
1682 *lpErrno = WSAEFAULT;
\r
1683 return SOCKET_ERROR;
\r
1686 wr->ds_array[ds_idx].vaddr =
\r
1687 (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1688 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;
\r
1689 wr->ds_array[ds_idx].lkey = node->lkey;
\r
1693 * We must set this now, because the operation could complete
\r
1694 * before ib_post_Recv returns.
\r
1696 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1698 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1699 lpOverlapped->Offset = *lpFlags;
\r
1701 cl_atomic_inc( &socket_info->recv_cnt );
\r
1704 if( lpOverlapped->hEvent == 0 )
\r
1706 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1710 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1711 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1714 cl_atomic_inc( &g_ibsp.recv_count );
\r
1716 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1717 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1718 GetCurrentThreadId(), lpOverlapped,
\r
1719 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1720 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1726 fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",
\r
1727 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1728 lpOverlapped, wr));
\r
1730 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
1732 if( status == IB_SUCCESS )
\r
1734 /* Update the index and wrap as needed */
\r
1735 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
1736 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
1737 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
1738 socket_info->recv_idx++;
\r
1739 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
1741 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
1742 socket_info->recv_idx = 0;
\r
1745 IBSP_TRACE1( IBSP_DBG_IO,
\r
1746 ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1747 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1749 *lpErrno = WSA_IO_PENDING;
\r
1754 ("ib_post_recv returned %s\n", ib_get_err_str( status )) );
\r
1756 if( lpOverlapped->hEvent == 0 )
\r
1758 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1762 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1763 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1766 cl_atomic_dec( &g_ibsp.recv_count );
\r
1768 memset( wr, 0x33, sizeof(struct _recv_wr) );
\r
1771 cl_atomic_dec( &socket_info->recv_cnt );
\r
1772 *lpErrno = ibal_to_wsa_error( status );
\r
1775 cl_spinlock_release( &socket_info->recv_lock );
\r
1777 /* We never complete the operation here. */
\r
1778 IBSP_EXIT( IBSP_DBG_IO );
\r
1779 return SOCKET_ERROR;
\r
1783 /* Function: IBSPSend
\r
1786 * This function sends data on a given socket and also allows for asynchronous
\r
1787 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1788 * handle and then make the send call.
\r
1793 IN LPWSABUF lpBuffers,
\r
1794 IN DWORD dwBufferCount,
\r
1795 OUT LPDWORD lpNumberOfBytesSent,
\r
1797 IN LPWSAOVERLAPPED lpOverlapped,
\r
1798 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1799 IN LPWSATHREADID lpThreadId,
\r
1800 OUT LPINT lpErrno )
\r
1802 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1803 ib_api_status_t status;
\r
1804 struct memory_node *node;
\r
1806 ib_send_wr_t send_wr;
\r
1807 ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE];
\r
1810 IBSP_ENTER( IBSP_DBG_IO );
\r
1812 UNUSED_PARAM( lpNumberOfBytesSent );
\r
1813 UNUSED_PARAM( lpCompletionRoutine );
\r
1814 UNUSED_PARAM( lpThreadId );
\r
1816 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,
\r
1817 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1819 if( s == INVALID_SOCKET )
\r
1821 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1822 *lpErrno = WSAENOTSOCK;
\r
1823 return SOCKET_ERROR;
\r
1826 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1827 CL_ASSERT( lpOverlapped != NULL );
\r
1829 /* Check the state of the socket */
\r
1830 if( socket_info->socket_state != IBSP_CONNECTED )
\r
1832 IBSP_ERROR_EXIT( ("Socket is not in connected socket_state \n") );
\r
1833 *lpErrno = WSAENOTCONN;
\r
1834 return SOCKET_ERROR;
\r
1837 if( socket_info->qp_error )
\r
1840 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1841 *lpErrno = socket_info->qp_error;
\r
1842 return SOCKET_ERROR;
\r
1845 /* This function only works for that case. */
\r
1846 if( dwBufferCount > QP_ATTRIB_SQ_SGE )
\r
1848 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );
\r
1850 ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );
\r
1851 *lpErrno = WSAEINVAL;
\r
1852 return SOCKET_ERROR;
\r
1855 /* The send lock is only used to serialize posting. */
\r
1856 cl_spinlock_acquire( &socket_info->send_lock );
\r
1857 if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )
\r
1859 /* This should never happen */
\r
1860 cl_spinlock_release( &socket_info->send_lock );
\r
1861 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1862 *lpErrno = WSAENETDOWN;
\r
1863 return SOCKET_ERROR;
\r
1866 wr = &socket_info->send_wr[socket_info->send_idx];
\r
1868 wr->lpOverlapped = lpOverlapped;
\r
1869 wr->socket_info = socket_info;
\r
1871 /* Looks good. Post the send buffer. */
\r
1872 send_wr.p_next = NULL;
\r
1873 send_wr.wr_id = (uint64_t) (uintptr_t) wr;
\r
1874 send_wr.wr_type = WR_SEND;
\r
1875 send_wr.send_opt = socket_info->send_opt;
\r
1876 socket_info->send_opt = 0;
\r
1878 send_wr.num_ds = dwBufferCount;
\r
1879 send_wr.ds_array = local_ds;
\r
1881 lpOverlapped->InternalHigh = 0;
\r
1882 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1884 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1885 local_ds[ds_idx].length = lpBuffers[ds_idx].len;
\r
1887 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;
\r
1890 if( lpOverlapped->InternalHigh <= socket_info->max_inline )
\r
1892 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1896 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1898 /* Get the memory region node */
\r
1899 node = lookup_partial_mr( &socket_info->buf_mem_list, 0, /* READ */
\r
1900 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1903 cl_spinlock_release( &socket_info->send_lock );
\r
1905 * No mr fits. This error is not official, but seems to be the
\r
1908 IBSP_ERROR_EXIT( ("mr lookup failed\n") );
\r
1909 *lpErrno = WSAEFAULT;
\r
1910 return SOCKET_ERROR;
\r
1913 local_ds[ds_idx].lkey = node->lkey;
\r
1918 * We must set this now, because the operation could complete
\r
1919 * before ib_post_send returns.
\r
1921 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1923 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1924 lpOverlapped->Offset = dwFlags;
\r
1926 cl_atomic_inc( &socket_info->send_cnt );
\r
1929 if( lpOverlapped->hEvent == 0)
\r
1931 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1935 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1936 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1939 cl_atomic_inc( &g_ibsp.send_count );
\r
1941 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1942 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1943 GetCurrentThreadId(), lpOverlapped,
\r
1944 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1945 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1951 fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",
\r
1953 __LINE__, GetCurrentProcessId(),
\r
1954 GetCurrentThreadId(),
\r
1955 lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));
\r
1958 if( lpBuffers[0].len >= 40 )
\r
1960 debug_dump_buffer( IBSP_DBG_WQ, gdbg_lvl, "SEND", lpBuffers[0].buf, 40 );
\r
1964 status = ib_post_send( socket_info->qp, &send_wr, NULL );
\r
1966 if( status == IB_SUCCESS )
\r
1968 /* Update the index and wrap as needed */
\r
1969 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \
\r
1970 QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \
\r
1971 QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8
\r
1972 socket_info->send_idx++;
\r
1973 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);
\r
1975 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )
\r
1976 socket_info->send_idx = 0;
\r
1980 IBSP_TRACE1( IBSP_DBG_IO,
\r
1981 ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1982 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1984 *lpErrno = WSA_IO_PENDING;
\r
1988 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );
\r
1991 if( lpOverlapped->hEvent == 0 )
\r
1993 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1997 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1998 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
2000 cl_atomic_dec( &g_ibsp.send_count );
\r
2002 memset( wr, 0x37, sizeof(struct _wr) );
\r
2004 cl_atomic_dec( &socket_info->send_cnt );
\r
2006 *lpErrno = ibal_to_wsa_error( status );
\r
2008 cl_spinlock_release( &socket_info->send_lock );
\r
2010 /* We never complete the operation here. */
\r
2011 IBSP_EXIT( IBSP_DBG_IO );
\r
2012 return SOCKET_ERROR;
\r
2016 /* Function: IBSPSetSockOpt
\r
2019 * Set a socket option. For most all options we just have to translate the
\r
2020 * socket option and call the lower provider. The only special case is for
\r
2021 * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the
\r
2022 * argument which we need to translate before calling the lower provider.
\r
2029 const char FAR *optval,
\r
2033 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
2035 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
2037 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2038 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
2040 if( level != SOL_SOCKET )
\r
2042 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid level %d", level) );
\r
2043 *lpErrno = WSAENOPROTOOPT;
\r
2044 return SOCKET_ERROR;
\r
2047 if( optval == NULL )
\r
2049 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid optval=%p", optval) );
\r
2050 *lpErrno = WSAEFAULT;
\r
2051 return SOCKET_ERROR;
\r
2057 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_DEBUG\n") );
\r
2058 if( optlen != sizeof(BOOL) )
\r
2060 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
2061 ("option len is invalid (0x%x)\n", optlen) );
\r
2062 *lpErrno = WSAEFAULT;
\r
2063 return SOCKET_ERROR;
\r
2065 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );
\r
2068 case SO_GROUP_PRIORITY:
\r
2069 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_PRIORITY\n") );
\r
2070 if( optlen != sizeof(int) )
\r
2072 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
2073 ("option len is invalid (0x%x)\n", optlen) );
\r
2074 *lpErrno = WSAEFAULT;
\r
2075 return SOCKET_ERROR;
\r
2077 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );
\r
2081 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid option %x\n", optname) );
\r
2082 *lpErrno = WSAENOPROTOOPT;
\r
2083 return SOCKET_ERROR;
\r
2087 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
2093 /* Function: IBSPSocket
\r
2096 * This function creates a socket. There are two sockets created. The first
\r
2097 * socket is created by calling the lower providers WSPSocket. This is the
\r
2098 * handle that we use internally within our LSP. We then create a second
\r
2099 * socket with WPUCreateSocketHandle which will be returned to the calling
\r
2100 * application. We will also create a socket context structure which will
\r
2101 * maintain information on each socket. This context is associated with the
\r
2102 * socket handle passed to the application.
\r
2104 static SOCKET WSPAPI
\r
2109 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2114 struct ibsp_socket_info *socket_info = NULL;
\r
2116 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
2118 UNUSED_PARAM( g );
\r
2120 if( af != AF_INET )
\r
2122 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2123 ("bad family %d instead of %d\n", af, AF_INET) );
\r
2124 *lpErrno = WSAEAFNOSUPPORT;
\r
2128 if( type != SOCK_STREAM )
\r
2130 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2131 ("bad type %d instead of %d\n", type, SOCK_STREAM) );
\r
2132 *lpErrno = WSAEPROTOTYPE;
\r
2136 if( protocol != IPPROTO_TCP )
\r
2138 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2139 ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );
\r
2140 *lpErrno = WSAEPROTONOSUPPORT;
\r
2144 if( (dwFlags != WSA_FLAG_OVERLAPPED) )
\r
2146 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2147 ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );
\r
2148 *lpErrno = WSAEINVAL;
\r
2152 socket_info = create_socket_info();
\r
2153 if( socket_info == NULL )
\r
2155 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("create_socket_info return NULL\n") );
\r
2156 *lpErrno = WSAENOBUFS;
\r
2160 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2162 /* This is a duplicate socket. */
\r
2165 ret = setup_duplicate_socket( socket_info, lpProtocolInfo->dwProviderReserved );
\r
2168 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2169 ("setup_duplicate_socket failed with %d\n",ret) );
\r
2176 socket_info->switch_socket =
\r
2177 g_ibsp.up_call_table.lpWPUCreateSocketHandle( 0,
\r
2178 (DWORD_PTR) socket_info,
\r
2181 if( socket_info->switch_socket != INVALID_SOCKET )
\r
2183 fzprint(("%s():%d:0x%x:0x%x: socket_info=0x%p switch_socket=0x%p \n",
\r
2184 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
2185 socket_info, socket_info->switch_socket));
\r
2187 STAT_INC( wpusocket_num );
\r
2191 if( socket_info->switch_socket == INVALID_SOCKET )
\r
2193 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
2194 ("WPUCreateSocketHandle() failed: %d\n", *lpErrno) );
\r
2195 /* lpErrno has just been set */
\r
2200 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2202 CL_ASSERT( socket_info->socket_state == IBSP_CONNECTED );
\r
2206 socket_info->socket_state = IBSP_CREATE;
\r
2208 /* Set the (non-zero) default socket options for that socket */
\r
2209 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;
\r
2210 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;
\r
2211 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;
\r
2214 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
2215 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );
\r
2216 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
2220 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2221 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
2223 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl,
\r
2224 ("returning socket handle %p\n", socket_info) );
\r
2226 return (SOCKET) socket_info;
\r
2230 free_socket_info( socket_info );
\r
2232 CL_ASSERT( *lpErrno != 0 );
\r
2234 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Returning error %d\n", *lpErrno) );
\r
2236 return INVALID_SOCKET;
\r
2240 /* Function: IBSPCleanup
\r
2243 * Decrement the entry count. If equal to zero then we can prepare to have us
\r
2244 * unloaded. Close any outstanding sockets and free up allocated memory.
\r
2252 CL_ENTER( IBSP_DBG_INIT, gdbg_lvl );
\r
2254 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2256 if( !g_ibsp.entry_count )
\r
2258 cl_spinlock_release( &g_ibsp.mutex );
\r
2260 *lpErrno = WSANOTINITIALISED;
\r
2262 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl, ("returning WSAENOTINITIALISED\n") );
\r
2264 return SOCKET_ERROR;
\r
2267 /* Decrement the entry count */
\r
2268 g_ibsp.entry_count--;
\r
2270 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("WSPCleanup: %d\n", g_ibsp.entry_count) );
\r
2272 if( g_ibsp.entry_count == 0 )
\r
2274 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("entry_count is 0 => cleaning up\n") );
\r
2278 cl_spinlock_release( &g_ibsp.mutex );
\r
2280 CL_EXIT( IBSP_DBG_INIT, gdbg_lvl );
\r
2287 * Function: WSPStartupEx
\r
2290 * This function intializes the service provider. We maintain a ref count to keep track
\r
2291 * of how many times this function has been called.
\r
2296 LPWSPDATA lpWSPData,
\r
2297 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2298 LPWSPUPCALLTABLEEX UpCallTable,
\r
2299 LPWSPPROC_TABLE lpProcTable )
\r
2301 static WSPPROC_TABLE gProcTable;
\r
2302 static WSPDATA gWSPData;
\r
2304 CL_ENTER( IBSP_DBG_INIT, gdbg_lvl );
\r
2306 /* Make sure that the version requested is >= 2.2. The low byte is the
\r
2307 major version and the high byte is the minor version. */
\r
2308 if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )
\r
2310 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl,
\r
2311 ("Invalid winsock version requested %x\n", wVersion) );
\r
2313 return WSAVERNOTSUPPORTED;
\r
2316 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("entry_count=%d)\n", g_ibsp.entry_count) );
\r
2318 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2320 if( g_ibsp.entry_count == 0 )
\r
2324 /* Save the global WSPData */
\r
2325 gWSPData.wVersion = MAKEWORD(2, 2);
\r
2326 gWSPData.wHighVersion = MAKEWORD(2, 2);
\r
2327 wcscpy( gWSPData.szDescription, Description );
\r
2329 /* provide Service provider's entry points in proc table */
\r
2330 memset( &gProcTable, 0, sizeof(gProcTable) );
\r
2331 gProcTable.lpWSPAccept = IBSPAccept;
\r
2332 gProcTable.lpWSPBind = IBSPBind;
\r
2333 gProcTable.lpWSPCleanup = IBSPCleanup;
\r
2334 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;
\r
2335 gProcTable.lpWSPConnect = IBSPConnect;
\r
2336 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;
\r
2337 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;
\r
2338 gProcTable.lpWSPEventSelect = IBSPEventSelect;
\r
2339 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;
\r
2340 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;
\r
2341 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;
\r
2342 gProcTable.lpWSPIoctl = IBSPIoctl;
\r
2343 gProcTable.lpWSPListen = IBSPListen;
\r
2344 gProcTable.lpWSPRecv = IBSPRecv;
\r
2345 gProcTable.lpWSPSend = IBSPSend;
\r
2346 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;
\r
2347 gProcTable.lpWSPSocket = IBSPSocket;
\r
2349 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */
\r
2350 lpWSPData->wVersion = MAKEWORD(2, 2);
\r
2351 lpWSPData->wHighVersion = MAKEWORD(2, 2);
\r
2352 wcscpy( lpWSPData->szDescription, Description );
\r
2355 /* TODO: remove? */
\r
2356 cl_qlist_init( &g_ibsp.cq_thread_info_list );
\r
2357 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );
\r
2360 g_ibsp.protocol_info = *lpProtocolInfo;
\r
2362 /* Initialize Infiniband */
\r
2363 ret = ibsp_initialize();
\r
2366 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl,
\r
2367 ("ibsp_initialize failed (%d)\n", ret) );
\r
2371 g_ibsp.entry_count++;
\r
2373 cl_spinlock_release( &g_ibsp.mutex );
\r
2375 /* Set the return parameters */
\r
2376 *lpWSPData = gWSPData;
\r
2377 *lpProcTable = gProcTable;
\r
2379 /* store the upcall function table */
\r
2380 g_ibsp.up_call_table = *UpCallTable;
\r
2382 CL_EXIT( IBSP_DBG_INIT, gdbg_lvl );
\r