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
50 uint32_t g_max_inline = 0xFFFFFFFF;
\r
56 * Provides initialization when the ibspdll DLL is loaded.
\r
60 IN HINSTANCE hinstDll,
\r
62 IN LPVOID lpvReserved )
\r
67 CL_ENTER( IBSP_DBG_DLL, gdbg_lvl );
\r
69 UNUSED_PARAM( hinstDll );
\r
70 UNUSED_PARAM( lpvReserved );
\r
72 fzprint(("%s():%d:0x%x:0x%x: hinstDll=%d dwReason=%d lpvReserved=0x%p\n",
\r
74 __LINE__, GetCurrentProcessId(),
\r
75 GetCurrentThreadId(), hinstDll, dwReason, lpvReserved));
\r
81 if( GetEnvironmentVariable( "IBSPLOAD", buf, sizeof(buf) ) == 0 )
\r
83 CL_EXIT_ERROR( IBSP_DBG_DLL, gdbg_lvl, ("IBSPLOAD not defined:\n") );
\r
92 case DLL_PROCESS_ATTACH:
\r
93 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_PROCESS_ATTACH\n") );
\r
96 i = GetEnvironmentVariable( "IBWSD_DBG", env_var, 16 );
\r
99 gdbg_lvl = _tcstoul( env_var, NULL, 16 );
\r
100 IBSP_TRACE( IBSP_DBG_DLL,
\r
101 ("Given IBWSD_DBG debug level:0x%X\n",
\r
106 /* See if the user wants to disable RDMA reads. */
\r
107 no_read = GetEnvironmentVariable( "IBWSD_NO_READ", NULL, 0 );
\r
109 i = GetEnvironmentVariable( "IBWSD_INLINE", env_var, 16 );
\r
111 g_max_inline = _tcstoul( env_var, NULL, 10 );
\r
113 if( init_globals() )
\r
117 case DLL_THREAD_ATTACH:
\r
118 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_THREAD_ATTACH\n") );
\r
121 case DLL_THREAD_DETACH:
\r
122 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_THREAD_DETACH\n") );
\r
125 case DLL_PROCESS_DETACH:
\r
126 CL_TRACE( IBSP_DBG_DLL, gdbg_lvl, ("DllMain: DLL_PROCESS_DETACH\n") );
\r
130 cl_list_item_t *socket_item = NULL;
\r
132 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
134 for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list );
\r
135 socket_item != cl_qlist_end( &g_ibsp.socket_info_list );
\r
136 socket_item = cl_qlist_next( socket_item ) )
\r
138 struct ibsp_socket_info *socket_info = NULL;
\r
139 socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item);
\r
142 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
144 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl, ("Statistics:\n") );
\r
145 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
146 (" overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );
\r
147 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
148 (" max_comp_count = %d\n", g_ibsp.max_comp_count) );
\r
149 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
150 (" overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );
\r
152 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl, (" send_count = %d\n", g_ibsp.send_count) );
\r
154 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
155 (" number of QPs left = %d\n", g_ibsp.qp_num) );
\r
156 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
157 (" number of CQs left = %d\n", g_ibsp.cq_num) );
\r
158 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
159 (" number of PDs left = %d\n", g_ibsp.pd_num) );
\r
160 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
161 (" number of ALs left = %d\n", g_ibsp.al_num) );
\r
162 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
163 (" number of MRs left = %d\n", g_ibsp.mr_num) );
\r
164 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
165 (" number of listens left = %d\n", g_ibsp.listen_num) );
\r
166 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
167 (" number of PNPs left = %d\n", g_ibsp.pnp_num) );
\r
168 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
169 (" number of threads left = %d\n", g_ibsp.thread_num) );
\r
170 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
171 (" number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );
\r
173 CL_ERROR( IBSP_DBG_DLL, gdbg_lvl,
\r
174 (" CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );
\r
182 CL_EXIT( IBSP_DBG_DLL, gdbg_lvl );
\r
188 extern BOOL APIENTRY
\r
189 _DllMainCRTStartupForGS(
\r
190 IN HINSTANCE h_module,
\r
191 IN DWORD ul_reason_for_call,
\r
192 IN LPVOID lp_reserved );
\r
197 IN HINSTANCE h_module,
\r
198 IN DWORD ul_reason_for_call,
\r
199 IN LPVOID lp_reserved )
\r
201 switch( ul_reason_for_call )
\r
203 case DLL_PROCESS_ATTACH:
\r
204 if( !_DllMainCRTStartupForGS(
\r
205 h_module, ul_reason_for_call, lp_reserved ) )
\r
210 return _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
212 case DLL_PROCESS_DETACH:
\r
213 _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
215 return _DllMainCRTStartupForGS(
\r
216 h_module, ul_reason_for_call, lp_reserved );
\r
222 /* Function: IBSPAccept
\r
225 * Handle the WSAAccept function. The only special consideration here
\r
226 * is the conditional accept callback. You can choose to intercept
\r
227 * this by substituting your own callback (you'll need to keep track
\r
228 * of the user supplied callback so you can trigger that once your
\r
229 * substituted function is triggered).
\r
231 static SOCKET WSPAPI
\r
234 OUT struct sockaddr FAR *addr,
\r
235 IN OUT LPINT addrlen,
\r
236 IN LPCONDITIONPROC lpfnCondition,
\r
237 IN DWORD_PTR dwCallbackData,
\r
238 OUT LPINT lpErrno )
\r
240 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
241 struct ibsp_socket_info *new_socket_info;
\r
243 SOCKET new_socket = INVALID_SOCKET;
\r
246 struct listen_incoming *incoming;
\r
247 struct ibsp_port *port;
\r
249 IBSP_ENTER( IBSP_DBG_CONN );
\r
251 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
252 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
254 CL_ASSERT( lpfnCondition );
\r
256 if( *addrlen < sizeof(struct sockaddr_in) )
\r
258 IBSP_ERROR_EXIT( ("invalid addrlen (%d, %d)\n",
\r
259 *addrlen, sizeof(struct sockaddr_in)) );
\r
260 *lpErrno = WSAEFAULT;
\r
261 return INVALID_SOCKET;
\r
264 /* Check if there is any pending connection for this socket. If
\r
265 * there is one, create a socket, and then query the switch about
\r
266 * the pending connection */
\r
268 cl_spinlock_acquire( &socket_info->mutex );
\r
270 /* Verify the state of the socket */
\r
271 if( socket_info->socket_state != IBSP_LISTEN )
\r
273 cl_spinlock_release( &socket_info->mutex );
\r
274 IBSP_ERROR_EXIT( ("Socket is not in right socket_state (%s)\n",
\r
275 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
276 *lpErrno = WSAEINVAL;
\r
277 return INVALID_SOCKET;
\r
280 if( cl_qlist_count( &socket_info->info.listen.list ) == 0 )
\r
282 cl_spinlock_release( &socket_info->mutex );
\r
284 IBSP_ERROR_EXIT( ("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
296 /* Find the destination IP address */
\r
299 /* The socket was bound to INADDR_ANY. We must find the correct port
\r
300 * for the new socket. */
\r
301 port = get_port_from_ip_address( incoming->params.dest.sin_addr );
\r
305 ("incoming destination IP address not local (%s)\n",
\r
306 inet_ntoa( incoming->params.dest.sin_addr )) );
\r
311 /* Cross-check with the path info to make sure we are conectiong correctly */
\r
312 if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) )
\r
315 ("GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n",
\r
317 ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) );
\r
320 /* The request is invalid. Remove it from the list and reject it. */
\r
321 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
322 cl_spinlock_release( &socket_info->mutex );
\r
324 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
326 HeapFree( g_ibsp.heap, 0, incoming );
\r
327 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("bad incoming parameter\n") );
\r
328 *lpErrno = WSAECONNREFUSED;
\r
329 return INVALID_SOCKET;
\r
333 * Check against the conditional routine if socket can be created
\r
337 /* Set the caller and callee data buffer */
\r
338 caller_id.buf = (char *)&incoming->params.source;
\r
339 caller_id.len = sizeof(incoming->params.source);
\r
341 callee_id.buf = (char *)&incoming->params.dest;
\r
342 callee_id.len = sizeof(incoming->params.dest);
\r
344 IBSP_TRACE( IBSP_DBG_CONN,
\r
345 ("Got incoming conn from %s/%d-%d to %s/%d-%d\n",
\r
346 inet_ntoa( incoming->params.source.sin_addr ),
\r
347 cl_ntoh16( incoming->params.source.sin_port ),
\r
348 incoming->params.source.sin_family,
\r
349 inet_ntoa( incoming->params.dest.sin_addr ),
\r
350 cl_ntoh16( incoming->params.dest.sin_port ),
\r
351 incoming->params.dest.sin_family) );
\r
353 /* Call the conditional function */
\r
354 ret = lpfnCondition( &caller_id, NULL, NULL, NULL,
\r
355 &callee_id, NULL, NULL, dwCallbackData );
\r
360 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
361 cl_spinlock_release( &socket_info->mutex );
\r
363 IBSP_TRACE1( IBSP_DBG_CONN,
\r
364 ("Conditional routine returned CF_REJECT\n") );
\r
366 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED );
\r
368 HeapFree( g_ibsp.heap, 0, incoming );
\r
369 *lpErrno = WSAECONNREFUSED;
\r
370 IBSP_EXIT( IBSP_DBG_CONN );
\r
371 return INVALID_SOCKET;
\r
374 cl_spinlock_release( &socket_info->mutex );
\r
376 IBSP_TRACE1( IBSP_DBG_CONN,
\r
377 ("Conditional routine returned CF_DEFER\n") );
\r
378 /* TODO: Send MRA */
\r
379 *lpErrno = WSATRY_AGAIN;
\r
380 IBSP_EXIT( IBSP_DBG_CONN );
\r
381 return INVALID_SOCKET;
\r
387 /* Should never happen */
\r
388 cl_spinlock_release( &socket_info->mutex );
\r
390 ("Conditional routine returned undocumented code (%d)\n", ret) );
\r
392 *lpErrno = WSAECONNREFUSED;
\r
393 IBSP_EXIT( IBSP_DBG_CONN );
\r
394 return INVALID_SOCKET;
\r
397 /* Create a new socket here */
\r
398 new_socket_info = create_socket_info();
\r
399 if( new_socket_info == NULL )
\r
401 cl_spinlock_release( &socket_info->mutex );
\r
403 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("create_socket_info return NULL\n") );
\r
404 *lpErrno = WSAENOBUFS;
\r
405 return INVALID_SOCKET;
\r
408 new_socket = g_ibsp.up_call_table.lpWPUCreateSocketHandle(
\r
409 0, (DWORD_PTR)new_socket_info, lpErrno );
\r
411 if( new_socket == INVALID_SOCKET )
\r
413 cl_spinlock_release( &socket_info->mutex );
\r
415 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
416 ("WPUCreateSocketHandle() failed: %d", *lpErrno) );
\r
417 free_socket_info( new_socket_info );
\r
418 return INVALID_SOCKET;
\r
421 STAT_INC( wpusocket_num );
\r
423 fzprint(("%s():%d:0x%x:0x%x: new_socket_info=0x%p new_socket=0x%p \n", __FUNCTION__,
\r
424 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), new_socket_info,
\r
427 /* Time to allocate our IB QP */
\r
428 new_socket_info->port = port;
\r
429 ret = ib_create_socket( new_socket_info );
\r
432 cl_spinlock_release( &socket_info->mutex );
\r
434 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
435 ("ib_create socket failed with %d\n", ret) );
\r
436 *lpErrno = WSAENOBUFS;
\r
437 return INVALID_SOCKET;
\r
440 /* Store the IP address and port number in the socket context */
\r
441 new_socket_info->local_addr = incoming->params.dest;
\r
443 cl_qlist_remove_item( &socket_info->info.listen.list, &incoming->item );
\r
444 /* Signal the event again if there are more connection requests. */
\r
445 if( cl_qlist_count( &socket_info->info.listen.list ) )
\r
446 ibsp_post_select_event( socket_info, FD_ACCEPT, 0 );
\r
448 cl_spinlock_release( &socket_info->mutex );
\r
450 /* Copy the socket context info from parent socket context */
\r
451 new_socket_info->socket_options = socket_info->socket_options;
\r
453 /* Store the client socket address information */
\r
454 memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) );
\r
455 *addrlen = sizeof(struct sockaddr_in);
\r
457 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("The socket address of connecting entity is\n") );
\r
458 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, &incoming->params.source );
\r
460 new_socket_info->peer_addr = incoming->params.source;
\r
461 new_socket_info->switch_socket = new_socket;
\r
463 new_socket_info->info.accept.event = CreateEvent( NULL, FALSE, FALSE, NULL );
\r
465 cl_spinlock_acquire( &new_socket_info->mutex );
\r
466 /* Update the state of the socket context */
\r
467 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_ACCEPT );
\r
469 ret = ib_accept( new_socket_info, &incoming->cm_req_received, lpErrno );
\r
473 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE );
\r
474 cl_spinlock_release( &new_socket_info->mutex );
\r
475 /* Free the socket descriptor */
\r
476 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p calling lpWPUCloseSocketHandle=0x%p\n",
\r
477 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
478 socket_info, socket_info->switch_socket));
\r
480 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
481 new_socket_info->switch_socket, &ret ) == SOCKET_ERROR )
\r
483 IBSP_ERROR( ("WPUCloseSocketHandle failed: %d\n", ret) );
\r
487 STAT_DEC( wpusocket_num );
\r
490 CloseHandle( new_socket_info->info.accept.event );
\r
492 ib_destroy_socket( new_socket_info );
\r
494 free_socket_info( new_socket_info );
\r
496 /* Be nice and reject that connection. */
\r
497 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
499 HeapFree( g_ibsp.heap, 0, incoming );
\r
502 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_accept failed (%d)\n", ret) );
\r
504 return INVALID_SOCKET;
\r
508 cl_spinlock_release( &new_socket_info->mutex );
\r
509 HeapFree( g_ibsp.heap, 0, incoming );
\r
511 if( WaitForSingleObject( new_socket_info->info.accept.event, INFINITE ) == WAIT_OBJECT_0 )
\r
513 CloseHandle( new_socket_info->info.accept.event );
\r
515 cl_spinlock_acquire( &new_socket_info->mutex );
\r
517 if( new_socket_info->socket_state == IBSP_CONNECTED )
\r
519 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
520 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &new_socket_info->item );
\r
521 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
523 cl_spinlock_release( &new_socket_info->mutex );
\r
528 ("ib_accept failed - socket state is %s\n",
\r
529 IBSP_SOCKET_STATE_STR( new_socket_info->socket_state )) );
\r
531 cl_spinlock_release( &new_socket_info->mutex );
\r
533 /* The accept failed (by a REJ for instance). */
\r
535 /* Free the socket descriptor */
\r
536 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
538 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
539 new_socket_info->switch_socket, lpErrno ) == SOCKET_ERROR )
\r
542 ("WPUCloseSocketHandle failed: %d\n", *lpErrno) );
\r
546 STAT_DEC( wpusocket_num );
\r
549 ib_destroy_socket( new_socket_info );
\r
550 free_socket_info( new_socket_info );
\r
552 *lpErrno = WSAEACCES;
\r
554 new_socket_info = (struct ibsp_socket_info *)INVALID_SOCKET;
\r
557 CL_TRACE_EXIT(IBSP_DBG_CONN, gdbg_lvl,
\r
558 ("returns new SocketID (0x%x)\n", new_socket) );
\r
560 return (SOCKET) new_socket_info;
\r
564 CloseHandle( new_socket_info->info.accept.event );
\r
566 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("wait for ib_accept failed\n") );
\r
568 *lpErrno = WSAEACCES;
\r
569 return INVALID_SOCKET;
\r
577 /* Function: IBSPBind
\r
580 * Bind the socket to a local address.
\r
586 IN const struct sockaddr FAR *name,
\r
588 OUT LPINT lpErrno )
\r
590 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
591 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
592 struct ibsp_port *port;
\r
595 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
597 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
598 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
600 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("Address to bind to:\n") );
\r
601 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );
\r
603 fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));
\r
605 /* Sanity checks */
\r
606 if( namelen != sizeof(struct sockaddr_in) )
\r
609 ("invalid namelen (%d instead of %d)\n",
\r
610 namelen, sizeof(struct sockaddr_in)) );
\r
611 *lpErrno = WSAEFAULT;
\r
615 if( addr->sin_family != AF_INET )
\r
617 IBSP_ERROR( ("bad family for socket\n") );
\r
618 *lpErrno = WSAEFAULT;
\r
622 /* Check if the ip address is assigned to one of our IBoIB HCA. */
\r
623 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
625 port = get_port_from_ip_address( addr->sin_addr );
\r
629 ("This IP address does not belong to that host (%08x)\n",
\r
630 addr->sin_addr.S_un.S_addr) );
\r
631 *lpErrno = WSAEADDRNOTAVAIL;
\r
640 /* We are going to take this mutex for some time,
\r
641 * but at this stage, it shouldn't impact anything. */
\r
642 cl_spinlock_acquire( &socket_info->mutex );
\r
644 /* Verify the state of the socket */
\r
645 if( socket_info->socket_state != IBSP_CREATE )
\r
647 cl_spinlock_release( &socket_info->mutex );
\r
649 ("Invalid socket state (%s)\n",
\r
650 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
651 *lpErrno = WSAEINVAL;
\r
655 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
657 /* Time to allocate our IB QP */
\r
658 socket_info->port = port;
\r
659 ret = ib_create_socket( socket_info );
\r
662 socket_info->port = NULL;
\r
663 cl_spinlock_release( &socket_info->mutex );
\r
664 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );
\r
665 *lpErrno = WSAENOBUFS;
\r
671 socket_info->local_addr = *addr;
\r
673 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
675 cl_spinlock_release( &socket_info->mutex );
\r
677 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
681 CL_ASSERT( *lpErrno != 0 );
\r
682 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl, ("failed with error %d\n", *lpErrno) );
\r
683 return SOCKET_ERROR;
\r
687 /* Function: IBSPCloseSocket
\r
690 * Close the socket handle of the app socket as well as the provider socket.
\r
691 * However, if there are outstanding async IO requests on the app socket
\r
692 * we only close the provider socket. Only when all the IO requests complete
\r
693 * (with error) will we then close the app socket.
\r
700 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
703 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
705 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
706 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
708 if( s == INVALID_SOCKET )
\r
710 CL_EXIT_ERROR( IBSP_DBG_WQ, gdbg_lvl, ("invalid socket handle %x\n", s) );
\r
711 *lpErrno = WSAENOTSOCK;
\r
712 return SOCKET_ERROR;
\r
715 cl_atomic_inc( &g_ibsp.CloseSocket_count );
\r
718 cl_spinlock_acquire( &socket_info->mutex );
\r
720 old_state = socket_info->socket_state;
\r
721 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CLOSING );
\r
723 cl_spinlock_release( &socket_info->mutex );
\r
725 shutdown_and_destroy_socket_info( socket_info, old_state );
\r
727 cl_spinlock_acquire( &socket_info->mutex );
\r
728 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CLOSED );
\r
729 cl_spinlock_release( &socket_info->mutex );
\r
731 /* Take off socket_info_list and put on closed_socket_info_list */
\r
732 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
733 cl_qlist_remove_item( &g_ibsp.socket_info_list, &socket_info->item );
\r
734 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
736 cl_spinlock_acquire( &g_ibsp.closed_socket_info_mutex );
\r
737 cl_qlist_insert_tail( &g_ibsp.closed_socket_info_list, &socket_info->item );
\r
738 cl_spinlock_release( &g_ibsp.closed_socket_info_mutex );
\r
740 /* Notify ib_cleanup_thread() to free this */
\r
741 SetEvent( g_ibsp.ib_cleanup_event );
\r
743 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
750 /* Function: IBSPConnect
\r
753 * Performs a connect call. The only thing we need to do is translate
\r
754 * the socket handle.
\r
759 const struct sockaddr FAR *name,
\r
761 LPWSABUF lpCallerData,
\r
762 LPWSABUF lpCalleeData,
\r
767 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
768 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
770 ib_net64_t dest_port_guid;
\r
771 ib_path_rec_t path_rec;
\r
773 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
775 UNUSED_PARAM( lpCalleeData );
\r
776 UNUSED_PARAM( lpSQOS );
\r
777 UNUSED_PARAM( lpGQOS );
\r
779 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
780 __LINE__, GetCurrentProcessId(),
\r
781 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
783 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl,
\r
784 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );
\r
786 /* Sanity checks */
\r
789 /* We don't support that. The current switch does not use it. */
\r
790 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("lpCallerData.len=%d\n", lpCallerData->len) );
\r
791 *lpErrno = WSAEINVAL;
\r
795 if( namelen < sizeof(struct sockaddr_in) )
\r
797 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
798 ("invalid remote address (%d)\n", socket_info->socket_state) );
\r
799 *lpErrno = WSAEFAULT;
\r
803 /* Check if the name (actually address) of peer entity is correct */
\r
804 if( addr->sin_family != AF_INET ||
\r
805 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )
\r
807 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
808 ("peer entity address is invalid (%d, %d, %x)\n",
\r
809 addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );
\r
810 *lpErrno = WSAEADDRNOTAVAIL;
\r
814 if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )
\r
816 /* Loopback - let the regular stack take care of that. */
\r
817 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Loopback!\n") );
\r
818 *lpErrno = WSAEADDRNOTAVAIL;
\r
822 /* Get the GUID for that IP address. */
\r
823 ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );
\r
826 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
827 ("query_guid_address failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
828 *lpErrno = WSAEADDRNOTAVAIL;
\r
832 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("got GUID %I64x for IP %s\n",
\r
833 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );
\r
835 /* Get the path record */
\r
836 ret = query_pr( socket_info->port, dest_port_guid, &path_rec );
\r
839 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
840 ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
841 *lpErrno = WSAEADDRNOTAVAIL;
\r
845 cl_spinlock_acquire( &socket_info->mutex );
\r
847 /* Verify the state of the socket */
\r
848 switch( socket_info->socket_state )
\r
851 /* Good. That's the only valid state we want. */
\r
854 case IBSP_CONNECTED:
\r
855 cl_spinlock_release( &socket_info->mutex );
\r
856 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Socket is already connected\n") );
\r
857 *lpErrno = WSAEISCONN;
\r
862 cl_spinlock_release( &socket_info->mutex );
\r
863 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("Socket is a listening socket\n") );
\r
864 *lpErrno = WSAEINVAL;
\r
868 cl_spinlock_release( &socket_info->mutex );
\r
869 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
870 ("Socket is not in the bound state (%s)\n",
\r
871 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
872 *lpErrno = WSAEINVAL;
\r
877 /* Store the peer entity's address in socket context */
\r
878 socket_info->peer_addr = *addr;
\r
880 /* Update the socket state */
\r
881 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );
\r
883 cl_spinlock_release( &socket_info->mutex );
\r
886 ret = ib_connect( socket_info, &path_rec, lpErrno );
\r
889 cl_spinlock_acquire( &socket_info->mutex );
\r
891 if( socket_info->socket_state == IBSP_CONNECT )
\r
893 /* We must be sure none destroyed our socket */
\r
894 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
895 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );
\r
898 cl_spinlock_release( &socket_info->mutex );
\r
900 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_connect failed (%d)\n", ret) );
\r
902 *lpErrno = WSAEHOSTUNREACH;
\r
906 /* Operation is pending */
\r
907 *lpErrno = WSAEWOULDBLOCK;
\r
910 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
911 return SOCKET_ERROR;
\r
915 /* Function: IBSPDuplicateSocket
\r
918 This function provides a WSAPROTOCOL_INFOW structure which can be passed
\r
919 to another process to open a handle to the same socket. First we need
\r
920 to translate the user socket into the provider socket and call the underlying
\r
921 WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us
\r
922 is an out parameter only!
\r
925 IBSPDuplicateSocket(
\r
928 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
931 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
934 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
936 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
937 __LINE__, GetCurrentProcessId(),
\r
938 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
940 cl_spinlock_acquire( &socket_info->mutex );
\r
941 if( socket_info->socket_state != IBSP_CONNECTED )
\r
943 cl_spinlock_release( &socket_info->mutex );
\r
944 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl,
\r
945 ("Socket state not IBSP_CONNECTED, state=%s.\n",
\r
946 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
947 *lpErrno = WSAENOTCONN;
\r
948 return SOCKET_ERROR;
\r
950 cl_spinlock_release( &socket_info->mutex );
\r
952 ret = prepare_duplicate_socket( socket_info, dwProcessId );
\r
955 CL_TRACE_EXIT( IBSP_DBG_CONN, gdbg_lvl,
\r
956 ("prepare_duplicate_socket failed with %d\n", ret) );
\r
958 return SOCKET_ERROR;
\r
962 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
963 lpProtocolInfo->dwProviderReserved = socket_info->duplicate.identifier;
\r
970 /* Function: IBSPEnumNetworkEvents
\r
973 * Enumerate the network events for a socket. We only need to
\r
974 * translate the socket handle.
\r
977 IBSPEnumNetworkEvents(
\r
979 WSAEVENT hEventObject,
\r
980 LPWSANETWORKEVENTS lpNetworkEvents,
\r
983 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
985 IBSP_ENTER( IBSP_DBG_NEV );
\r
987 ResetEvent( hEventObject );
\r
989 lpNetworkEvents->lNetworkEvents =
\r
990 InterlockedExchange( &socket_info->network_events, 0 );
\r
992 if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT )
\r
994 IBSP_TRACE1( IBSP_DBG_NEV,
\r
995 ("socket %p notify FD_ACCEPT at time %I64d\n",
\r
996 socket_info, cl_get_time_stamp()) );
\r
997 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0;
\r
1000 if( lpNetworkEvents->lNetworkEvents & FD_CONNECT )
\r
1002 IBSP_TRACE1( IBSP_DBG_NEV,
\r
1003 ("socket %p notify FD_CONNECT %d at time %I64d\n",
\r
1004 socket_info, socket_info->errno_connect, cl_get_time_stamp()) );
\r
1005 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;
\r
1009 IBSP_EXIT( IBSP_DBG_NEV );
\r
1014 /* Function: IBSPEventSelect
\r
1017 * Register the specified events on the socket with the given event handle.
\r
1018 * All we need to do is translate the socket handle.
\r
1023 WSAEVENT hEventObject,
\r
1024 long lNetworkEvents,
\r
1027 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1030 IBSP_ENTER( IBSP_DBG_NEV );
\r
1032 IBSP_TRACE4( IBSP_DBG_NEV,
\r
1033 ("Socket %p requesting notifiction of %d on event %p.\n",
\r
1034 s, lNetworkEvents, hEventObject) );
\r
1036 if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )
\r
1038 IBSP_TRACE_EXIT(IBSP_DBG_NEV,
\r
1039 ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );
\r
1040 *lpErrno = WSAEINVAL;
\r
1041 return SOCKET_ERROR;
\r
1044 CL_ASSERT( lpErrno );
\r
1046 socket_info->event_mask = lNetworkEvents;
\r
1047 InterlockedExchangePointer( &socket_info->event_select, hEventObject );
\r
1049 events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 );
\r
1050 /* Check for existing events and signal as appropriate. */
\r
1051 if( (socket_info->event_mask & events) && hEventObject )
\r
1053 IBSP_TRACE2( IBSP_DBG_NEV,
\r
1054 ("Signaling eventHandle %p .\n", socket_info->event_select) );
\r
1055 SetEvent( hEventObject );
\r
1058 IBSP_EXIT( IBSP_DBG_NEV );
\r
1063 /* Function: IBSPGetOverlappedResult
\r
1066 * This function reports whether the specified overlapped call has
\r
1067 * completed. If it has, return the requested information. If not,
\r
1068 * and fWait is true, wait until completion. Otherwise return an
\r
1069 * error immediately.
\r
1071 static BOOL WSPAPI
\r
1072 IBSPGetOverlappedResult(
\r
1074 IN LPWSAOVERLAPPED lpOverlapped,
\r
1075 OUT LPDWORD lpcbTransfer,
\r
1077 OUT LPDWORD lpdwFlags,
\r
1078 OUT LPINT lpErrno )
\r
1080 struct ibsp_socket_info *p_socket_info;
\r
1083 IBSP_ENTER( IBSP_DBG_IO );
\r
1085 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
1087 CL_ASSERT( fWait == FALSE );
\r
1088 if( fWait == TRUE )
\r
1090 IBSP_ERROR_EXIT( ("fWait not supported\n") );
\r
1091 *lpErrno = WSAENETDOWN;
\r
1095 if( s == INVALID_SOCKET )
\r
1097 /* Seen in real life with overlap/client test.
\r
1098 * The switch closes a socket then calls this. Why? */
\r
1099 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1100 *lpErrno = WSAENOTSOCK;
\r
1101 return SOCKET_ERROR;
\r
1104 if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )
\r
1106 p_socket_info = (struct ibsp_socket_info*)s;
\r
1107 /* Poll just in case it's done. */
\r
1108 ib_cq_comp( p_socket_info->cq_tinfo );
\r
1111 if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )
\r
1113 /* Operation has completed, perhaps with error */
\r
1114 *lpdwFlags = lpOverlapped->Offset;
\r
1115 *lpErrno = lpOverlapped->OffsetHigh;
\r
1118 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )
\r
1120 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1122 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1123 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
1124 lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1125 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1128 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
1130 IBSP_TRACE1( IBSP_DBG_IO,
\r
1131 ("socket=%p completed ov=%p\n", s, lpOverlapped) );
\r
1135 /* Operation is still in progress */
\r
1136 *lpErrno = WSA_IO_INCOMPLETE;
\r
1137 IBSP_TRACE1( IBSP_DBG_IO,
\r
1138 ("socket=%p ov=%p hEvent=%p, operation in progress\n",
\r
1139 s, lpOverlapped, lpOverlapped->hEvent));
\r
1142 *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;
\r
1144 if( *lpErrno == 0 )
\r
1149 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",
\r
1150 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1151 lpOverlapped, *lpErrno, rc));
\r
1153 IBSP_EXIT( IBSP_DBG_IO );
\r
1158 /* Function: IBSPGetSockOpt
\r
1161 * Get the specified socket option. All we need to do is translate the
\r
1173 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1175 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
1177 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1178 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1180 if( level != SOL_SOCKET )
\r
1182 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid level %d", level) );
\r
1183 *lpErrno = WSAENOPROTOOPT;
\r
1184 return SOCKET_ERROR;
\r
1187 if( optval == NULL || optlen == NULL )
\r
1189 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1190 ("invalid optval=%p or optlen=%p", optval, optlen) );
\r
1191 *lpErrno = WSAEFAULT;
\r
1192 return SOCKET_ERROR;
\r
1198 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_DEBUG\n") );
\r
1199 if( *optlen < sizeof(BOOL) )
\r
1201 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1202 ("option len is invalid (0x%x)\n", *optlen) );
\r
1203 *optlen = sizeof(BOOL);
\r
1204 *lpErrno = WSAEFAULT;
\r
1205 return SOCKET_ERROR;
\r
1208 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );
\r
1209 *optlen = sizeof(BOOL);
\r
1213 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_ID\n") );
\r
1214 if( *optlen < sizeof(GROUP) )
\r
1216 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1217 ("option len is invalid (0x%x)\n", *optlen) );
\r
1218 *optlen = sizeof(GROUP);
\r
1219 *lpErrno = WSAEFAULT;
\r
1220 return SOCKET_ERROR;
\r
1223 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );
\r
1224 *optlen = sizeof(GROUP);
\r
1227 case SO_GROUP_PRIORITY:
\r
1228 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_PRIORITY\n") );
\r
1230 if( *optlen < sizeof(int) )
\r
1232 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1233 ("option len is invalid (0x%x)\n", *optlen) );
\r
1234 *optlen = sizeof(int);
\r
1235 *lpErrno = WSAEFAULT;
\r
1236 return SOCKET_ERROR;
\r
1239 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );
\r
1240 *optlen = sizeof(int);
\r
1243 case SO_MAX_MSG_SIZE:
\r
1244 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_MAX_MSG_SIZE\n") );
\r
1246 if( *optlen < sizeof(unsigned int) )
\r
1248 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1249 ("option len is invalid (0x%x)\n", *optlen) );
\r
1250 *optlen = sizeof(unsigned int);
\r
1251 *lpErrno = WSAEFAULT;
\r
1252 return SOCKET_ERROR;
\r
1255 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );
\r
1256 *optlen = sizeof(unsigned int);
\r
1259 case SO_MAX_RDMA_SIZE:
\r
1260 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_MAX_RDMA_SIZE\n") );
\r
1262 if( *optlen < sizeof(unsigned int) )
\r
1264 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1265 ("option len is invalid (0x%x)\n", *optlen) );
\r
1266 *optlen = sizeof(unsigned int);
\r
1267 *lpErrno = WSAEFAULT;
\r
1268 return SOCKET_ERROR;
\r
1271 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );
\r
1272 *optlen = sizeof(unsigned int);
\r
1275 case SO_RDMA_THRESHOLD_SIZE:
\r
1276 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );
\r
1278 if( *optlen < sizeof(unsigned int) )
\r
1280 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1281 ("option len is invalid (0x%x)\n", *optlen) );
\r
1282 *optlen = sizeof(unsigned int);
\r
1283 *lpErrno = WSAEFAULT;
\r
1284 return SOCKET_ERROR;
\r
1287 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,
\r
1288 sizeof(unsigned int) );
\r
1289 *optlen = sizeof(unsigned int);
\r
1293 *lpErrno = WSAENOPROTOOPT;
\r
1295 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("unknown option 0x%x\n", optname) );
\r
1297 return SOCKET_ERROR;
\r
1301 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
1306 /* Function: IBSPGetQOSByName
\r
1309 * Get a QOS template by name. All we need to do is translate the socket
\r
1312 static BOOL WSPAPI
\r
1315 LPWSABUF lpQOSName,
\r
1319 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
1321 UNUSED_PARAM( s );
\r
1322 UNUSED_PARAM( lpQOSName );
\r
1323 UNUSED_PARAM( lpQOS );
\r
1325 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1326 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1328 *lpErrno = WSAEOPNOTSUPP;
\r
1330 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("not supported\n") );
\r
1336 /* Function: IBSPIoctl
\r
1339 * Invoke an ioctl. In most cases, we just need to translate the socket
\r
1340 * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,
\r
1341 * we'll need to intercept this and return our own function pointers.
\r
1346 IN DWORD dwIoControlCode,
\r
1347 IN LPVOID lpvInBuffer,
\r
1348 IN DWORD cbInBuffer,
\r
1349 OUT LPVOID lpvOutBuffer,
\r
1350 IN DWORD cbOutBuffer,
\r
1351 OUT LPDWORD lpcbBytesReturned,
\r
1352 IN LPWSAOVERLAPPED lpOverlapped,
\r
1353 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1354 IN LPWSATHREADID lpThreadId,
\r
1355 OUT LPINT lpErrno )
\r
1357 struct ibsp_socket_info *socket_info;
\r
1358 GUID SANRegisterMemory = WSAID_REGISTERMEMORY;
\r
1359 GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;
\r
1360 GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;
\r
1361 GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;
\r
1362 GUID SANRDMAWrite = WSAID_RDMAWRITE;
\r
1363 GUID SANRDMARead = WSAID_RDMAREAD;
\r
1364 GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;
\r
1366 IBSP_ENTER( IBSP_DBG_OPT );
\r
1368 UNUSED_PARAM( cbInBuffer );
\r
1369 UNUSED_PARAM( lpOverlapped );
\r
1370 UNUSED_PARAM( lpCompletionRoutine );
\r
1371 UNUSED_PARAM( lpThreadId );
\r
1373 if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )
\r
1375 /* This a special case. The socket handle passed is not valid. */
\r
1376 IBSP_TRACE1( IBSP_DBG_OPT, ("Get extension function pointer\n") );
\r
1378 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )
\r
1380 /* Return a pointer to our intermediate extension function */
\r
1381 *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;
\r
1383 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )
\r
1385 /* Return a pointer to our intermediate extension function */
\r
1386 *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;
\r
1388 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1390 /* Return a pointer to our intermediate extension function */
\r
1391 *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;
\r
1393 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1395 /* Return a pointer to our intermediate extension function */
\r
1396 *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;
\r
1398 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )
\r
1400 /* Return a pointer to our intermediate extension function */
\r
1401 *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;
\r
1403 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )
\r
1407 IBSP_TRACE( IBSP_DBG_WARN | IBSP_DBG_OPT,
\r
1408 ("RDMA_READ disabled.\n") );
\r
1409 *lpErrno = WSAEOPNOTSUPP;
\r
1410 return SOCKET_ERROR;
\r
1414 /* Return a pointer to our intermediate extension function */
\r
1415 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;
\r
1418 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,
\r
1419 sizeof(GUID) ) == 0 )
\r
1421 /* Return a pointer to our intermediate extension function */
\r
1422 *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =
\r
1423 IBSPMemoryRegistrationCacheCallback;
\r
1427 IBSP_ERROR_EXIT( ("invalid extension GUID\n") );
\r
1428 *lpErrno = WSAEINVAL;
\r
1429 return SOCKET_ERROR;
\r
1431 IBSP_EXIT( IBSP_DBG_OPT );
\r
1435 socket_info = (struct ibsp_socket_info *)s;
\r
1437 /* Verify the state of the socket */
\r
1438 /* Not sure which state socket should be in to receive this call */
\r
1439 DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,
\r
1444 cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );
\r
1446 switch( dwIoControlCode )
\r
1449 case SIO_GET_GROUP_QOS:
\r
1451 case SIO_SET_GROUP_QOS:
\r
1452 /* We don't support that. dwServiceFlags1 in installSP
\r
1454 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1455 ("unsupported dwIoControlCode %d\n", dwIoControlCode) );
\r
1456 *lpErrno = WSAENOPROTOOPT;
\r
1457 return SOCKET_ERROR;
\r
1460 case SIO_ADDRESS_LIST_QUERY:
\r
1464 *lpcbBytesReturned = cbOutBuffer;
\r
1465 ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,
\r
1466 lpcbBytesReturned, lpErrno );
\r
1468 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
1474 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
1475 ("invalid dwIoControlCode %d\n", dwIoControlCode) );
\r
1477 *lpErrno = WSAENOPROTOOPT;
\r
1478 return SOCKET_ERROR;
\r
1486 /* Function: IBSPListen
\r
1489 * This function establishes a socket to listen for incoming connections. It sets
\r
1490 * the backlog value on a listening socket.
\r
1498 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1501 CL_ENTER( IBSP_DBG_CONN, gdbg_lvl );
\r
1503 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1504 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1506 cl_spinlock_acquire( &socket_info->mutex );
\r
1508 CL_TRACE( IBSP_DBG_CONN, gdbg_lvl, ("socket_state is %s\n",
\r
1509 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1511 /* Verify the state of the socket */
\r
1512 switch( socket_info->socket_state )
\r
1516 /* Store the backlog value in the context */
\r
1517 socket_info->info.listen.backlog = backlog;
\r
1518 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );
\r
1520 socket_info->info.listen.listen_req_param.dwProcessId = 0;
\r
1521 socket_info->info.listen.listen_req_param.identifier = 0;
\r
1523 ret = ib_listen( socket_info, lpErrno );
\r
1526 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
1527 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_listen failed with %d\n", ret) );
\r
1537 /* Change the backlog */
\r
1538 socket_info->info.listen.backlog = backlog;
\r
1543 CL_ERROR( IBSP_DBG_CONN, gdbg_lvl,
\r
1544 ("Invalid socket_state (%s)\n",
\r
1545 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1546 *lpErrno = WSAEINVAL;
\r
1550 cl_spinlock_release( &socket_info->mutex );
\r
1552 CL_EXIT( IBSP_DBG_CONN, gdbg_lvl );
\r
1555 return SOCKET_ERROR;
\r
1561 /* Function: IBSPRecv
\r
1564 * This function receives data on a given socket and also allows for asynchronous
\r
1565 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1566 * handle and then make the receive call. If called with overlap, post the operation
\r
1567 * to our IOCP or completion routine.
\r
1572 LPWSABUF lpBuffers,
\r
1573 DWORD dwBufferCount,
\r
1574 LPDWORD lpNumberOfBytesRecvd,
\r
1576 LPWSAOVERLAPPED lpOverlapped,
\r
1577 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1578 LPWSATHREADID lpThreadId,
\r
1581 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1582 ib_api_status_t status;
\r
1583 struct memory_node *node;
\r
1584 struct _recv_wr *wr;
\r
1587 IBSP_ENTER( IBSP_DBG_IO );
\r
1589 UNUSED_PARAM( lpNumberOfBytesRecvd );
\r
1590 UNUSED_PARAM( lpCompletionRoutine );
\r
1591 UNUSED_PARAM( lpThreadId );
\r
1593 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1594 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1596 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1597 CL_ASSERT( lpOverlapped != NULL );
\r
1599 if( s == INVALID_SOCKET )
\r
1601 /* Seen in real life with overlap/client test.
\r
1602 * The switch closes a socket then calls this. Why? */
\r
1603 IBSP_TRACE_EXIT( IBSP_DBG_WARN | IBSP_DBG_IO,
\r
1604 ("invalid socket handle %x\n", s) );
\r
1605 *lpErrno = WSAENOTSOCK;
\r
1606 return SOCKET_ERROR;
\r
1609 /* Check the state of the socket */
\r
1610 if( socket_info->socket_state != IBSP_CONNECTED )
\r
1613 ("Socket is not in connected socket_state state=%s\n",
\r
1614 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1615 *lpErrno = WSAENOTCONN;
\r
1616 return SOCKET_ERROR;
\r
1619 if( socket_info->qp_error != 0 )
\r
1622 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1623 *lpErrno = socket_info->qp_error;
\r
1624 return SOCKET_ERROR;
\r
1627 /* This function only works for that case. Right now the switch is
\r
1628 * only using that. */
\r
1629 if( dwBufferCount > QP_ATTRIB_RQ_SGE )
\r
1631 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );
\r
1633 ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );
\r
1634 *lpErrno = WSAEINVAL;
\r
1635 return SOCKET_ERROR;
\r
1638 cl_spinlock_acquire( &socket_info->recv_lock );
\r
1639 if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )
\r
1641 /* This should never happen */
\r
1642 cl_spinlock_release( &socket_info->recv_lock );
\r
1643 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1644 *lpErrno = WSAENETDOWN;
\r
1645 return SOCKET_ERROR;
\r
1648 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
1650 wr->wr.lpOverlapped = lpOverlapped;
\r
1651 wr->wr.socket_info = socket_info;
\r
1653 /* Looks good. Post the receive buffer. */
\r
1654 wr->recv.p_next = NULL;
\r
1655 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
1656 wr->recv.num_ds = dwBufferCount;
\r
1657 wr->recv.ds_array = wr->ds_array;
\r
1659 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1661 /* Get the memory region node */
\r
1662 node = lookup_partial_mr( &socket_info->buf_mem_list, IB_AC_LOCAL_WRITE,
\r
1663 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1666 cl_spinlock_release( &socket_info->recv_lock );
\r
1668 * No mr fits. This should never happen. This error is not
\r
1669 * official, but seems to be the closest.
\r
1671 IBSP_ERROR_EXIT( ("no MR found\n") );
\r
1672 *lpErrno = WSAEFAULT;
\r
1673 return SOCKET_ERROR;
\r
1676 wr->ds_array[ds_idx].vaddr =
\r
1677 (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1678 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;
\r
1679 wr->ds_array[ds_idx].lkey = node->lkey;
\r
1683 * We must set this now, because the operation could complete
\r
1684 * before ib_post_Recv returns.
\r
1686 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1688 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1689 lpOverlapped->Offset = *lpFlags;
\r
1691 cl_atomic_inc( &socket_info->recv_cnt );
\r
1694 if( lpOverlapped->hEvent == 0 )
\r
1696 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1700 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1701 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1704 cl_atomic_inc( &g_ibsp.recv_count );
\r
1706 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1707 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1708 GetCurrentThreadId(), lpOverlapped,
\r
1709 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1710 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1716 fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",
\r
1717 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1718 lpOverlapped, wr));
\r
1720 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
1722 if( status == IB_SUCCESS )
\r
1724 /* Update the index and wrap as needed */
\r
1725 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
1726 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
1727 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
1728 socket_info->recv_idx++;
\r
1729 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
1731 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
1732 socket_info->recv_idx = 0;
\r
1735 IBSP_TRACE1( IBSP_DBG_IO,
\r
1736 ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1737 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1739 *lpErrno = WSA_IO_PENDING;
\r
1744 ("ib_post_recv returned %s\n", ib_get_err_str( status )) );
\r
1746 if( lpOverlapped->hEvent == 0 )
\r
1748 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1752 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1753 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1756 cl_atomic_dec( &g_ibsp.recv_count );
\r
1758 memset( wr, 0x33, sizeof(struct _recv_wr) );
\r
1761 cl_atomic_dec( &socket_info->recv_cnt );
\r
1762 *lpErrno = ibal_to_wsa_error( status );
\r
1765 cl_spinlock_release( &socket_info->recv_lock );
\r
1767 /* We never complete the operation here. */
\r
1768 IBSP_EXIT( IBSP_DBG_IO );
\r
1769 return SOCKET_ERROR;
\r
1773 /* Function: IBSPSend
\r
1776 * This function sends data on a given socket and also allows for asynchronous
\r
1777 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1778 * handle and then make the send call.
\r
1783 IN LPWSABUF lpBuffers,
\r
1784 IN DWORD dwBufferCount,
\r
1785 OUT LPDWORD lpNumberOfBytesSent,
\r
1787 IN LPWSAOVERLAPPED lpOverlapped,
\r
1788 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1789 IN LPWSATHREADID lpThreadId,
\r
1790 OUT LPINT lpErrno )
\r
1792 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1793 ib_api_status_t status;
\r
1794 struct memory_node *node;
\r
1796 ib_send_wr_t send_wr;
\r
1797 ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE];
\r
1800 IBSP_ENTER( IBSP_DBG_IO );
\r
1802 UNUSED_PARAM( lpNumberOfBytesSent );
\r
1803 UNUSED_PARAM( lpCompletionRoutine );
\r
1804 UNUSED_PARAM( lpThreadId );
\r
1806 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,
\r
1807 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1809 if( s == INVALID_SOCKET )
\r
1811 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1812 *lpErrno = WSAENOTSOCK;
\r
1813 return SOCKET_ERROR;
\r
1816 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1817 CL_ASSERT( lpOverlapped != NULL );
\r
1819 cl_spinlock_acquire( &socket_info->mutex );
\r
1820 /* Check the state of the socket */
\r
1821 switch( socket_info->socket_state )
\r
1823 case IBSP_CONNECTED:
\r
1824 case IBSP_DISCONNECTED:
\r
1828 IBSP_ERROR_EXIT( ("Socket is not in connected socket_state \n") );
\r
1829 *lpErrno = WSAENOTCONN;
\r
1830 return SOCKET_ERROR;
\r
1832 cl_spinlock_release( &socket_info->mutex );
\r
1834 if( socket_info->qp_error )
\r
1837 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1838 *lpErrno = socket_info->qp_error;
\r
1839 return SOCKET_ERROR;
\r
1842 /* This function only works for that case. */
\r
1843 if( dwBufferCount > QP_ATTRIB_SQ_SGE )
\r
1845 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );
\r
1847 ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );
\r
1848 *lpErrno = WSAEINVAL;
\r
1849 return SOCKET_ERROR;
\r
1852 /* The send lock is only used to serialize posting. */
\r
1853 cl_spinlock_acquire( &socket_info->send_lock );
\r
1854 if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )
\r
1856 /* This should never happen */
\r
1857 cl_spinlock_release( &socket_info->send_lock );
\r
1858 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1859 *lpErrno = WSAENETDOWN;
\r
1860 return SOCKET_ERROR;
\r
1863 wr = &socket_info->send_wr[socket_info->send_idx];
\r
1865 wr->lpOverlapped = lpOverlapped;
\r
1866 wr->socket_info = socket_info;
\r
1868 /* Looks good. Post the send buffer. */
\r
1869 send_wr.p_next = NULL;
\r
1870 send_wr.wr_id = (uint64_t) (uintptr_t) wr;
\r
1871 send_wr.wr_type = WR_SEND;
\r
1872 send_wr.send_opt = socket_info->send_opt;
\r
1873 socket_info->send_opt = 0;
\r
1875 send_wr.num_ds = dwBufferCount;
\r
1876 send_wr.ds_array = local_ds;
\r
1878 lpOverlapped->InternalHigh = 0;
\r
1879 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1881 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1882 local_ds[ds_idx].length = lpBuffers[ds_idx].len;
\r
1884 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;
\r
1887 if( lpOverlapped->InternalHigh <= socket_info->max_inline )
\r
1889 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1893 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1895 /* Get the memory region node */
\r
1896 node = lookup_partial_mr( &socket_info->buf_mem_list, 0, /* READ */
\r
1897 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1900 cl_spinlock_release( &socket_info->send_lock );
\r
1902 * No mr fits. This error is not official, but seems to be the
\r
1905 IBSP_ERROR_EXIT( ("mr lookup failed\n") );
\r
1906 *lpErrno = WSAEFAULT;
\r
1907 return SOCKET_ERROR;
\r
1910 local_ds[ds_idx].lkey = node->lkey;
\r
1915 * We must set this now, because the operation could complete
\r
1916 * before ib_post_send returns.
\r
1918 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1920 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1921 lpOverlapped->Offset = dwFlags;
\r
1923 cl_atomic_inc( &socket_info->send_cnt );
\r
1926 if( lpOverlapped->hEvent == 0)
\r
1928 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1932 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1933 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1936 cl_atomic_inc( &g_ibsp.send_count );
\r
1938 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1939 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1940 GetCurrentThreadId(), lpOverlapped,
\r
1941 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1942 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1948 fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",
\r
1950 __LINE__, GetCurrentProcessId(),
\r
1951 GetCurrentThreadId(),
\r
1952 lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));
\r
1955 if( lpBuffers[0].len >= 40 )
\r
1957 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",
\r
1958 lpBuffers[0].buf, 40 );
\r
1962 status = ib_post_send( socket_info->qp, &send_wr, NULL );
\r
1964 if( status == IB_SUCCESS )
\r
1966 /* Update the index and wrap as needed */
\r
1967 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \
\r
1968 QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \
\r
1969 QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8
\r
1970 socket_info->send_idx++;
\r
1971 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);
\r
1973 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )
\r
1974 socket_info->send_idx = 0;
\r
1978 IBSP_TRACE1( IBSP_DBG_IO,
\r
1979 ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1980 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1982 *lpErrno = WSA_IO_PENDING;
\r
1986 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );
\r
1989 if( lpOverlapped->hEvent == 0 )
\r
1991 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1995 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1996 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1998 cl_atomic_dec( &g_ibsp.send_count );
\r
2000 memset( wr, 0x37, sizeof(struct _wr) );
\r
2002 cl_atomic_dec( &socket_info->send_cnt );
\r
2004 *lpErrno = ibal_to_wsa_error( status );
\r
2006 cl_spinlock_release( &socket_info->send_lock );
\r
2008 /* We never complete the operation here. */
\r
2009 IBSP_EXIT( IBSP_DBG_IO );
\r
2010 return SOCKET_ERROR;
\r
2014 /* Function: IBSPSetSockOpt
\r
2017 * Set a socket option. For most all options we just have to translate the
\r
2018 * socket option and call the lower provider. The only special case is for
\r
2019 * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the
\r
2020 * argument which we need to translate before calling the lower provider.
\r
2027 const char FAR *optval,
\r
2031 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
2033 CL_ENTER( IBSP_DBG_OPT, gdbg_lvl );
\r
2035 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2036 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
2038 if( level != SOL_SOCKET )
\r
2040 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid level %d", level) );
\r
2041 *lpErrno = WSAENOPROTOOPT;
\r
2042 return SOCKET_ERROR;
\r
2045 if( optval == NULL )
\r
2047 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid optval=%p", optval) );
\r
2048 *lpErrno = WSAEFAULT;
\r
2049 return SOCKET_ERROR;
\r
2055 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_DEBUG\n") );
\r
2056 if( optlen != sizeof(BOOL) )
\r
2058 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
2059 ("option len is invalid (0x%x)\n", optlen) );
\r
2060 *lpErrno = WSAEFAULT;
\r
2061 return SOCKET_ERROR;
\r
2063 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );
\r
2066 case SO_GROUP_PRIORITY:
\r
2067 CL_TRACE( IBSP_DBG_OPT, gdbg_lvl, ("Option name SO_GROUP_PRIORITY\n") );
\r
2068 if( optlen != sizeof(int) )
\r
2070 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl,
\r
2071 ("option len is invalid (0x%x)\n", optlen) );
\r
2072 *lpErrno = WSAEFAULT;
\r
2073 return SOCKET_ERROR;
\r
2075 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );
\r
2079 CL_EXIT_ERROR( IBSP_DBG_OPT, gdbg_lvl, ("invalid option %x\n", optname) );
\r
2080 *lpErrno = WSAENOPROTOOPT;
\r
2081 return SOCKET_ERROR;
\r
2085 CL_EXIT( IBSP_DBG_OPT, gdbg_lvl );
\r
2091 /* Function: IBSPSocket
\r
2094 * This function creates a socket. There are two sockets created. The first
\r
2095 * socket is created by calling the lower providers WSPSocket. This is the
\r
2096 * handle that we use internally within our LSP. We then create a second
\r
2097 * socket with WPUCreateSocketHandle which will be returned to the calling
\r
2098 * application. We will also create a socket context structure which will
\r
2099 * maintain information on each socket. This context is associated with the
\r
2100 * socket handle passed to the application.
\r
2102 static SOCKET WSPAPI
\r
2107 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2112 struct ibsp_socket_info *socket_info = NULL;
\r
2114 IBSP_ENTER( IBSP_DBG_SI );
\r
2116 UNUSED_PARAM( g );
\r
2118 if( af != AF_INET )
\r
2121 ("bad family %d instead of %d\n", af, AF_INET) );
\r
2122 *lpErrno = WSAEAFNOSUPPORT;
\r
2126 if( type != SOCK_STREAM )
\r
2129 ("bad type %d instead of %d\n", type, SOCK_STREAM) );
\r
2130 *lpErrno = WSAEPROTOTYPE;
\r
2134 if( protocol != IPPROTO_TCP )
\r
2137 ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );
\r
2138 *lpErrno = WSAEPROTONOSUPPORT;
\r
2142 if( (dwFlags != WSA_FLAG_OVERLAPPED) )
\r
2145 ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );
\r
2146 *lpErrno = WSAEINVAL;
\r
2150 socket_info = create_socket_info();
\r
2151 if( socket_info == NULL )
\r
2153 IBSP_ERROR( ("create_socket_info return NULL\n") );
\r
2154 *lpErrno = WSAENOBUFS;
\r
2158 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2160 /* This is a duplicate socket. */
\r
2163 ret = setup_duplicate_socket( socket_info, lpProtocolInfo->dwProviderReserved );
\r
2167 ("setup_duplicate_socket failed with %d\n",ret) );
\r
2174 socket_info->switch_socket =
\r
2175 g_ibsp.up_call_table.lpWPUCreateSocketHandle( 0,
\r
2176 (DWORD_PTR) socket_info,
\r
2179 if( socket_info->switch_socket != INVALID_SOCKET )
\r
2181 IBSP_TRACE1( IBSP_DBG_SI, ("socket_info=0x%p switch_socket=0x%p \n",
\r
2182 socket_info, socket_info->switch_socket) );
\r
2184 STAT_INC( wpusocket_num );
\r
2188 if( socket_info->switch_socket == INVALID_SOCKET )
\r
2191 ("WPUCreateSocketHandle() failed: %d\n", *lpErrno) );
\r
2192 /* lpErrno has just been set */
\r
2197 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2199 CL_ASSERT( socket_info->socket_state == IBSP_CONNECTED );
\r
2203 socket_info->socket_state = IBSP_CREATE;
\r
2205 /* Set the (non-zero) default socket options for that socket */
\r
2206 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;
\r
2207 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;
\r
2208 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;
\r
2211 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
2212 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );
\r
2213 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
2217 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2218 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
2220 IBSP_TRACE_EXIT( IBSP_DBG_SI,
\r
2221 ("returning socket handle %p\n", socket_info) );
\r
2223 return (SOCKET) socket_info;
\r
2227 free_socket_info( socket_info );
\r
2229 CL_ASSERT( *lpErrno != 0 );
\r
2231 IBSP_ERROR_EXIT( ("Returning error %d\n", *lpErrno) );
\r
2233 return INVALID_SOCKET;
\r
2237 /* Function: IBSPCleanup
\r
2240 * Decrement the entry count. If equal to zero then we can prepare to have us
\r
2241 * unloaded. Close any outstanding sockets and free up allocated memory.
\r
2249 CL_ENTER( IBSP_DBG_INIT, gdbg_lvl );
\r
2251 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2253 if( !g_ibsp.entry_count )
\r
2255 cl_spinlock_release( &g_ibsp.mutex );
\r
2257 *lpErrno = WSANOTINITIALISED;
\r
2259 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl, ("returning WSAENOTINITIALISED\n") );
\r
2261 return SOCKET_ERROR;
\r
2264 /* Decrement the entry count */
\r
2265 g_ibsp.entry_count--;
\r
2267 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("WSPCleanup: %d\n", g_ibsp.entry_count) );
\r
2269 if( g_ibsp.entry_count == 0 )
\r
2271 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("entry_count is 0 => cleaning up\n") );
\r
2275 cl_spinlock_release( &g_ibsp.mutex );
\r
2277 CL_EXIT( IBSP_DBG_INIT, gdbg_lvl );
\r
2284 * Function: WSPStartupEx
\r
2287 * This function intializes the service provider. We maintain a ref count to keep track
\r
2288 * of how many times this function has been called.
\r
2293 LPWSPDATA lpWSPData,
\r
2294 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2295 LPWSPUPCALLTABLEEX UpCallTable,
\r
2296 LPWSPPROC_TABLE lpProcTable )
\r
2298 static WSPPROC_TABLE gProcTable;
\r
2299 static WSPDATA gWSPData;
\r
2301 CL_ENTER( IBSP_DBG_INIT, gdbg_lvl );
\r
2303 /* Make sure that the version requested is >= 2.2. The low byte is the
\r
2304 major version and the high byte is the minor version. */
\r
2305 if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )
\r
2307 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl,
\r
2308 ("Invalid winsock version requested %x\n", wVersion) );
\r
2310 return WSAVERNOTSUPPORTED;
\r
2313 CL_TRACE( IBSP_DBG_INIT, gdbg_lvl, ("entry_count=%d)\n", g_ibsp.entry_count) );
\r
2315 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2317 if( g_ibsp.entry_count == 0 )
\r
2321 /* Save the global WSPData */
\r
2322 gWSPData.wVersion = MAKEWORD(2, 2);
\r
2323 gWSPData.wHighVersion = MAKEWORD(2, 2);
\r
2324 wcscpy( gWSPData.szDescription, Description );
\r
2326 /* provide Service provider's entry points in proc table */
\r
2327 memset( &gProcTable, 0, sizeof(gProcTable) );
\r
2328 gProcTable.lpWSPAccept = IBSPAccept;
\r
2329 gProcTable.lpWSPBind = IBSPBind;
\r
2330 gProcTable.lpWSPCleanup = IBSPCleanup;
\r
2331 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;
\r
2332 gProcTable.lpWSPConnect = IBSPConnect;
\r
2333 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;
\r
2334 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;
\r
2335 gProcTable.lpWSPEventSelect = IBSPEventSelect;
\r
2336 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;
\r
2337 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;
\r
2338 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;
\r
2339 gProcTable.lpWSPIoctl = IBSPIoctl;
\r
2340 gProcTable.lpWSPListen = IBSPListen;
\r
2341 gProcTable.lpWSPRecv = IBSPRecv;
\r
2342 gProcTable.lpWSPSend = IBSPSend;
\r
2343 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;
\r
2344 gProcTable.lpWSPSocket = IBSPSocket;
\r
2346 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */
\r
2347 lpWSPData->wVersion = MAKEWORD(2, 2);
\r
2348 lpWSPData->wHighVersion = MAKEWORD(2, 2);
\r
2349 wcscpy( lpWSPData->szDescription, Description );
\r
2352 /* TODO: remove? */
\r
2353 cl_qlist_init( &g_ibsp.cq_thread_info_list );
\r
2354 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );
\r
2357 g_ibsp.protocol_info = *lpProtocolInfo;
\r
2359 /* Initialize Infiniband */
\r
2360 ret = ibsp_initialize();
\r
2363 CL_EXIT_ERROR( IBSP_DBG_INIT, gdbg_lvl,
\r
2364 ("ibsp_initialize failed (%d)\n", ret) );
\r
2368 g_ibsp.entry_count++;
\r
2370 cl_spinlock_release( &g_ibsp.mutex );
\r
2372 /* Set the return parameters */
\r
2373 *lpWSPData = gWSPData;
\r
2374 *lpProcTable = gProcTable;
\r
2376 /* store the upcall function table */
\r
2377 g_ibsp.up_call_table = *UpCallTable;
\r
2379 CL_EXIT( IBSP_DBG_INIT, gdbg_lvl );
\r