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 IBSP_ENTER( IBSP_DBG_DLL );
\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 IBSP_ERROR_EXIT( ("IBSPLOAD not defined:\n") );
\r
92 case DLL_PROCESS_ATTACH:
\r
93 IBSP_TRACE( IBSP_DBG_DLL, ("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 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_ATTACH\n") );
\r
121 case DLL_THREAD_DETACH:
\r
122 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_DETACH\n") );
\r
125 case DLL_PROCESS_DETACH:
\r
126 IBSP_TRACE( IBSP_DBG_DLL, ("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 IBSP_ERROR( ("Statistics:\n") );
\r
146 (" overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );
\r
148 (" max_comp_count = %d\n", g_ibsp.max_comp_count) );
\r
150 (" overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );
\r
152 IBSP_ERROR( (" send_count = %d\n", g_ibsp.send_count) );
\r
155 (" number of QPs left = %d\n", g_ibsp.qp_num) );
\r
157 (" number of CQs left = %d\n", g_ibsp.cq_num) );
\r
159 (" number of PDs left = %d\n", g_ibsp.pd_num) );
\r
161 (" number of ALs left = %d\n", g_ibsp.al_num) );
\r
163 (" number of MRs left = %d\n", g_ibsp.mr_num) );
\r
165 (" number of listens left = %d\n", g_ibsp.listen_num) );
\r
167 (" number of PNPs left = %d\n", g_ibsp.pnp_num) );
\r
169 (" number of threads left = %d\n", g_ibsp.thread_num) );
\r
171 (" number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );
\r
174 (" CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );
\r
182 IBSP_EXIT( IBSP_DBG_DLL );
\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->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 IBSP_TRACE( IBSP_DBG_CONN,
\r
290 ("IBSPAccept: Found pending connection on this socket\n") );
\r
292 incoming = PARENT_STRUCT(cl_qlist_head( &socket_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->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 IBSP_ERROR_EXIT( ("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->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 IBSP_ERROR_EXIT( ("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
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
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->listen.list, &incoming->item );
\r
444 /* Signal the event again if there are more connection requests. */
\r
445 if( cl_qlist_count( &socket_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 IBSP_TRACE( IBSP_DBG_CONN, ("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->h_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 );
\r
472 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE );
\r
473 cl_spinlock_release( &new_socket_info->mutex );
\r
474 /* Free the socket descriptor */
\r
475 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p calling lpWPUCloseSocketHandle=0x%p\n",
\r
476 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
477 socket_info, socket_info->switch_socket));
\r
479 if( g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
480 new_socket_info->switch_socket, &ret ) == SOCKET_ERROR )
\r
482 IBSP_ERROR( ("WPUCloseSocketHandle failed: %d\n", ret) );
\r
486 STAT_DEC( wpusocket_num );
\r
489 CloseHandle( new_socket_info->h_event );
\r
491 ib_destroy_socket( new_socket_info );
\r
493 free_socket_info( new_socket_info );
\r
495 /* Be nice and reject that connection. */
\r
496 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
498 HeapFree( g_ibsp.heap, 0, incoming );
\r
501 IBSP_ERROR_EXIT( ("ib_accept failed (%d)\n", ret) );
\r
503 return INVALID_SOCKET;
\r
507 cl_spinlock_release( &new_socket_info->mutex );
\r
508 HeapFree( g_ibsp.heap, 0, incoming );
\r
510 if( WaitForSingleObject( new_socket_info->h_event, INFINITE ) == WAIT_OBJECT_0 )
\r
512 CloseHandle( new_socket_info->h_event );
\r
513 new_socket_info->h_event = NULL;
\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->h_event );
\r
565 new_socket_info->h_event = NULL;
\r
567 IBSP_ERROR_EXIT( ("wait for ib_accept failed\n") );
\r
569 *lpErrno = WSAEACCES;
\r
570 return INVALID_SOCKET;
\r
578 /* Function: IBSPBind
\r
581 * Bind the socket to a local address.
\r
587 IN const struct sockaddr FAR *name,
\r
589 OUT LPINT lpErrno )
\r
591 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
592 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
593 struct ibsp_port *port;
\r
596 IBSP_ENTER( IBSP_DBG_CONN );
\r
598 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
599 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
601 IBSP_TRACE( IBSP_DBG_CONN, ("Address to bind to:\n") );
\r
602 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );
\r
604 fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));
\r
606 /* Sanity checks */
\r
607 if( namelen != sizeof(struct sockaddr_in) )
\r
610 ("invalid namelen (%d instead of %d)\n",
\r
611 namelen, sizeof(struct sockaddr_in)) );
\r
612 *lpErrno = WSAEFAULT;
\r
616 if( addr->sin_family != AF_INET )
\r
618 IBSP_ERROR( ("bad family for socket\n") );
\r
619 *lpErrno = WSAEFAULT;
\r
623 /* Check if the ip address is assigned to one of our IBoIB HCA. */
\r
624 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
626 port = get_port_from_ip_address( addr->sin_addr );
\r
630 ("This IP address does not belong to that host (%08x)\n",
\r
631 addr->sin_addr.S_un.S_addr) );
\r
632 *lpErrno = WSAEADDRNOTAVAIL;
\r
641 /* We are going to take this mutex for some time,
\r
642 * but at this stage, it shouldn't impact anything. */
\r
643 cl_spinlock_acquire( &socket_info->mutex );
\r
645 /* Verify the state of the socket */
\r
646 if( socket_info->socket_state != IBSP_CREATE )
\r
648 cl_spinlock_release( &socket_info->mutex );
\r
650 ("Invalid socket state (%s)\n",
\r
651 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
652 *lpErrno = WSAEINVAL;
\r
656 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
658 /* Time to allocate our IB QP */
\r
659 socket_info->port = port;
\r
660 ret = ib_create_socket( socket_info );
\r
663 socket_info->port = NULL;
\r
664 cl_spinlock_release( &socket_info->mutex );
\r
665 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );
\r
666 *lpErrno = WSAENOBUFS;
\r
672 socket_info->local_addr = *addr;
\r
674 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
676 cl_spinlock_release( &socket_info->mutex );
\r
678 IBSP_EXIT( IBSP_DBG_CONN );
\r
682 CL_ASSERT( *lpErrno != 0 );
\r
683 IBSP_TRACE_EXIT( IBSP_DBG_CONN, ("failed with error %d\n", *lpErrno) );
\r
684 return SOCKET_ERROR;
\r
688 /* Function: IBSPCloseSocket
\r
691 * Close the socket handle of the app socket as well as the provider socket.
\r
692 * However, if there are outstanding async IO requests on the app socket
\r
693 * we only close the provider socket. Only when all the IO requests complete
\r
694 * (with error) will we then close the app socket.
\r
701 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
703 IBSP_ENTER( IBSP_DBG_CONN );
\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 IBSP_ERROR_EXIT( ("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( &g_ibsp.socket_info_mutex );
\r
719 cl_qlist_remove_item( &g_ibsp.socket_info_list, &socket_info->item );
\r
720 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
722 shutdown_and_destroy_socket_info( socket_info );
\r
724 IBSP_EXIT( IBSP_DBG_CONN );
\r
731 /* Function: IBSPConnect
\r
734 * Performs a connect call. The only thing we need to do is translate
\r
735 * the socket handle.
\r
740 const struct sockaddr FAR *name,
\r
742 LPWSABUF lpCallerData,
\r
743 LPWSABUF lpCalleeData,
\r
748 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
749 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
751 ib_net64_t dest_port_guid;
\r
752 ib_path_rec_t path_rec;
\r
754 IBSP_ENTER( IBSP_DBG_CONN );
\r
756 UNUSED_PARAM( lpCalleeData );
\r
757 UNUSED_PARAM( lpSQOS );
\r
758 UNUSED_PARAM( lpGQOS );
\r
760 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
761 __LINE__, GetCurrentProcessId(),
\r
762 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
764 IBSP_TRACE( IBSP_DBG_CONN,
\r
765 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );
\r
767 /* Sanity checks */
\r
770 /* We don't support that. The current switch does not use it. */
\r
771 IBSP_ERROR_EXIT( ("lpCallerData.len=%d\n", lpCallerData->len) );
\r
772 *lpErrno = WSAEINVAL;
\r
773 return SOCKET_ERROR;
\r
776 if( namelen < sizeof(struct sockaddr_in) )
\r
779 ("invalid remote address (%d)\n", socket_info->socket_state) );
\r
780 *lpErrno = WSAEFAULT;
\r
781 return SOCKET_ERROR;
\r
784 /* Check if the name (actually address) of peer entity is correct */
\r
785 if( addr->sin_family != AF_INET ||
\r
786 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )
\r
789 ("peer entity address is invalid (%d, %d, %x)\n",
\r
790 addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );
\r
791 *lpErrno = WSAEADDRNOTAVAIL;
\r
792 return SOCKET_ERROR;
\r
795 if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )
\r
797 /* Loopback - let the regular stack take care of that. */
\r
798 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
799 *lpErrno = WSAEADDRNOTAVAIL;
\r
800 return SOCKET_ERROR;
\r
803 /* Get the GUID for that IP address. */
\r
804 ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );
\r
808 ("query_guid_address failed for IP %08x\n",
\r
809 addr->sin_addr.s_addr) );
\r
810 *lpErrno = WSAEADDRNOTAVAIL;
\r
811 return SOCKET_ERROR;
\r
814 IBSP_TRACE( IBSP_DBG_CONN, ("got GUID %I64x for IP %s\n",
\r
815 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );
\r
817 if( dest_port_guid == socket_info->port->guid )
\r
819 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
820 *lpErrno = WSAEADDRNOTAVAIL;
\r
821 return SOCKET_ERROR;
\r
824 /* Get the path record */
\r
825 ret = query_pr( socket_info->port, dest_port_guid, &path_rec );
\r
829 ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
830 *lpErrno = WSAEADDRNOTAVAIL;
\r
831 return SOCKET_ERROR;
\r
834 cl_spinlock_acquire( &socket_info->mutex );
\r
836 /* Verify the state of the socket */
\r
837 switch( socket_info->socket_state )
\r
840 /* Good. That's the only valid state we want. */
\r
843 case IBSP_CONNECTED:
\r
844 IBSP_ERROR( ("Socket is already connected\n") );
\r
845 *lpErrno = WSAEISCONN;
\r
849 IBSP_ERROR( ("Socket is a listening socket\n") );
\r
850 *lpErrno = WSAEINVAL;
\r
854 IBSP_ERROR( ("Socket is not in the bound state (%s)\n",
\r
855 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
856 *lpErrno = WSAEINVAL;
\r
860 /* Store the peer entity's address in socket context */
\r
861 socket_info->peer_addr = *addr;
\r
863 /* Update the socket state */
\r
864 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );
\r
867 *lpErrno = ib_connect( socket_info, &path_rec );
\r
868 if( *lpErrno != WSAEWOULDBLOCK )
\r
870 /* We must be sure none destroyed our socket */
\r
871 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
872 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );
\r
874 IBSP_ERROR( ("ib_connect failed (%d)\n", *lpErrno) );
\r
878 cl_spinlock_release( &socket_info->mutex );
\r
879 IBSP_EXIT( IBSP_DBG_CONN );
\r
880 return SOCKET_ERROR;
\r
884 /* Function: IBSPDuplicateSocket
\r
887 This function provides a WSAPROTOCOL_INFOW structure which can be passed
\r
888 to another process to open a handle to the same socket. First we need
\r
889 to translate the user socket into the provider socket and call the underlying
\r
890 WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us
\r
891 is an out parameter only!
\r
894 IBSPDuplicateSocket(
\r
897 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
900 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
903 IBSP_ENTER( IBSP_DBG_CONN );
\r
905 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
906 __LINE__, GetCurrentProcessId(),
\r
907 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
909 cl_spinlock_acquire( &socket_info->mutex );
\r
910 if( socket_info->socket_state != IBSP_CONNECTED )
\r
912 cl_spinlock_release( &socket_info->mutex );
\r
913 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
914 ("Socket state not IBSP_CONNECTED, state=%s.\n",
\r
915 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
916 *lpErrno = WSAENOTCONN;
\r
917 return SOCKET_ERROR;
\r
920 ret = prepare_duplicate_socket( socket_info, dwProcessId );
\r
921 cl_spinlock_release( &socket_info->mutex );
\r
924 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
925 ("prepare_duplicate_socket failed with %d\n", ret) );
\r
927 return SOCKET_ERROR;
\r
931 IBSP_EXIT( IBSP_DBG_CONN );
\r
932 lpProtocolInfo->dwProviderReserved = socket_info->duplicate.identifier;
\r
939 /* Function: IBSPEnumNetworkEvents
\r
942 * Enumerate the network events for a socket. We only need to
\r
943 * translate the socket handle.
\r
946 IBSPEnumNetworkEvents(
\r
948 WSAEVENT hEventObject,
\r
949 LPWSANETWORKEVENTS lpNetworkEvents,
\r
952 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
954 IBSP_ENTER( IBSP_DBG_NEV );
\r
956 ResetEvent( hEventObject );
\r
958 lpNetworkEvents->lNetworkEvents =
\r
959 InterlockedExchange( &socket_info->network_events, 0 );
\r
961 if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT )
\r
963 IBSP_TRACE1( IBSP_DBG_NEV,
\r
964 ("socket %p notify FD_ACCEPT at time %I64d\n",
\r
965 socket_info, cl_get_time_stamp()) );
\r
966 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0;
\r
969 if( lpNetworkEvents->lNetworkEvents & FD_CONNECT )
\r
971 IBSP_TRACE1( IBSP_DBG_NEV,
\r
972 ("socket %p notify FD_CONNECT %d at time %I64d\n",
\r
973 socket_info, socket_info->errno_connect, cl_get_time_stamp()) );
\r
974 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;
\r
978 IBSP_EXIT( IBSP_DBG_NEV );
\r
983 /* Function: IBSPEventSelect
\r
986 * Register the specified events on the socket with the given event handle.
\r
987 * All we need to do is translate the socket handle.
\r
992 WSAEVENT hEventObject,
\r
993 long lNetworkEvents,
\r
996 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
999 IBSP_ENTER( IBSP_DBG_NEV );
\r
1001 IBSP_TRACE4( IBSP_DBG_NEV,
\r
1002 ("Socket %p requesting notifiction of %d on event %p.\n",
\r
1003 s, lNetworkEvents, hEventObject) );
\r
1005 if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )
\r
1007 IBSP_TRACE_EXIT(IBSP_DBG_NEV,
\r
1008 ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );
\r
1009 *lpErrno = WSAEINVAL;
\r
1010 return SOCKET_ERROR;
\r
1013 CL_ASSERT( lpErrno );
\r
1015 socket_info->event_mask = lNetworkEvents;
\r
1016 InterlockedExchangePointer( &socket_info->event_select, hEventObject );
\r
1018 events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 );
\r
1019 /* Check for existing events and signal as appropriate. */
\r
1020 if( (socket_info->event_mask & events) && hEventObject )
\r
1022 IBSP_TRACE2( IBSP_DBG_NEV,
\r
1023 ("Signaling eventHandle %p .\n", socket_info->event_select) );
\r
1024 SetEvent( hEventObject );
\r
1027 IBSP_EXIT( IBSP_DBG_NEV );
\r
1032 /* Function: IBSPGetOverlappedResult
\r
1035 * This function reports whether the specified overlapped call has
\r
1036 * completed. If it has, return the requested information. If not,
\r
1037 * and fWait is true, wait until completion. Otherwise return an
\r
1038 * error immediately.
\r
1040 static BOOL WSPAPI
\r
1041 IBSPGetOverlappedResult(
\r
1043 IN LPWSAOVERLAPPED lpOverlapped,
\r
1044 OUT LPDWORD lpcbTransfer,
\r
1046 OUT LPDWORD lpdwFlags,
\r
1047 OUT LPINT lpErrno )
\r
1049 struct ibsp_socket_info *p_socket_info;
\r
1052 IBSP_ENTER( IBSP_DBG_IO );
\r
1054 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
1056 CL_ASSERT( fWait == FALSE );
\r
1057 if( fWait == TRUE )
\r
1059 IBSP_ERROR_EXIT( ("fWait not supported\n") );
\r
1060 *lpErrno = WSAENETDOWN;
\r
1064 if( s == INVALID_SOCKET )
\r
1066 /* Seen in real life with overlap/client test.
\r
1067 * The switch closes a socket then calls this. Why? */
\r
1068 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1069 *lpErrno = WSAENOTSOCK;
\r
1070 return SOCKET_ERROR;
\r
1073 if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )
\r
1075 p_socket_info = (struct ibsp_socket_info*)s;
\r
1076 /* Poll just in case it's done. */
\r
1077 ib_cq_comp( p_socket_info->cq_tinfo );
\r
1080 if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )
\r
1082 /* Operation has completed, perhaps with error */
\r
1083 *lpdwFlags = lpOverlapped->Offset;
\r
1084 *lpErrno = lpOverlapped->OffsetHigh;
\r
1087 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )
\r
1089 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1091 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1092 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
1093 lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1094 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1097 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
1099 IBSP_TRACE1( IBSP_DBG_IO,
\r
1100 ("socket=%p completed ov=%p\n", s, lpOverlapped) );
\r
1104 /* Operation is still in progress */
\r
1105 *lpErrno = WSA_IO_INCOMPLETE;
\r
1106 IBSP_TRACE1( IBSP_DBG_IO,
\r
1107 ("socket=%p ov=%p hEvent=%p, operation in progress\n",
\r
1108 s, lpOverlapped, lpOverlapped->hEvent));
\r
1111 *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;
\r
1113 if( *lpErrno == 0 )
\r
1118 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",
\r
1119 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1120 lpOverlapped, *lpErrno, rc));
\r
1122 IBSP_EXIT( IBSP_DBG_IO );
\r
1127 /* Function: IBSPGetSockOpt
\r
1130 * Get the specified socket option. All we need to do is translate the
\r
1142 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1144 IBSP_ENTER( IBSP_DBG_OPT );
\r
1146 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1147 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1149 if( level != SOL_SOCKET )
\r
1151 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
1152 *lpErrno = WSAENOPROTOOPT;
\r
1153 return SOCKET_ERROR;
\r
1156 if( optval == NULL || optlen == NULL )
\r
1159 ("invalid optval=%p or optlen=%p", optval, optlen) );
\r
1160 *lpErrno = WSAEFAULT;
\r
1161 return SOCKET_ERROR;
\r
1167 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
1168 if( *optlen < sizeof(BOOL) )
\r
1171 ("option len is invalid (0x%x)\n", *optlen) );
\r
1172 *optlen = sizeof(BOOL);
\r
1173 *lpErrno = WSAEFAULT;
\r
1174 return SOCKET_ERROR;
\r
1177 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );
\r
1178 *optlen = sizeof(BOOL);
\r
1182 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_ID\n") );
\r
1183 if( *optlen < sizeof(GROUP) )
\r
1186 ("option len is invalid (0x%x)\n", *optlen) );
\r
1187 *optlen = sizeof(GROUP);
\r
1188 *lpErrno = WSAEFAULT;
\r
1189 return SOCKET_ERROR;
\r
1192 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );
\r
1193 *optlen = sizeof(GROUP);
\r
1196 case SO_GROUP_PRIORITY:
\r
1197 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
1199 if( *optlen < sizeof(int) )
\r
1202 ("option len is invalid (0x%x)\n", *optlen) );
\r
1203 *optlen = sizeof(int);
\r
1204 *lpErrno = WSAEFAULT;
\r
1205 return SOCKET_ERROR;
\r
1208 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );
\r
1209 *optlen = sizeof(int);
\r
1212 case SO_MAX_MSG_SIZE:
\r
1213 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_MSG_SIZE\n") );
\r
1215 if( *optlen < sizeof(unsigned int) )
\r
1218 ("option len is invalid (0x%x)\n", *optlen) );
\r
1219 *optlen = sizeof(unsigned int);
\r
1220 *lpErrno = WSAEFAULT;
\r
1221 return SOCKET_ERROR;
\r
1224 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );
\r
1225 *optlen = sizeof(unsigned int);
\r
1228 case SO_MAX_RDMA_SIZE:
\r
1229 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_RDMA_SIZE\n") );
\r
1231 if( *optlen < sizeof(unsigned int) )
\r
1234 ("option len is invalid (0x%x)\n", *optlen) );
\r
1235 *optlen = sizeof(unsigned int);
\r
1236 *lpErrno = WSAEFAULT;
\r
1237 return SOCKET_ERROR;
\r
1240 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );
\r
1241 *optlen = sizeof(unsigned int);
\r
1244 case SO_RDMA_THRESHOLD_SIZE:
\r
1245 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );
\r
1247 if( *optlen < sizeof(unsigned int) )
\r
1250 ("option len is invalid (0x%x)\n", *optlen) );
\r
1251 *optlen = sizeof(unsigned int);
\r
1252 *lpErrno = WSAEFAULT;
\r
1253 return SOCKET_ERROR;
\r
1256 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,
\r
1257 sizeof(unsigned int) );
\r
1258 *optlen = sizeof(unsigned int);
\r
1262 *lpErrno = WSAENOPROTOOPT;
\r
1264 IBSP_ERROR_EXIT( ("unknown option 0x%x\n", optname) );
\r
1266 return SOCKET_ERROR;
\r
1270 IBSP_EXIT( IBSP_DBG_OPT );
\r
1275 /* Function: IBSPGetQOSByName
\r
1278 * Get a QOS template by name. All we need to do is translate the socket
\r
1281 static BOOL WSPAPI
\r
1284 LPWSABUF lpQOSName,
\r
1288 IBSP_ENTER( IBSP_DBG_OPT );
\r
1290 UNUSED_PARAM( s );
\r
1291 UNUSED_PARAM( lpQOSName );
\r
1292 UNUSED_PARAM( lpQOS );
\r
1294 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1295 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1297 *lpErrno = WSAEOPNOTSUPP;
\r
1299 IBSP_ERROR_EXIT( ("not supported\n") );
\r
1305 /* Function: IBSPIoctl
\r
1308 * Invoke an ioctl. In most cases, we just need to translate the socket
\r
1309 * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,
\r
1310 * we'll need to intercept this and return our own function pointers.
\r
1315 IN DWORD dwIoControlCode,
\r
1316 IN LPVOID lpvInBuffer,
\r
1317 IN DWORD cbInBuffer,
\r
1318 OUT LPVOID lpvOutBuffer,
\r
1319 IN DWORD cbOutBuffer,
\r
1320 OUT LPDWORD lpcbBytesReturned,
\r
1321 IN LPWSAOVERLAPPED lpOverlapped,
\r
1322 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1323 IN LPWSATHREADID lpThreadId,
\r
1324 OUT LPINT lpErrno )
\r
1326 struct ibsp_socket_info *socket_info;
\r
1327 GUID SANRegisterMemory = WSAID_REGISTERMEMORY;
\r
1328 GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;
\r
1329 GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;
\r
1330 GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;
\r
1331 GUID SANRDMAWrite = WSAID_RDMAWRITE;
\r
1332 GUID SANRDMARead = WSAID_RDMAREAD;
\r
1333 GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;
\r
1335 IBSP_ENTER( IBSP_DBG_OPT );
\r
1337 UNUSED_PARAM( cbInBuffer );
\r
1338 UNUSED_PARAM( lpOverlapped );
\r
1339 UNUSED_PARAM( lpCompletionRoutine );
\r
1340 UNUSED_PARAM( lpThreadId );
\r
1342 if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )
\r
1344 /* This a special case. The socket handle passed is not valid. */
\r
1345 IBSP_TRACE1( IBSP_DBG_OPT, ("Get extension function pointer\n") );
\r
1347 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )
\r
1349 /* Return a pointer to our intermediate extension function */
\r
1350 *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;
\r
1352 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )
\r
1354 /* Return a pointer to our intermediate extension function */
\r
1355 *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;
\r
1357 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1359 /* Return a pointer to our intermediate extension function */
\r
1360 *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;
\r
1362 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1364 /* Return a pointer to our intermediate extension function */
\r
1365 *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;
\r
1367 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )
\r
1369 /* Return a pointer to our intermediate extension function */
\r
1370 *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;
\r
1372 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )
\r
1376 IBSP_TRACE( IBSP_DBG_WARN | IBSP_DBG_OPT,
\r
1377 ("RDMA_READ disabled.\n") );
\r
1378 *lpErrno = WSAEOPNOTSUPP;
\r
1379 return SOCKET_ERROR;
\r
1383 /* Return a pointer to our intermediate extension function */
\r
1384 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;
\r
1387 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,
\r
1388 sizeof(GUID) ) == 0 )
\r
1390 /* Return a pointer to our intermediate extension function */
\r
1391 *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =
\r
1392 IBSPMemoryRegistrationCacheCallback;
\r
1396 IBSP_ERROR_EXIT( ("invalid extension GUID\n") );
\r
1397 *lpErrno = WSAEINVAL;
\r
1398 return SOCKET_ERROR;
\r
1400 IBSP_EXIT( IBSP_DBG_OPT );
\r
1404 socket_info = (struct ibsp_socket_info *)s;
\r
1406 /* Verify the state of the socket */
\r
1407 /* Not sure which state socket should be in to receive this call */
\r
1408 DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,
\r
1413 cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );
\r
1415 switch( dwIoControlCode )
\r
1418 case SIO_GET_GROUP_QOS:
\r
1420 case SIO_SET_GROUP_QOS:
\r
1421 /* We don't support that. dwServiceFlags1 in installSP
\r
1424 ("unsupported dwIoControlCode %d\n", dwIoControlCode) );
\r
1425 *lpErrno = WSAENOPROTOOPT;
\r
1426 return SOCKET_ERROR;
\r
1429 case SIO_ADDRESS_LIST_QUERY:
\r
1433 *lpcbBytesReturned = cbOutBuffer;
\r
1434 ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,
\r
1435 lpcbBytesReturned, lpErrno );
\r
1437 IBSP_EXIT( IBSP_DBG_OPT );
\r
1444 ("invalid dwIoControlCode %d\n", dwIoControlCode) );
\r
1446 *lpErrno = WSAENOPROTOOPT;
\r
1447 return SOCKET_ERROR;
\r
1455 /* Function: IBSPListen
\r
1458 * This function establishes a socket to listen for incoming connections. It sets
\r
1459 * the backlog value on a listening socket.
\r
1467 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1470 IBSP_ENTER( IBSP_DBG_CONN );
\r
1472 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1473 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1475 cl_spinlock_acquire( &socket_info->mutex );
\r
1477 IBSP_TRACE( IBSP_DBG_CONN, ("socket_state is %s\n",
\r
1478 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1480 /* Verify the state of the socket */
\r
1481 switch( socket_info->socket_state )
\r
1485 /* Store the backlog value in the context */
\r
1486 socket_info->listen.backlog = backlog;
\r
1487 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );
\r
1489 socket_info->listen.listen_req_param.dwProcessId = 0;
\r
1490 socket_info->listen.listen_req_param.identifier = 0;
\r
1492 ret = ib_listen( socket_info );
\r
1495 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
1496 CL_EXIT_ERROR( IBSP_DBG_CONN, gdbg_lvl, ("ib_listen failed with %d\n", ret) );
\r
1501 /* Change the backlog */
\r
1502 ib_listen_backlog( socket_info, backlog );
\r
1508 ("Invalid socket_state (%s)\n",
\r
1509 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1514 cl_spinlock_release( &socket_info->mutex );
\r
1518 IBSP_EXIT( IBSP_DBG_CONN );
\r
1520 return SOCKET_ERROR;
\r
1526 /* Function: IBSPRecv
\r
1529 * This function receives data on a given socket and also allows for asynchronous
\r
1530 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1531 * handle and then make the receive call. If called with overlap, post the operation
\r
1532 * to our IOCP or completion routine.
\r
1537 LPWSABUF lpBuffers,
\r
1538 DWORD dwBufferCount,
\r
1539 LPDWORD lpNumberOfBytesRecvd,
\r
1541 LPWSAOVERLAPPED lpOverlapped,
\r
1542 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1543 LPWSATHREADID lpThreadId,
\r
1546 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1547 ib_api_status_t status;
\r
1548 struct memory_node *node;
\r
1549 struct _recv_wr *wr;
\r
1552 IBSP_ENTER( IBSP_DBG_IO );
\r
1554 UNUSED_PARAM( lpNumberOfBytesRecvd );
\r
1555 UNUSED_PARAM( lpCompletionRoutine );
\r
1556 UNUSED_PARAM( lpThreadId );
\r
1558 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1559 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1561 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1562 CL_ASSERT( lpOverlapped != NULL );
\r
1564 if( s == INVALID_SOCKET )
\r
1566 /* Seen in real life with overlap/client test.
\r
1567 * The switch closes a socket then calls this. Why? */
\r
1568 IBSP_TRACE_EXIT( IBSP_DBG_WARN | IBSP_DBG_IO,
\r
1569 ("invalid socket handle %x\n", s) );
\r
1570 *lpErrno = WSAENOTSOCK;
\r
1571 return SOCKET_ERROR;
\r
1574 /* Check the state of the socket */
\r
1575 if( socket_info->socket_state != IBSP_CONNECTED )
\r
1578 ("Socket is not in connected socket_state state=%s\n",
\r
1579 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1580 *lpErrno = WSAENOTCONN;
\r
1581 return SOCKET_ERROR;
\r
1584 if( socket_info->qp_error != 0 )
\r
1587 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1588 *lpErrno = socket_info->qp_error;
\r
1589 return SOCKET_ERROR;
\r
1592 /* This function only works for that case. Right now the switch is
\r
1593 * only using that. */
\r
1594 if( dwBufferCount > QP_ATTRIB_RQ_SGE )
\r
1596 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );
\r
1598 ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );
\r
1599 *lpErrno = WSAEINVAL;
\r
1600 return SOCKET_ERROR;
\r
1603 cl_spinlock_acquire( &socket_info->recv_lock );
\r
1604 if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )
\r
1606 /* This should never happen */
\r
1607 cl_spinlock_release( &socket_info->recv_lock );
\r
1608 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1609 *lpErrno = WSAENETDOWN;
\r
1610 return SOCKET_ERROR;
\r
1613 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
1615 wr->wr.lpOverlapped = lpOverlapped;
\r
1616 wr->wr.socket_info = socket_info;
\r
1618 /* Looks good. Post the receive buffer. */
\r
1619 wr->recv.p_next = NULL;
\r
1620 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
1621 wr->recv.num_ds = dwBufferCount;
\r
1622 wr->recv.ds_array = wr->ds_array;
\r
1624 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1626 /* Get the memory region node */
\r
1627 node = lookup_partial_mr( &socket_info->buf_mem_list, IB_AC_LOCAL_WRITE,
\r
1628 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1631 cl_spinlock_release( &socket_info->recv_lock );
\r
1633 * No mr fits. This should never happen. This error is not
\r
1634 * official, but seems to be the closest.
\r
1636 IBSP_ERROR_EXIT( ("no MR found\n") );
\r
1637 *lpErrno = WSAEFAULT;
\r
1638 return SOCKET_ERROR;
\r
1641 wr->ds_array[ds_idx].vaddr =
\r
1642 (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1643 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;
\r
1644 wr->ds_array[ds_idx].lkey = node->lkey;
\r
1648 * We must set this now, because the operation could complete
\r
1649 * before ib_post_Recv returns.
\r
1651 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1653 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1654 lpOverlapped->Offset = *lpFlags;
\r
1656 cl_atomic_inc( &socket_info->recv_cnt );
\r
1659 if( lpOverlapped->hEvent == 0 )
\r
1661 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1665 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1666 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1669 cl_atomic_inc( &g_ibsp.recv_count );
\r
1671 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1672 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1673 GetCurrentThreadId(), lpOverlapped,
\r
1674 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1675 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1681 fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",
\r
1682 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1683 lpOverlapped, wr));
\r
1685 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
1687 if( status == IB_SUCCESS )
\r
1689 /* Update the index and wrap as needed */
\r
1690 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
1691 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
1692 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
1693 socket_info->recv_idx++;
\r
1694 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
1696 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
1697 socket_info->recv_idx = 0;
\r
1700 IBSP_TRACE1( IBSP_DBG_IO,
\r
1701 ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1702 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1704 *lpErrno = WSA_IO_PENDING;
\r
1709 ("ib_post_recv returned %s\n", ib_get_err_str( status )) );
\r
1711 if( lpOverlapped->hEvent == 0 )
\r
1713 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1717 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1718 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1721 cl_atomic_dec( &g_ibsp.recv_count );
\r
1723 memset( wr, 0x33, sizeof(struct _recv_wr) );
\r
1726 cl_atomic_dec( &socket_info->recv_cnt );
\r
1727 *lpErrno = ibal_to_wsa_error( status );
\r
1730 cl_spinlock_release( &socket_info->recv_lock );
\r
1732 /* We never complete the operation here. */
\r
1733 IBSP_EXIT( IBSP_DBG_IO );
\r
1734 return SOCKET_ERROR;
\r
1738 /* Function: IBSPSend
\r
1741 * This function sends data on a given socket and also allows for asynchronous
\r
1742 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1743 * handle and then make the send call.
\r
1748 IN LPWSABUF lpBuffers,
\r
1749 IN DWORD dwBufferCount,
\r
1750 OUT LPDWORD lpNumberOfBytesSent,
\r
1752 IN LPWSAOVERLAPPED lpOverlapped,
\r
1753 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1754 IN LPWSATHREADID lpThreadId,
\r
1755 OUT LPINT lpErrno )
\r
1757 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1758 ib_api_status_t status;
\r
1759 struct memory_node *node;
\r
1761 ib_send_wr_t send_wr;
\r
1762 ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE];
\r
1765 IBSP_ENTER( IBSP_DBG_IO );
\r
1767 UNUSED_PARAM( lpNumberOfBytesSent );
\r
1768 UNUSED_PARAM( lpCompletionRoutine );
\r
1769 UNUSED_PARAM( lpThreadId );
\r
1771 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,
\r
1772 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1774 if( s == INVALID_SOCKET )
\r
1776 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1777 *lpErrno = WSAENOTSOCK;
\r
1778 return SOCKET_ERROR;
\r
1781 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1782 CL_ASSERT( lpOverlapped != NULL );
\r
1784 cl_spinlock_acquire( &socket_info->mutex );
\r
1785 /* Check the state of the socket */
\r
1786 switch( socket_info->socket_state )
\r
1788 case IBSP_CONNECTED:
\r
1789 case IBSP_DISCONNECTED:
\r
1793 IBSP_ERROR_EXIT( ("Socket is not in connected socket_state \n") );
\r
1794 *lpErrno = WSAENOTCONN;
\r
1795 return SOCKET_ERROR;
\r
1797 cl_spinlock_release( &socket_info->mutex );
\r
1799 if( socket_info->qp_error )
\r
1802 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1803 *lpErrno = socket_info->qp_error;
\r
1804 return SOCKET_ERROR;
\r
1807 /* This function only works for that case. */
\r
1808 if( dwBufferCount > QP_ATTRIB_SQ_SGE )
\r
1810 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );
\r
1812 ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );
\r
1813 *lpErrno = WSAEINVAL;
\r
1814 return SOCKET_ERROR;
\r
1817 /* The send lock is only used to serialize posting. */
\r
1818 cl_spinlock_acquire( &socket_info->send_lock );
\r
1819 if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )
\r
1821 /* This should never happen */
\r
1822 cl_spinlock_release( &socket_info->send_lock );
\r
1823 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1824 *lpErrno = WSAENETDOWN;
\r
1825 return SOCKET_ERROR;
\r
1828 wr = &socket_info->send_wr[socket_info->send_idx];
\r
1830 wr->lpOverlapped = lpOverlapped;
\r
1831 wr->socket_info = socket_info;
\r
1833 /* Looks good. Post the send buffer. */
\r
1834 send_wr.p_next = NULL;
\r
1835 send_wr.wr_id = (uint64_t) (uintptr_t) wr;
\r
1836 send_wr.wr_type = WR_SEND;
\r
1837 send_wr.send_opt = socket_info->send_opt;
\r
1838 socket_info->send_opt = 0;
\r
1840 send_wr.num_ds = dwBufferCount;
\r
1841 send_wr.ds_array = local_ds;
\r
1843 lpOverlapped->InternalHigh = 0;
\r
1844 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1846 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1847 local_ds[ds_idx].length = lpBuffers[ds_idx].len;
\r
1849 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;
\r
1852 if( lpOverlapped->InternalHigh <= socket_info->max_inline )
\r
1854 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1858 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1860 /* Get the memory region node */
\r
1861 node = lookup_partial_mr( &socket_info->buf_mem_list, 0, /* READ */
\r
1862 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1865 cl_spinlock_release( &socket_info->send_lock );
\r
1867 * No mr fits. This error is not official, but seems to be the
\r
1870 IBSP_ERROR_EXIT( ("mr lookup failed\n") );
\r
1871 *lpErrno = WSAEFAULT;
\r
1872 return SOCKET_ERROR;
\r
1875 local_ds[ds_idx].lkey = node->lkey;
\r
1880 * We must set this now, because the operation could complete
\r
1881 * before ib_post_send returns.
\r
1883 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1885 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1886 lpOverlapped->Offset = dwFlags;
\r
1888 cl_atomic_inc( &socket_info->send_cnt );
\r
1891 if( lpOverlapped->hEvent == 0)
\r
1893 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1897 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1898 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1901 cl_atomic_inc( &g_ibsp.send_count );
\r
1903 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1904 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1905 GetCurrentThreadId(), lpOverlapped,
\r
1906 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1907 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1913 fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",
\r
1915 __LINE__, GetCurrentProcessId(),
\r
1916 GetCurrentThreadId(),
\r
1917 lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));
\r
1920 if( lpBuffers[0].len >= 40 )
\r
1922 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",
\r
1923 lpBuffers[0].buf, 40 );
\r
1927 status = ib_post_send( socket_info->qp, &send_wr, NULL );
\r
1929 if( status == IB_SUCCESS )
\r
1931 /* Update the index and wrap as needed */
\r
1932 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \
\r
1933 QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \
\r
1934 QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8
\r
1935 socket_info->send_idx++;
\r
1936 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);
\r
1938 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )
\r
1939 socket_info->send_idx = 0;
\r
1943 IBSP_TRACE1( IBSP_DBG_IO,
\r
1944 ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1945 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1947 *lpErrno = WSA_IO_PENDING;
\r
1951 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );
\r
1954 if( lpOverlapped->hEvent == 0 )
\r
1956 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1960 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1961 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1963 cl_atomic_dec( &g_ibsp.send_count );
\r
1965 memset( wr, 0x37, sizeof(struct _wr) );
\r
1967 cl_atomic_dec( &socket_info->send_cnt );
\r
1969 *lpErrno = ibal_to_wsa_error( status );
\r
1971 cl_spinlock_release( &socket_info->send_lock );
\r
1973 /* We never complete the operation here. */
\r
1974 IBSP_EXIT( IBSP_DBG_IO );
\r
1975 return SOCKET_ERROR;
\r
1979 /* Function: IBSPSetSockOpt
\r
1982 * Set a socket option. For most all options we just have to translate the
\r
1983 * socket option and call the lower provider. The only special case is for
\r
1984 * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the
\r
1985 * argument which we need to translate before calling the lower provider.
\r
1992 const char FAR *optval,
\r
1996 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1998 IBSP_ENTER( IBSP_DBG_OPT );
\r
2000 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2001 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
2003 if( level != SOL_SOCKET )
\r
2005 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
2006 *lpErrno = WSAENOPROTOOPT;
\r
2007 return SOCKET_ERROR;
\r
2010 if( optval == NULL )
\r
2012 IBSP_ERROR_EXIT( ("invalid optval=%p", optval) );
\r
2013 *lpErrno = WSAEFAULT;
\r
2014 return SOCKET_ERROR;
\r
2020 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
2021 if( optlen != sizeof(BOOL) )
\r
2024 ("option len is invalid (0x%x)\n", optlen) );
\r
2025 *lpErrno = WSAEFAULT;
\r
2026 return SOCKET_ERROR;
\r
2028 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );
\r
2031 case SO_GROUP_PRIORITY:
\r
2032 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
2033 if( optlen != sizeof(int) )
\r
2036 ("option len is invalid (0x%x)\n", optlen) );
\r
2037 *lpErrno = WSAEFAULT;
\r
2038 return SOCKET_ERROR;
\r
2040 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );
\r
2044 IBSP_ERROR_EXIT( ("invalid option %x\n", optname) );
\r
2045 *lpErrno = WSAENOPROTOOPT;
\r
2046 return SOCKET_ERROR;
\r
2050 IBSP_EXIT( IBSP_DBG_OPT );
\r
2056 /* Function: IBSPSocket
\r
2059 * This function creates a socket. There are two sockets created. The first
\r
2060 * socket is created by calling the lower providers WSPSocket. This is the
\r
2061 * handle that we use internally within our LSP. We then create a second
\r
2062 * socket with WPUCreateSocketHandle which will be returned to the calling
\r
2063 * application. We will also create a socket context structure which will
\r
2064 * maintain information on each socket. This context is associated with the
\r
2065 * socket handle passed to the application.
\r
2067 static SOCKET WSPAPI
\r
2072 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2077 struct ibsp_socket_info *socket_info = NULL;
\r
2079 IBSP_ENTER( IBSP_DBG_SI );
\r
2081 UNUSED_PARAM( g );
\r
2083 if( af != AF_INET )
\r
2086 ("bad family %d instead of %d\n", af, AF_INET) );
\r
2087 *lpErrno = WSAEAFNOSUPPORT;
\r
2091 if( type != SOCK_STREAM )
\r
2094 ("bad type %d instead of %d\n", type, SOCK_STREAM) );
\r
2095 *lpErrno = WSAEPROTOTYPE;
\r
2099 if( protocol != IPPROTO_TCP )
\r
2102 ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );
\r
2103 *lpErrno = WSAEPROTONOSUPPORT;
\r
2107 if( (dwFlags != WSA_FLAG_OVERLAPPED) )
\r
2110 ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );
\r
2111 *lpErrno = WSAEINVAL;
\r
2115 socket_info = create_socket_info();
\r
2116 if( socket_info == NULL )
\r
2118 IBSP_ERROR( ("create_socket_info return NULL\n") );
\r
2119 *lpErrno = WSAENOBUFS;
\r
2123 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2125 /* This is a duplicate socket. */
\r
2128 ret = setup_duplicate_socket( socket_info, lpProtocolInfo->dwProviderReserved );
\r
2132 ("setup_duplicate_socket failed with %d\n",ret) );
\r
2139 socket_info->switch_socket =
\r
2140 g_ibsp.up_call_table.lpWPUCreateSocketHandle( 0,
\r
2141 (DWORD_PTR) socket_info,
\r
2144 if( socket_info->switch_socket != INVALID_SOCKET )
\r
2146 IBSP_TRACE1( IBSP_DBG_SI, ("socket_info=0x%p switch_socket=0x%p \n",
\r
2147 socket_info, socket_info->switch_socket) );
\r
2149 STAT_INC( wpusocket_num );
\r
2153 if( socket_info->switch_socket == INVALID_SOCKET )
\r
2156 ("WPUCreateSocketHandle() failed: %d\n", *lpErrno) );
\r
2157 /* lpErrno has just been set */
\r
2162 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2164 CL_ASSERT( socket_info->socket_state == IBSP_CONNECTED );
\r
2168 socket_info->socket_state = IBSP_CREATE;
\r
2170 /* Set the (non-zero) default socket options for that socket */
\r
2171 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;
\r
2172 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;
\r
2173 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;
\r
2176 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
2177 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );
\r
2178 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
2182 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2183 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
2185 IBSP_TRACE_EXIT( IBSP_DBG_SI,
\r
2186 ("returning socket handle %p\n", socket_info) );
\r
2188 return (SOCKET) socket_info;
\r
2192 free_socket_info( socket_info );
\r
2194 CL_ASSERT( *lpErrno != 0 );
\r
2196 IBSP_ERROR_EXIT( ("Returning error %d\n", *lpErrno) );
\r
2198 return INVALID_SOCKET;
\r
2202 /* Function: IBSPCleanup
\r
2205 * Decrement the entry count. If equal to zero then we can prepare to have us
\r
2206 * unloaded. Close any outstanding sockets and free up allocated memory.
\r
2214 IBSP_ENTER( IBSP_DBG_INIT );
\r
2216 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2218 if( !g_ibsp.entry_count )
\r
2220 cl_spinlock_release( &g_ibsp.mutex );
\r
2222 *lpErrno = WSANOTINITIALISED;
\r
2224 IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") );
\r
2226 return SOCKET_ERROR;
\r
2229 /* Decrement the entry count */
\r
2230 g_ibsp.entry_count--;
\r
2232 IBSP_TRACE( IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) );
\r
2234 if( g_ibsp.entry_count == 0 )
\r
2236 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") );
\r
2240 cl_spinlock_release( &g_ibsp.mutex );
\r
2242 IBSP_EXIT( IBSP_DBG_INIT );
\r
2249 * Function: WSPStartupEx
\r
2252 * This function intializes the service provider. We maintain a ref count to keep track
\r
2253 * of how many times this function has been called.
\r
2258 LPWSPDATA lpWSPData,
\r
2259 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2260 LPWSPUPCALLTABLEEX UpCallTable,
\r
2261 LPWSPPROC_TABLE lpProcTable )
\r
2263 static WSPPROC_TABLE gProcTable;
\r
2264 static WSPDATA gWSPData;
\r
2266 IBSP_ENTER( IBSP_DBG_INIT );
\r
2268 /* Make sure that the version requested is >= 2.2. The low byte is the
\r
2269 major version and the high byte is the minor version. */
\r
2270 if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )
\r
2273 ("Invalid winsock version requested %x\n", wVersion) );
\r
2275 return WSAVERNOTSUPPORTED;
\r
2278 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) );
\r
2280 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2282 if( g_ibsp.entry_count == 0 )
\r
2286 /* Save the global WSPData */
\r
2287 gWSPData.wVersion = MAKEWORD(2, 2);
\r
2288 gWSPData.wHighVersion = MAKEWORD(2, 2);
\r
2289 wcscpy( gWSPData.szDescription, Description );
\r
2291 /* provide Service provider's entry points in proc table */
\r
2292 memset( &gProcTable, 0, sizeof(gProcTable) );
\r
2293 gProcTable.lpWSPAccept = IBSPAccept;
\r
2294 gProcTable.lpWSPBind = IBSPBind;
\r
2295 gProcTable.lpWSPCleanup = IBSPCleanup;
\r
2296 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;
\r
2297 gProcTable.lpWSPConnect = IBSPConnect;
\r
2298 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;
\r
2299 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;
\r
2300 gProcTable.lpWSPEventSelect = IBSPEventSelect;
\r
2301 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;
\r
2302 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;
\r
2303 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;
\r
2304 gProcTable.lpWSPIoctl = IBSPIoctl;
\r
2305 gProcTable.lpWSPListen = IBSPListen;
\r
2306 gProcTable.lpWSPRecv = IBSPRecv;
\r
2307 gProcTable.lpWSPSend = IBSPSend;
\r
2308 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;
\r
2309 gProcTable.lpWSPSocket = IBSPSocket;
\r
2311 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */
\r
2312 lpWSPData->wVersion = MAKEWORD(2, 2);
\r
2313 lpWSPData->wHighVersion = MAKEWORD(2, 2);
\r
2314 wcscpy( lpWSPData->szDescription, Description );
\r
2317 /* TODO: remove? */
\r
2318 cl_qlist_init( &g_ibsp.cq_thread_info_list );
\r
2319 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );
\r
2322 g_ibsp.protocol_info = *lpProtocolInfo;
\r
2324 /* Initialize Infiniband */
\r
2325 ret = ibsp_initialize();
\r
2329 ("ibsp_initialize failed (%d)\n", ret) );
\r
2333 g_ibsp.entry_count++;
\r
2335 cl_spinlock_release( &g_ibsp.mutex );
\r
2337 /* Set the return parameters */
\r
2338 *lpWSPData = gWSPData;
\r
2339 *lpProcTable = gProcTable;
\r
2341 /* store the upcall function table */
\r
2342 g_ibsp.up_call_table = *UpCallTable;
\r
2344 IBSP_EXIT( IBSP_DBG_INIT );
\r