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
51 uint32_t g_max_poll = 0;
\r
57 * Provides initialization when the ibspdll DLL is loaded.
\r
59 #pragma auto_inline( off )
\r
62 IN HINSTANCE hinstDll,
\r
64 IN LPVOID lpvReserved )
\r
69 IBSP_ENTER( IBSP_DBG_DLL );
\r
71 UNUSED_PARAM( hinstDll );
\r
72 UNUSED_PARAM( lpvReserved );
\r
74 fzprint(("%s():%d:0x%x:0x%x: hinstDll=%d dwReason=%d lpvReserved=0x%p\n",
\r
76 __LINE__, GetCurrentProcessId(),
\r
77 GetCurrentThreadId(), hinstDll, dwReason, lpvReserved));
\r
83 if( GetEnvironmentVariable( "IBSPLOAD", buf, sizeof(buf) ) == 0 )
\r
85 IBSP_ERROR_EXIT( ("IBSPLOAD not defined:\n") );
\r
94 case DLL_PROCESS_ATTACH:
\r
95 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_ATTACH\n") );
\r
98 i = GetEnvironmentVariable( "IBWSD_DBG", env_var, sizeof(env_var) );
\r
101 gdbg_lvl = _tcstoul( env_var, NULL, 16 );
\r
102 IBSP_TRACE( IBSP_DBG_DLL,
\r
103 ("Given IBWSD_DBG debug level:0x%X\n",
\r
108 /* See if the user wants to disable RDMA reads. */
\r
109 no_read = GetEnvironmentVariable( "IBWSD_NO_READ", NULL, 0 );
\r
111 i = GetEnvironmentVariable( "IBWSD_INLINE", env_var, sizeof(env_var) );
\r
113 g_max_inline = _tcstoul( env_var, NULL, 10 );
\r
115 i = GetEnvironmentVariable( "IBWSD_POLL", env_var, sizeof(env_var) );
\r
117 g_max_poll = _tcstoul( env_var, NULL, 10 );
\r
119 if( init_globals() )
\r
123 case DLL_THREAD_ATTACH:
\r
124 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_ATTACH\n") );
\r
127 case DLL_THREAD_DETACH:
\r
128 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_THREAD_DETACH\n") );
\r
131 case DLL_PROCESS_DETACH:
\r
132 IBSP_TRACE( IBSP_DBG_DLL, ("DllMain: DLL_PROCESS_DETACH\n") );
\r
136 cl_list_item_t *socket_item = NULL;
\r
138 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
140 for( socket_item = cl_qlist_head( &g_ibsp.socket_info_list );
\r
141 socket_item != cl_qlist_end( &g_ibsp.socket_info_list );
\r
142 socket_item = cl_qlist_next( socket_item ) )
\r
144 struct ibsp_socket_info *socket_info = NULL;
\r
145 socket_info = PARENT_STRUCT(socket_item, struct ibsp_socket_info, item);
\r
148 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
150 IBSP_ERROR( ("Statistics:\n") );
\r
152 (" overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );
\r
154 (" max_comp_count = %d\n", g_ibsp.max_comp_count) );
\r
156 (" overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );
\r
158 IBSP_ERROR( (" send_count = %d\n", g_ibsp.send_count) );
\r
161 (" number of QPs left = %d\n", g_ibsp.qp_num) );
\r
163 (" number of CQs left = %d\n", g_ibsp.cq_num) );
\r
165 (" number of PDs left = %d\n", g_ibsp.pd_num) );
\r
167 (" number of ALs left = %d\n", g_ibsp.al_num) );
\r
169 (" number of MRs left = %d\n", g_ibsp.mr_num) );
\r
171 (" number of listens left = %d\n", g_ibsp.listen_num) );
\r
173 (" number of PNPs left = %d\n", g_ibsp.pnp_num) );
\r
175 (" number of threads left = %d\n", g_ibsp.thread_num) );
\r
177 (" number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );
\r
180 (" CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );
\r
188 IBSP_EXIT( IBSP_DBG_DLL );
\r
192 #pragma auto_inline( off )
\r
195 extern BOOL APIENTRY
\r
196 _DllMainCRTStartupForGS(
\r
197 IN HINSTANCE h_module,
\r
198 IN DWORD ul_reason_for_call,
\r
199 IN LPVOID lp_reserved );
\r
204 IN HINSTANCE h_module,
\r
205 IN DWORD ul_reason_for_call,
\r
206 IN LPVOID lp_reserved )
\r
208 switch( ul_reason_for_call )
\r
210 case DLL_PROCESS_ATTACH:
\r
211 if( !_DllMainCRTStartupForGS(
\r
212 h_module, ul_reason_for_call, lp_reserved ) )
\r
217 return _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
219 case DLL_PROCESS_DETACH:
\r
220 _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
222 return _DllMainCRTStartupForGS(
\r
223 h_module, ul_reason_for_call, lp_reserved );
\r
231 IN struct ibsp_socket_info *p_socket,
\r
232 IN struct listen_incoming *p_incoming,
\r
233 IN struct ibsp_port *p_port,
\r
234 OUT LPINT lpErrno )
\r
236 struct ibsp_socket_info *new_socket_info;
\r
239 IBSP_ENTER( IBSP_DBG_CONN );
\r
241 /* Create a new socket here */
\r
242 new_socket_info = create_socket_info( lpErrno );
\r
243 if( !new_socket_info )
\r
246 p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_RESOURCES );
\r
248 IBSP_ERROR_EXIT( ("create_socket_info failed (%d)\n", *lpErrno) );
\r
249 return INVALID_SOCKET;
\r
252 /* Time to allocate our IB QP */
\r
253 new_socket_info->port = p_port;
\r
254 *lpErrno = ib_create_socket( new_socket_info );
\r
257 deref_socket_info( new_socket_info );
\r
260 p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
262 IBSP_ERROR_EXIT( ("ib_create_socket failed (%d)\n", *lpErrno) );
\r
263 return INVALID_SOCKET;
\r
266 /* Store the IP address and port number in the socket context */
\r
267 new_socket_info->local_addr = p_incoming->params.dest;
\r
269 /* Copy the socket context info from parent socket context */
\r
270 new_socket_info->socket_options = p_socket->socket_options;
\r
272 IBSP_TRACE( IBSP_DBG_CONN,
\r
273 ("The socket address of connecting entity is\n") );
\r
274 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, &p_incoming->params.source );
\r
276 new_socket_info->peer_addr = p_incoming->params.source;
\r
278 cl_spinlock_acquire( &new_socket_info->mutex );
\r
279 /* Update the state of the socket context */
\r
280 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CONNECTED );
\r
282 *lpErrno = ib_accept( new_socket_info, &p_incoming->cm_req_received );
\r
285 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE );
\r
286 cl_spinlock_release( &new_socket_info->mutex );
\r
288 if( *lpErrno == WSAEADDRINUSE )
\r
290 /* Be nice and reject that connection. */
\r
291 ib_reject( p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
294 g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
295 new_socket_info->switch_socket, &ret );
\r
296 new_socket_info->switch_socket = INVALID_SOCKET;
\r
297 STAT_DEC( wpusocket_num );
\r
299 ib_destroy_socket( new_socket_info );
\r
300 deref_socket_info( new_socket_info );
\r
301 return INVALID_SOCKET;
\r
304 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
305 cl_qlist_insert_tail(
\r
306 &g_ibsp.socket_info_list, &new_socket_info->item );
\r
307 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
309 cl_spinlock_release( &new_socket_info->mutex );
\r
311 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
312 ("returns new socket (0x%p)\n", new_socket_info) );
\r
313 return (SOCKET)new_socket_info;
\r
317 /* Function: IBSPAccept
\r
320 * Handle the WSAAccept function. The only special consideration here
\r
321 * is the conditional accept callback. You can choose to intercept
\r
322 * this by substituting your own callback (you'll need to keep track
\r
323 * of the user supplied callback so you can trigger that once your
\r
324 * substituted function is triggered).
\r
326 static SOCKET WSPAPI
\r
329 OUT struct sockaddr FAR *addr,
\r
330 IN OUT LPINT addrlen,
\r
331 IN LPCONDITIONPROC lpfnCondition,
\r
332 IN DWORD_PTR dwCallbackData,
\r
333 OUT LPINT lpErrno )
\r
335 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
338 struct listen_incoming *incoming;
\r
339 struct ibsp_port *port;
\r
342 IBSP_ENTER( IBSP_DBG_CONN );
\r
344 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
345 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
347 CL_ASSERT( lpfnCondition );
\r
349 if( *addrlen < sizeof(struct sockaddr_in) )
\r
351 IBSP_ERROR_EXIT( ("invalid addrlen (%d, %d)\n",
\r
352 *addrlen, sizeof(struct sockaddr_in)) );
\r
353 *lpErrno = WSAEFAULT;
\r
354 return INVALID_SOCKET;
\r
357 /* Check if there is any pending connection for this socket. If
\r
358 * there is one, create a socket, and then query the switch about
\r
359 * the pending connection */
\r
361 cl_spinlock_acquire( &socket_info->mutex );
\r
363 /* Verify the state of the socket */
\r
364 if( socket_info->socket_state != IBSP_LISTEN )
\r
366 cl_spinlock_release( &socket_info->mutex );
\r
367 IBSP_ERROR_EXIT( ("Socket is not in right socket_state (%s)\n",
\r
368 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
369 *lpErrno = WSAEINVAL;
\r
370 return INVALID_SOCKET;
\r
373 if( cl_qlist_count( &socket_info->listen.list ) == 0 )
\r
375 cl_spinlock_release( &socket_info->mutex );
\r
377 IBSP_ERROR_EXIT( ("No pending connection found for this socket\n") );
\r
378 *lpErrno = WSAEWOULDBLOCK;
\r
379 return INVALID_SOCKET;
\r
382 IBSP_TRACE( IBSP_DBG_CONN,
\r
383 ("IBSPAccept: Found pending connection on this socket\n") );
\r
385 incoming = PARENT_STRUCT(cl_qlist_remove_head( &socket_info->listen.list ),
\r
386 struct listen_incoming, item);
\r
388 /* Signal the event again if there are more connection requests. */
\r
389 if( cl_qlist_count( &socket_info->listen.list ) )
\r
390 ibsp_post_select_event( socket_info, FD_ACCEPT, 0 );
\r
391 cl_spinlock_release( &socket_info->mutex );
\r
393 port = socket_info->port;
\r
395 /* Find the destination IP address */
\r
398 /* The socket was bound to INADDR_ANY. We must find the correct port
\r
399 * for the new socket. */
\r
400 port = get_port_from_ip_address( incoming->params.dest.sin_addr );
\r
404 ("incoming destination IP address not local (%s)\n",
\r
405 inet_ntoa( incoming->params.dest.sin_addr )) );
\r
410 /* Cross-check with the path info to make sure we are conectiong correctly */
\r
411 if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) )
\r
414 ("GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n",
\r
416 ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) );
\r
419 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
421 HeapFree( g_ibsp.heap, 0, incoming );
\r
422 IBSP_ERROR_EXIT( ("bad incoming parameter\n") );
\r
423 *lpErrno = WSAECONNREFUSED;
\r
424 return INVALID_SOCKET;
\r
428 * Check against the conditional routine if socket can be created
\r
432 /* Set the caller and callee data buffer */
\r
433 caller_id.buf = (char *)&incoming->params.source;
\r
434 caller_id.len = sizeof(incoming->params.source);
\r
436 callee_id.buf = (char *)&incoming->params.dest;
\r
437 callee_id.len = sizeof(incoming->params.dest);
\r
439 IBSP_TRACE( IBSP_DBG_CONN,
\r
440 ("Got incoming conn from %s/%d-%d to %s/%d-%d\n",
\r
441 inet_ntoa( incoming->params.source.sin_addr ),
\r
442 cl_ntoh16( incoming->params.source.sin_port ),
\r
443 incoming->params.source.sin_family,
\r
444 inet_ntoa( incoming->params.dest.sin_addr ),
\r
445 cl_ntoh16( incoming->params.dest.sin_port ),
\r
446 incoming->params.dest.sin_family) );
\r
448 /* Call the conditional function */
\r
449 switch( lpfnCondition( &caller_id, NULL, NULL, NULL,
\r
450 &callee_id, NULL, NULL, dwCallbackData ) )
\r
453 /* Should never happen */
\r
455 ("Conditional routine returned undocumented code\n") );
\r
456 /* Fall through. */
\r
459 IBSP_TRACE1( IBSP_DBG_CONN,
\r
460 ("Conditional routine returned CF_REJECT\n") );
\r
462 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED );
\r
464 HeapFree( g_ibsp.heap, 0, incoming );
\r
465 *lpErrno = WSAECONNREFUSED;
\r
466 IBSP_EXIT( IBSP_DBG_CONN );
\r
467 return INVALID_SOCKET;
\r
471 mra.mra_length = 0;
\r
472 mra.p_mra_pdata = NULL;
\r
473 mra.svc_timeout = 0x15;
\r
474 ib_cm_mra( incoming->cm_req_received.h_cm_req, &mra );
\r
476 /* Put the item back at the head of the list. */
\r
477 cl_spinlock_acquire( &socket_info->mutex );
\r
478 cl_qlist_insert_head( &socket_info->listen.list, &incoming->item );
\r
479 cl_spinlock_release( &socket_info->mutex );
\r
481 IBSP_TRACE1( IBSP_DBG_CONN,
\r
482 ("Conditional routine returned CF_DEFER\n") );
\r
484 *lpErrno = WSATRY_AGAIN;
\r
485 IBSP_EXIT( IBSP_DBG_CONN );
\r
486 return INVALID_SOCKET;
\r
492 s = accept_socket( socket_info, incoming, port, lpErrno );
\r
493 if( s != INVALID_SOCKET )
\r
495 /* Store the client socket address information */
\r
496 memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) );
\r
497 *addrlen = sizeof(struct sockaddr_in);
\r
500 HeapFree( g_ibsp.heap, 0, incoming );
\r
502 IBSP_EXIT( IBSP_DBG_CONN );
\r
507 /* Function: IBSPBind
\r
510 * Bind the socket to a local address.
\r
516 IN const struct sockaddr FAR *name,
\r
518 OUT LPINT lpErrno )
\r
520 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
521 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
522 struct ibsp_port *port;
\r
525 IBSP_ENTER( IBSP_DBG_CONN );
\r
527 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
528 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
530 IBSP_TRACE( IBSP_DBG_CONN, ("Address to bind to:\n") );
\r
531 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );
\r
533 fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));
\r
535 /* Sanity checks */
\r
536 if( namelen != sizeof(struct sockaddr_in) )
\r
539 ("invalid namelen (%d instead of %d)\n",
\r
540 namelen, sizeof(struct sockaddr_in)) );
\r
541 *lpErrno = WSAEFAULT;
\r
545 if( addr->sin_family != AF_INET )
\r
547 IBSP_ERROR( ("bad family for socket\n") );
\r
548 *lpErrno = WSAEFAULT;
\r
552 /* Check if the ip address is assigned to one of our IBoIB HCA. */
\r
553 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
555 port = get_port_from_ip_address( addr->sin_addr );
\r
559 ("This IP address does not belong to that host (%08x)\n",
\r
560 addr->sin_addr.S_un.S_addr) );
\r
561 *lpErrno = WSAEADDRNOTAVAIL;
\r
570 /* We are going to take this mutex for some time,
\r
571 * but at this stage, it shouldn't impact anything. */
\r
572 cl_spinlock_acquire( &socket_info->mutex );
\r
574 /* Verify the state of the socket */
\r
575 if( socket_info->socket_state != IBSP_CREATE )
\r
577 cl_spinlock_release( &socket_info->mutex );
\r
579 ("Invalid socket state (%s)\n",
\r
580 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
581 *lpErrno = WSAEINVAL;
\r
585 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
587 /* Time to allocate our IB QP */
\r
588 socket_info->port = port;
\r
589 ret = ib_create_socket( socket_info );
\r
592 socket_info->port = NULL;
\r
593 cl_spinlock_release( &socket_info->mutex );
\r
594 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );
\r
595 *lpErrno = WSAENOBUFS;
\r
601 socket_info->local_addr = *addr;
\r
603 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
605 cl_spinlock_release( &socket_info->mutex );
\r
607 IBSP_EXIT( IBSP_DBG_CONN );
\r
611 CL_ASSERT( *lpErrno != 0 );
\r
612 IBSP_TRACE_EXIT( IBSP_DBG_CONN, ("failed with error %d\n", *lpErrno) );
\r
613 return SOCKET_ERROR;
\r
617 /* Function: IBSPCloseSocket
\r
620 * Close the socket handle of the app socket as well as the provider socket.
\r
621 * However, if there are outstanding async IO requests on the app socket
\r
622 * we only close the provider socket. Only when all the IO requests complete
\r
623 * (with error) will we then close the app socket.
\r
630 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
632 IBSP_ENTER( IBSP_DBG_CONN );
\r
634 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
635 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
637 if( s == INVALID_SOCKET )
\r
639 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
640 *lpErrno = WSAENOTSOCK;
\r
641 return SOCKET_ERROR;
\r
644 cl_atomic_inc( &g_ibsp.CloseSocket_count );
\r
647 shutdown_and_destroy_socket_info( socket_info );
\r
649 IBSP_EXIT( IBSP_DBG_CONN );
\r
656 /* Function: IBSPConnect
\r
659 * Performs a connect call. The only thing we need to do is translate
\r
660 * the socket handle.
\r
665 const struct sockaddr FAR *name,
\r
667 LPWSABUF lpCallerData,
\r
668 LPWSABUF lpCalleeData,
\r
673 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
674 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
676 ib_net64_t dest_port_guid;
\r
677 ib_path_rec_t path_rec;
\r
679 IBSP_ENTER( IBSP_DBG_CONN );
\r
681 UNUSED_PARAM( lpCalleeData );
\r
682 UNUSED_PARAM( lpSQOS );
\r
683 UNUSED_PARAM( lpGQOS );
\r
685 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
686 __LINE__, GetCurrentProcessId(),
\r
687 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
689 IBSP_TRACE( IBSP_DBG_CONN,
\r
690 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );
\r
692 /* Sanity checks */
\r
695 /* We don't support that. The current switch does not use it. */
\r
696 IBSP_ERROR_EXIT( ("lpCallerData.len=%d\n", lpCallerData->len) );
\r
697 *lpErrno = WSAEINVAL;
\r
698 return SOCKET_ERROR;
\r
701 if( namelen < sizeof(struct sockaddr_in) )
\r
704 ("invalid remote address (%d)\n", socket_info->socket_state) );
\r
705 *lpErrno = WSAEFAULT;
\r
706 return SOCKET_ERROR;
\r
709 /* Check if the name (actually address) of peer entity is correct */
\r
710 if( addr->sin_family != AF_INET ||
\r
711 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )
\r
714 ("peer entity address is invalid (%d, %d, %x)\n",
\r
715 addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );
\r
716 *lpErrno = WSAEADDRNOTAVAIL;
\r
717 return SOCKET_ERROR;
\r
720 if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )
\r
722 /* Loopback - let the regular stack take care of that. */
\r
723 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
724 *lpErrno = WSAEADDRNOTAVAIL;
\r
725 return SOCKET_ERROR;
\r
728 /* Get the GUID for that IP address. */
\r
729 ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );
\r
733 ("query_guid_address failed for IP %08x\n",
\r
734 addr->sin_addr.s_addr) );
\r
735 *lpErrno = WSAEADDRNOTAVAIL;
\r
736 return SOCKET_ERROR;
\r
739 IBSP_TRACE( IBSP_DBG_CONN, ("got GUID %I64x for IP %s\n",
\r
740 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );
\r
742 if( dest_port_guid == socket_info->port->guid )
\r
744 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
745 *lpErrno = WSAEADDRNOTAVAIL;
\r
746 return SOCKET_ERROR;
\r
749 /* Get the path record */
\r
750 ret = query_pr( socket_info->port, dest_port_guid, &path_rec );
\r
754 ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
755 *lpErrno = WSAEADDRNOTAVAIL;
\r
756 return SOCKET_ERROR;
\r
759 cl_spinlock_acquire( &socket_info->mutex );
\r
761 /* Verify the state of the socket */
\r
762 switch( socket_info->socket_state )
\r
765 /* Good. That's the only valid state we want. */
\r
768 case IBSP_CONNECTED:
\r
769 IBSP_ERROR( ("Socket is already connected\n") );
\r
770 *lpErrno = WSAEISCONN;
\r
774 IBSP_ERROR( ("Socket is a listening socket\n") );
\r
775 *lpErrno = WSAEINVAL;
\r
779 IBSP_ERROR( ("Socket is not in the bound state (%s)\n",
\r
780 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
781 *lpErrno = WSAEINVAL;
\r
785 /* Store the peer entity's address in socket context */
\r
786 socket_info->peer_addr = *addr;
\r
788 /* Update the socket state */
\r
789 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );
\r
792 *lpErrno = ib_connect( socket_info, &path_rec );
\r
793 if( *lpErrno != WSAEWOULDBLOCK )
\r
795 /* We must be sure none destroyed our socket */
\r
796 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
797 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );
\r
799 IBSP_ERROR( ("ib_connect failed (%d)\n", *lpErrno) );
\r
803 cl_spinlock_release( &socket_info->mutex );
\r
804 IBSP_EXIT( IBSP_DBG_CONN );
\r
805 return SOCKET_ERROR;
\r
809 /* Function: IBSPDuplicateSocket
\r
812 This function provides a WSAPROTOCOL_INFOW structure which can be passed
\r
813 to another process to open a handle to the same socket. First we need
\r
814 to translate the user socket into the provider socket and call the underlying
\r
815 WSPDuplicateSocket. Note that the lpProtocolInfo structure passed into us
\r
816 is an out parameter only!
\r
819 IBSPDuplicateSocket(
\r
822 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
825 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
828 IBSP_ENTER( IBSP_DBG_CONN );
\r
830 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
831 __LINE__, GetCurrentProcessId(),
\r
832 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
834 cl_spinlock_acquire( &socket_info->mutex );
\r
835 if( socket_info->socket_state != IBSP_CONNECTED )
\r
837 cl_spinlock_release( &socket_info->mutex );
\r
838 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
839 ("Socket state not IBSP_CONNECTED, state=%s.\n",
\r
840 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
841 *lpErrno = WSAENOTCONN;
\r
842 return SOCKET_ERROR;
\r
845 ret = prepare_duplicate_socket( socket_info, dwProcessId );
\r
846 cl_spinlock_release( &socket_info->mutex );
\r
849 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
850 ("prepare_duplicate_socket failed with %d\n", ret) );
\r
852 return SOCKET_ERROR;
\r
856 IBSP_EXIT( IBSP_DBG_CONN );
\r
857 lpProtocolInfo->dwProviderReserved = socket_info->duplicate.identifier;
\r
864 /* Function: IBSPEnumNetworkEvents
\r
867 * Enumerate the network events for a socket. We only need to
\r
868 * translate the socket handle.
\r
871 IBSPEnumNetworkEvents(
\r
873 WSAEVENT hEventObject,
\r
874 LPWSANETWORKEVENTS lpNetworkEvents,
\r
877 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
879 IBSP_ENTER( IBSP_DBG_NEV );
\r
881 ResetEvent( hEventObject );
\r
883 lpNetworkEvents->lNetworkEvents =
\r
884 InterlockedExchange( &socket_info->network_events, 0 );
\r
886 if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT )
\r
888 IBSP_TRACE1( IBSP_DBG_NEV,
\r
889 ("socket %p notify FD_ACCEPT at time %I64d\n",
\r
890 socket_info, cl_get_time_stamp()) );
\r
891 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0;
\r
894 if( lpNetworkEvents->lNetworkEvents & FD_CONNECT )
\r
896 IBSP_TRACE1( IBSP_DBG_NEV,
\r
897 ("socket %p notify FD_CONNECT %d at time %I64d\n",
\r
898 socket_info, socket_info->errno_connect, cl_get_time_stamp()) );
\r
899 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;
\r
903 IBSP_EXIT( IBSP_DBG_NEV );
\r
908 /* Function: IBSPEventSelect
\r
911 * Register the specified events on the socket with the given event handle.
\r
912 * All we need to do is translate the socket handle.
\r
917 WSAEVENT hEventObject,
\r
918 long lNetworkEvents,
\r
921 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
924 IBSP_ENTER( IBSP_DBG_NEV );
\r
926 IBSP_TRACE4( IBSP_DBG_NEV,
\r
927 ("Socket %p requesting notifiction of %d on event %p.\n",
\r
928 s, lNetworkEvents, hEventObject) );
\r
930 if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )
\r
932 IBSP_TRACE_EXIT(IBSP_DBG_NEV,
\r
933 ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );
\r
934 *lpErrno = WSAEINVAL;
\r
935 return SOCKET_ERROR;
\r
938 CL_ASSERT( lpErrno );
\r
940 socket_info->event_mask = lNetworkEvents;
\r
941 InterlockedExchangePointer( &socket_info->event_select, hEventObject );
\r
943 events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 );
\r
944 /* Check for existing events and signal as appropriate. */
\r
945 if( (socket_info->event_mask & events) && hEventObject )
\r
947 IBSP_TRACE2( IBSP_DBG_NEV,
\r
948 ("Signaling eventHandle %p .\n", socket_info->event_select) );
\r
949 SetEvent( hEventObject );
\r
952 IBSP_EXIT( IBSP_DBG_NEV );
\r
957 /* Function: IBSPGetOverlappedResult
\r
960 * This function reports whether the specified overlapped call has
\r
961 * completed. If it has, return the requested information. If not,
\r
962 * and fWait is true, wait until completion. Otherwise return an
\r
963 * error immediately.
\r
966 IBSPGetOverlappedResult(
\r
968 IN LPWSAOVERLAPPED lpOverlapped,
\r
969 OUT LPDWORD lpcbTransfer,
\r
971 OUT LPDWORD lpdwFlags,
\r
972 OUT LPINT lpErrno )
\r
974 struct ibsp_socket_info *p_socket_info;
\r
977 IBSP_ENTER( IBSP_DBG_IO );
\r
979 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
981 CL_ASSERT( fWait == FALSE );
\r
982 if( fWait == TRUE )
\r
984 IBSP_ERROR_EXIT( ("fWait not supported\n") );
\r
985 *lpErrno = WSAENETDOWN;
\r
989 if( s == INVALID_SOCKET )
\r
991 /* Seen in real life with overlap/client test.
\r
992 * The switch closes a socket then calls this. Why? */
\r
993 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
994 *lpErrno = WSAENOTSOCK;
\r
995 return SOCKET_ERROR;
\r
998 if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )
\r
1000 p_socket_info = (struct ibsp_socket_info*)s;
\r
1001 /* Poll just in case it's done. */
\r
1002 ib_cq_comp( p_socket_info->cq_tinfo );
\r
1005 if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )
\r
1007 /* Operation has completed, perhaps with error */
\r
1008 *lpdwFlags = lpOverlapped->Offset;
\r
1009 *lpErrno = lpOverlapped->OffsetHigh;
\r
1012 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )
\r
1014 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1016 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1017 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
1018 lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1019 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1022 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
1024 IBSP_TRACE1( IBSP_DBG_IO,
\r
1025 ("socket=%p completed ov=%p\n", s, lpOverlapped) );
\r
1029 /* Operation is still in progress */
\r
1030 *lpErrno = WSA_IO_INCOMPLETE;
\r
1031 IBSP_TRACE1( IBSP_DBG_IO,
\r
1032 ("socket=%p ov=%p hEvent=%p, operation in progress\n",
\r
1033 s, lpOverlapped, lpOverlapped->hEvent));
\r
1036 *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;
\r
1038 if( *lpErrno == 0 )
\r
1043 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",
\r
1044 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1045 lpOverlapped, *lpErrno, rc));
\r
1047 IBSP_EXIT( IBSP_DBG_IO );
\r
1052 /* Function: IBSPGetSockOpt
\r
1055 * Get the specified socket option. All we need to do is translate the
\r
1067 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1069 IBSP_ENTER( IBSP_DBG_OPT );
\r
1071 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1072 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1074 if( level != SOL_SOCKET )
\r
1076 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
1077 *lpErrno = WSAENOPROTOOPT;
\r
1078 return SOCKET_ERROR;
\r
1081 if( optval == NULL || optlen == NULL )
\r
1084 ("invalid optval=%p or optlen=%p", optval, optlen) );
\r
1085 *lpErrno = WSAEFAULT;
\r
1086 return SOCKET_ERROR;
\r
1092 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
1093 if( *optlen < sizeof(BOOL) )
\r
1096 ("option len is invalid (0x%x)\n", *optlen) );
\r
1097 *optlen = sizeof(BOOL);
\r
1098 *lpErrno = WSAEFAULT;
\r
1099 return SOCKET_ERROR;
\r
1102 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );
\r
1103 *optlen = sizeof(BOOL);
\r
1107 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_ID\n") );
\r
1108 if( *optlen < sizeof(GROUP) )
\r
1111 ("option len is invalid (0x%x)\n", *optlen) );
\r
1112 *optlen = sizeof(GROUP);
\r
1113 *lpErrno = WSAEFAULT;
\r
1114 return SOCKET_ERROR;
\r
1117 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );
\r
1118 *optlen = sizeof(GROUP);
\r
1121 case SO_GROUP_PRIORITY:
\r
1122 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
1124 if( *optlen < sizeof(int) )
\r
1127 ("option len is invalid (0x%x)\n", *optlen) );
\r
1128 *optlen = sizeof(int);
\r
1129 *lpErrno = WSAEFAULT;
\r
1130 return SOCKET_ERROR;
\r
1133 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );
\r
1134 *optlen = sizeof(int);
\r
1137 case SO_MAX_MSG_SIZE:
\r
1138 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_MSG_SIZE\n") );
\r
1140 if( *optlen < sizeof(unsigned int) )
\r
1143 ("option len is invalid (0x%x)\n", *optlen) );
\r
1144 *optlen = sizeof(unsigned int);
\r
1145 *lpErrno = WSAEFAULT;
\r
1146 return SOCKET_ERROR;
\r
1149 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );
\r
1150 *optlen = sizeof(unsigned int);
\r
1153 case SO_MAX_RDMA_SIZE:
\r
1154 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_RDMA_SIZE\n") );
\r
1156 if( *optlen < sizeof(unsigned int) )
\r
1159 ("option len is invalid (0x%x)\n", *optlen) );
\r
1160 *optlen = sizeof(unsigned int);
\r
1161 *lpErrno = WSAEFAULT;
\r
1162 return SOCKET_ERROR;
\r
1165 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );
\r
1166 *optlen = sizeof(unsigned int);
\r
1169 case SO_RDMA_THRESHOLD_SIZE:
\r
1170 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );
\r
1172 if( *optlen < sizeof(unsigned int) )
\r
1175 ("option len is invalid (0x%x)\n", *optlen) );
\r
1176 *optlen = sizeof(unsigned int);
\r
1177 *lpErrno = WSAEFAULT;
\r
1178 return SOCKET_ERROR;
\r
1181 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,
\r
1182 sizeof(unsigned int) );
\r
1183 *optlen = sizeof(unsigned int);
\r
1187 *lpErrno = WSAENOPROTOOPT;
\r
1189 IBSP_ERROR_EXIT( ("unknown option 0x%x\n", optname) );
\r
1191 return SOCKET_ERROR;
\r
1195 IBSP_EXIT( IBSP_DBG_OPT );
\r
1200 /* Function: IBSPGetQOSByName
\r
1203 * Get a QOS template by name. All we need to do is translate the socket
\r
1206 static BOOL WSPAPI
\r
1209 LPWSABUF lpQOSName,
\r
1213 IBSP_ENTER( IBSP_DBG_OPT );
\r
1215 UNUSED_PARAM( s );
\r
1216 UNUSED_PARAM( lpQOSName );
\r
1217 UNUSED_PARAM( lpQOS );
\r
1219 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1220 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1222 *lpErrno = WSAEOPNOTSUPP;
\r
1224 IBSP_ERROR_EXIT( ("not supported\n") );
\r
1230 /* Function: IBSPIoctl
\r
1233 * Invoke an ioctl. In most cases, we just need to translate the socket
\r
1234 * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,
\r
1235 * we'll need to intercept this and return our own function pointers.
\r
1240 IN DWORD dwIoControlCode,
\r
1241 IN LPVOID lpvInBuffer,
\r
1242 IN DWORD cbInBuffer,
\r
1243 OUT LPVOID lpvOutBuffer,
\r
1244 IN DWORD cbOutBuffer,
\r
1245 OUT LPDWORD lpcbBytesReturned,
\r
1246 IN LPWSAOVERLAPPED lpOverlapped,
\r
1247 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1248 IN LPWSATHREADID lpThreadId,
\r
1249 OUT LPINT lpErrno )
\r
1251 struct ibsp_socket_info *socket_info;
\r
1252 GUID SANRegisterMemory = WSAID_REGISTERMEMORY;
\r
1253 GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;
\r
1254 GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;
\r
1255 GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;
\r
1256 GUID SANRDMAWrite = WSAID_RDMAWRITE;
\r
1257 GUID SANRDMARead = WSAID_RDMAREAD;
\r
1258 GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;
\r
1260 IBSP_ENTER( IBSP_DBG_OPT );
\r
1262 UNUSED_PARAM( cbInBuffer );
\r
1263 UNUSED_PARAM( lpOverlapped );
\r
1264 UNUSED_PARAM( lpCompletionRoutine );
\r
1265 UNUSED_PARAM( lpThreadId );
\r
1267 if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )
\r
1269 /* This a special case. The socket handle passed is not valid. */
\r
1270 IBSP_TRACE1( IBSP_DBG_OPT, ("Get extension function pointer\n") );
\r
1272 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )
\r
1274 /* Return a pointer to our intermediate extension function */
\r
1275 *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;
\r
1277 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )
\r
1279 /* Return a pointer to our intermediate extension function */
\r
1280 *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;
\r
1282 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1284 /* Return a pointer to our intermediate extension function */
\r
1285 *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;
\r
1287 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1289 /* Return a pointer to our intermediate extension function */
\r
1290 *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;
\r
1292 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )
\r
1294 /* Return a pointer to our intermediate extension function */
\r
1295 *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;
\r
1297 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )
\r
1301 IBSP_TRACE( IBSP_DBG_WARN | IBSP_DBG_OPT,
\r
1302 ("RDMA_READ disabled.\n") );
\r
1303 *lpErrno = WSAEOPNOTSUPP;
\r
1304 return SOCKET_ERROR;
\r
1308 /* Return a pointer to our intermediate extension function */
\r
1309 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;
\r
1312 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,
\r
1313 sizeof(GUID) ) == 0 )
\r
1315 /* Return a pointer to our intermediate extension function */
\r
1316 *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =
\r
1317 IBSPMemoryRegistrationCacheCallback;
\r
1321 IBSP_ERROR_EXIT( ("invalid extension GUID\n") );
\r
1322 *lpErrno = WSAEINVAL;
\r
1323 return SOCKET_ERROR;
\r
1325 IBSP_EXIT( IBSP_DBG_OPT );
\r
1329 socket_info = (struct ibsp_socket_info *)s;
\r
1331 /* Verify the state of the socket */
\r
1332 /* Not sure which state socket should be in to receive this call */
\r
1333 DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,
\r
1338 cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );
\r
1340 switch( dwIoControlCode )
\r
1343 case SIO_GET_GROUP_QOS:
\r
1345 case SIO_SET_GROUP_QOS:
\r
1346 /* We don't support that. dwServiceFlags1 in installSP
\r
1349 ("unsupported dwIoControlCode %d\n", dwIoControlCode) );
\r
1350 *lpErrno = WSAENOPROTOOPT;
\r
1351 return SOCKET_ERROR;
\r
1354 case SIO_ADDRESS_LIST_QUERY:
\r
1358 *lpcbBytesReturned = cbOutBuffer;
\r
1359 ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,
\r
1360 lpcbBytesReturned, lpErrno );
\r
1362 IBSP_EXIT( IBSP_DBG_OPT );
\r
1369 ("invalid dwIoControlCode %d\n", dwIoControlCode) );
\r
1371 *lpErrno = WSAENOPROTOOPT;
\r
1372 return SOCKET_ERROR;
\r
1380 /* Function: IBSPListen
\r
1383 * This function establishes a socket to listen for incoming connections. It sets
\r
1384 * the backlog value on a listening socket.
\r
1392 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1395 IBSP_ENTER( IBSP_DBG_CONN );
\r
1397 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1398 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1400 cl_spinlock_acquire( &socket_info->mutex );
\r
1402 IBSP_TRACE( IBSP_DBG_CONN, ("socket_state is %s\n",
\r
1403 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1405 /* Verify the state of the socket */
\r
1406 switch( socket_info->socket_state )
\r
1410 /* Store the backlog value in the context */
\r
1411 socket_info->listen.backlog = backlog;
\r
1412 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );
\r
1414 socket_info->listen.listen_req_param.dwProcessId = 0;
\r
1415 socket_info->listen.listen_req_param.identifier = 0;
\r
1417 ret = ib_listen( socket_info );
\r
1420 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
1421 IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", ret) );
\r
1426 /* Change the backlog */
\r
1427 ib_listen_backlog( socket_info, backlog );
\r
1433 ("Invalid socket_state (%s)\n",
\r
1434 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1439 cl_spinlock_release( &socket_info->mutex );
\r
1443 IBSP_EXIT( IBSP_DBG_CONN );
\r
1445 return SOCKET_ERROR;
\r
1451 /* Function: IBSPRecv
\r
1454 * This function receives data on a given socket and also allows for asynchronous
\r
1455 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1456 * handle and then make the receive call. If called with overlap, post the operation
\r
1457 * to our IOCP or completion routine.
\r
1462 LPWSABUF lpBuffers,
\r
1463 DWORD dwBufferCount,
\r
1464 LPDWORD lpNumberOfBytesRecvd,
\r
1466 LPWSAOVERLAPPED lpOverlapped,
\r
1467 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1468 LPWSATHREADID lpThreadId,
\r
1471 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1472 ib_api_status_t status;
\r
1473 struct memory_node *node;
\r
1474 struct _recv_wr *wr;
\r
1477 IBSP_ENTER( IBSP_DBG_IO );
\r
1479 UNUSED_PARAM( lpNumberOfBytesRecvd );
\r
1480 UNUSED_PARAM( lpCompletionRoutine );
\r
1481 UNUSED_PARAM( lpThreadId );
\r
1483 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1484 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1486 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1487 CL_ASSERT( lpOverlapped != NULL );
\r
1489 if( s == INVALID_SOCKET )
\r
1491 /* Seen in real life with overlap/client test.
\r
1492 * The switch closes a socket then calls this. Why? */
\r
1493 IBSP_TRACE_EXIT( IBSP_DBG_WARN | IBSP_DBG_IO,
\r
1494 ("invalid socket handle %x\n", s) );
\r
1495 *lpErrno = WSAENOTSOCK;
\r
1496 return SOCKET_ERROR;
\r
1499 cl_spinlock_acquire( &socket_info->mutex );
\r
1500 switch( socket_info->socket_state )
\r
1502 case IBSP_CONNECTED:
\r
1503 case IBSP_DISCONNECTED:
\r
1507 cl_spinlock_release( &socket_info->mutex );
\r
1509 ("Socket is not in connected socket_state state=%s\n",
\r
1510 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1511 *lpErrno = WSAENOTCONN;
\r
1512 return SOCKET_ERROR;
\r
1514 cl_spinlock_release( &socket_info->mutex );
\r
1516 if( socket_info->qp_error != 0 )
\r
1519 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1520 *lpErrno = socket_info->qp_error;
\r
1521 return SOCKET_ERROR;
\r
1524 /* This function only works for that case. Right now the switch is
\r
1525 * only using that. */
\r
1526 if( dwBufferCount > QP_ATTRIB_RQ_SGE )
\r
1528 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );
\r
1530 ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );
\r
1531 *lpErrno = WSAEINVAL;
\r
1532 return SOCKET_ERROR;
\r
1535 cl_spinlock_acquire( &socket_info->recv_lock );
\r
1536 if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )
\r
1538 /* This should never happen */
\r
1539 cl_spinlock_release( &socket_info->recv_lock );
\r
1540 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1541 *lpErrno = WSAENETDOWN;
\r
1542 return SOCKET_ERROR;
\r
1545 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
1547 wr->wr.lpOverlapped = lpOverlapped;
\r
1548 wr->wr.socket_info = socket_info;
\r
1550 /* Looks good. Post the receive buffer. */
\r
1551 wr->recv.p_next = NULL;
\r
1552 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
1553 wr->recv.num_ds = dwBufferCount;
\r
1554 wr->recv.ds_array = wr->ds_array;
\r
1556 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1558 /* Get the memory region node */
\r
1559 node = lookup_partial_mr( socket_info, IB_AC_LOCAL_WRITE,
\r
1560 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1563 cl_spinlock_release( &socket_info->recv_lock );
\r
1565 * No mr fits. This should never happen. This error is not
\r
1566 * official, but seems to be the closest.
\r
1568 IBSP_ERROR_EXIT( ("no MR found\n") );
\r
1569 *lpErrno = WSAEFAULT;
\r
1570 return SOCKET_ERROR;
\r
1573 wr->ds_array[ds_idx].vaddr =
\r
1574 (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1575 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;
\r
1576 wr->ds_array[ds_idx].lkey = node->p_reg->lkey;
\r
1580 * We must set this now, because the operation could complete
\r
1581 * before ib_post_Recv returns.
\r
1583 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1585 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1586 lpOverlapped->Offset = *lpFlags;
\r
1588 cl_atomic_inc( &socket_info->recv_cnt );
\r
1591 if( lpOverlapped->hEvent == 0 )
\r
1593 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1597 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1598 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1601 cl_atomic_inc( &g_ibsp.recv_count );
\r
1603 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1604 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1605 GetCurrentThreadId(), lpOverlapped,
\r
1606 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1607 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1613 fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",
\r
1614 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1615 lpOverlapped, wr));
\r
1617 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
1619 if( status == IB_SUCCESS )
\r
1621 /* Update the index and wrap as needed */
\r
1622 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
1623 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
1624 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
1625 socket_info->recv_idx++;
\r
1626 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
1628 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
1629 socket_info->recv_idx = 0;
\r
1632 IBSP_TRACE1( IBSP_DBG_IO,
\r
1633 ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1634 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1636 *lpErrno = WSA_IO_PENDING;
\r
1641 ("ib_post_recv returned %s\n", ib_get_err_str( status )) );
\r
1643 if( lpOverlapped->hEvent == 0 )
\r
1645 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1649 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1650 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1653 cl_atomic_dec( &g_ibsp.recv_count );
\r
1655 memset( wr, 0x33, sizeof(struct _recv_wr) );
\r
1658 cl_atomic_dec( &socket_info->recv_cnt );
\r
1659 *lpErrno = ibal_to_wsa_error( status );
\r
1662 cl_spinlock_release( &socket_info->recv_lock );
\r
1664 /* We never complete the operation here. */
\r
1665 IBSP_EXIT( IBSP_DBG_IO );
\r
1666 return SOCKET_ERROR;
\r
1670 /* Function: IBSPSend
\r
1673 * This function sends data on a given socket and also allows for asynchronous
\r
1674 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1675 * handle and then make the send call.
\r
1680 IN LPWSABUF lpBuffers,
\r
1681 IN DWORD dwBufferCount,
\r
1682 OUT LPDWORD lpNumberOfBytesSent,
\r
1684 IN LPWSAOVERLAPPED lpOverlapped,
\r
1685 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1686 IN LPWSATHREADID lpThreadId,
\r
1687 OUT LPINT lpErrno )
\r
1689 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1690 ib_api_status_t status;
\r
1691 struct memory_node *node;
\r
1693 ib_send_wr_t send_wr;
\r
1694 ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE];
\r
1697 IBSP_ENTER( IBSP_DBG_IO );
\r
1699 UNUSED_PARAM( lpNumberOfBytesSent );
\r
1700 UNUSED_PARAM( lpCompletionRoutine );
\r
1701 UNUSED_PARAM( lpThreadId );
\r
1703 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,
\r
1704 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1706 if( s == INVALID_SOCKET )
\r
1708 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1709 *lpErrno = WSAENOTSOCK;
\r
1710 return SOCKET_ERROR;
\r
1713 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1714 CL_ASSERT( lpOverlapped != NULL );
\r
1716 cl_spinlock_acquire( &socket_info->mutex );
\r
1717 switch( socket_info->socket_state )
\r
1719 case IBSP_CONNECTED:
\r
1720 case IBSP_DISCONNECTED:
\r
1724 cl_spinlock_release( &socket_info->mutex );
\r
1726 ("Socket is not in connected socket_state state=%s\n",
\r
1727 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1728 *lpErrno = WSAENOTCONN;
\r
1729 return SOCKET_ERROR;
\r
1731 cl_spinlock_release( &socket_info->mutex );
\r
1733 if( socket_info->qp_error )
\r
1736 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1737 *lpErrno = socket_info->qp_error;
\r
1738 return SOCKET_ERROR;
\r
1741 /* This function only works for that case. */
\r
1742 if( dwBufferCount > QP_ATTRIB_SQ_SGE )
\r
1744 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );
\r
1746 ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );
\r
1747 *lpErrno = WSAEINVAL;
\r
1748 return SOCKET_ERROR;
\r
1751 /* The send lock is only used to serialize posting. */
\r
1752 cl_spinlock_acquire( &socket_info->send_lock );
\r
1753 if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )
\r
1755 /* This should never happen */
\r
1756 cl_spinlock_release( &socket_info->send_lock );
\r
1757 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1758 *lpErrno = WSAENETDOWN;
\r
1759 return SOCKET_ERROR;
\r
1762 wr = &socket_info->send_wr[socket_info->send_idx];
\r
1764 wr->lpOverlapped = lpOverlapped;
\r
1765 wr->socket_info = socket_info;
\r
1767 /* Looks good. Post the send buffer. */
\r
1768 send_wr.p_next = NULL;
\r
1769 send_wr.wr_id = (uint64_t) (uintptr_t) wr;
\r
1770 send_wr.wr_type = WR_SEND;
\r
1771 send_wr.send_opt = socket_info->send_opt;
\r
1772 socket_info->send_opt = 0;
\r
1774 send_wr.num_ds = dwBufferCount;
\r
1775 send_wr.ds_array = local_ds;
\r
1777 lpOverlapped->InternalHigh = 0;
\r
1778 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1780 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1781 local_ds[ds_idx].length = lpBuffers[ds_idx].len;
\r
1783 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;
\r
1786 if( lpOverlapped->InternalHigh <= socket_info->max_inline )
\r
1788 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1792 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1794 /* Get the memory region node */
\r
1795 node = lookup_partial_mr( socket_info, 0, /* READ */
\r
1796 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1799 cl_spinlock_release( &socket_info->send_lock );
\r
1801 * No mr fits. This error is not official, but seems to be the
\r
1804 IBSP_ERROR_EXIT( ("mr lookup failed\n") );
\r
1805 *lpErrno = WSAEFAULT;
\r
1806 return SOCKET_ERROR;
\r
1809 local_ds[ds_idx].lkey = node->p_reg->lkey;
\r
1814 * We must set this now, because the operation could complete
\r
1815 * before ib_post_send returns.
\r
1817 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1819 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1820 lpOverlapped->Offset = dwFlags;
\r
1822 cl_atomic_inc( &socket_info->send_cnt );
\r
1825 if( lpOverlapped->hEvent == 0)
\r
1827 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1831 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1832 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1835 cl_atomic_inc( &g_ibsp.send_count );
\r
1837 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1838 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1839 GetCurrentThreadId(), lpOverlapped,
\r
1840 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1841 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1847 fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",
\r
1849 __LINE__, GetCurrentProcessId(),
\r
1850 GetCurrentThreadId(),
\r
1851 lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));
\r
1854 if( lpBuffers[0].len >= 40 )
\r
1856 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",
\r
1857 lpBuffers[0].buf, 40 );
\r
1861 status = ib_post_send( socket_info->qp, &send_wr, NULL );
\r
1863 if( status == IB_SUCCESS )
\r
1865 /* Update the index and wrap as needed */
\r
1866 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \
\r
1867 QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \
\r
1868 QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8
\r
1869 socket_info->send_idx++;
\r
1870 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);
\r
1872 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )
\r
1873 socket_info->send_idx = 0;
\r
1877 IBSP_TRACE1( IBSP_DBG_IO,
\r
1878 ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1879 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1881 *lpErrno = WSA_IO_PENDING;
\r
1885 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );
\r
1888 if( lpOverlapped->hEvent == 0 )
\r
1890 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1894 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1895 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1897 cl_atomic_dec( &g_ibsp.send_count );
\r
1899 memset( wr, 0x37, sizeof(struct _wr) );
\r
1901 cl_atomic_dec( &socket_info->send_cnt );
\r
1903 *lpErrno = ibal_to_wsa_error( status );
\r
1905 cl_spinlock_release( &socket_info->send_lock );
\r
1907 /* We never complete the operation here. */
\r
1908 IBSP_EXIT( IBSP_DBG_IO );
\r
1909 return SOCKET_ERROR;
\r
1913 /* Function: IBSPSetSockOpt
\r
1916 * Set a socket option. For most all options we just have to translate the
\r
1917 * socket option and call the lower provider. The only special case is for
\r
1918 * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the
\r
1919 * argument which we need to translate before calling the lower provider.
\r
1926 const char FAR *optval,
\r
1930 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1932 IBSP_ENTER( IBSP_DBG_OPT );
\r
1934 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1935 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1937 if( level != SOL_SOCKET )
\r
1939 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
1940 *lpErrno = WSAENOPROTOOPT;
\r
1941 return SOCKET_ERROR;
\r
1944 if( optval == NULL )
\r
1946 IBSP_ERROR_EXIT( ("invalid optval=%p", optval) );
\r
1947 *lpErrno = WSAEFAULT;
\r
1948 return SOCKET_ERROR;
\r
1954 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
1955 if( optlen != sizeof(BOOL) )
\r
1958 ("option len is invalid (0x%x)\n", optlen) );
\r
1959 *lpErrno = WSAEFAULT;
\r
1960 return SOCKET_ERROR;
\r
1962 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );
\r
1965 case SO_GROUP_PRIORITY:
\r
1966 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
1967 if( optlen != sizeof(int) )
\r
1970 ("option len is invalid (0x%x)\n", optlen) );
\r
1971 *lpErrno = WSAEFAULT;
\r
1972 return SOCKET_ERROR;
\r
1974 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );
\r
1978 IBSP_ERROR_EXIT( ("invalid option %x\n", optname) );
\r
1979 *lpErrno = WSAENOPROTOOPT;
\r
1980 return SOCKET_ERROR;
\r
1984 IBSP_EXIT( IBSP_DBG_OPT );
\r
1990 /* Function: IBSPSocket
\r
1993 * This function creates a socket. There are two sockets created. The first
\r
1994 * socket is created by calling the lower providers WSPSocket. This is the
\r
1995 * handle that we use internally within our LSP. We then create a second
\r
1996 * socket with WPUCreateSocketHandle which will be returned to the calling
\r
1997 * application. We will also create a socket context structure which will
\r
1998 * maintain information on each socket. This context is associated with the
\r
1999 * socket handle passed to the application.
\r
2001 static SOCKET WSPAPI
\r
2006 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2011 struct ibsp_socket_info *socket_info = NULL;
\r
2013 IBSP_ENTER( IBSP_DBG_SI );
\r
2015 UNUSED_PARAM( g );
\r
2017 if( af != AF_INET )
\r
2020 ("bad family %d instead of %d\n", af, AF_INET) );
\r
2021 *lpErrno = WSAEAFNOSUPPORT;
\r
2022 return INVALID_SOCKET;
\r
2025 if( type != SOCK_STREAM )
\r
2028 ("bad type %d instead of %d\n", type, SOCK_STREAM) );
\r
2029 *lpErrno = WSAEPROTOTYPE;
\r
2030 return INVALID_SOCKET;
\r
2033 if( protocol != IPPROTO_TCP )
\r
2036 ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );
\r
2037 *lpErrno = WSAEPROTONOSUPPORT;
\r
2038 return INVALID_SOCKET;
\r
2041 if( (dwFlags != WSA_FLAG_OVERLAPPED) )
\r
2044 ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );
\r
2045 *lpErrno = WSAEINVAL;
\r
2046 return INVALID_SOCKET;
\r
2049 socket_info = create_socket_info( lpErrno );
\r
2050 if( socket_info == NULL )
\r
2052 IBSP_ERROR_EXIT( ("create_socket_info return NULL\n") );
\r
2053 return INVALID_SOCKET;
\r
2056 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2058 /* This is a duplicate socket. */
\r
2059 *lpErrno = setup_duplicate_socket(
\r
2060 socket_info, lpProtocolInfo->dwProviderReserved );
\r
2063 deref_socket_info( socket_info );
\r
2065 ("setup_duplicate_socket failed with %d\n", *lpErrno) );
\r
2066 return INVALID_SOCKET;
\r
2071 socket_info->socket_state = IBSP_CREATE;
\r
2073 /* Set the (non-zero) default socket options for that socket */
\r
2074 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;
\r
2075 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;
\r
2076 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;
\r
2079 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
2080 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );
\r
2081 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
2085 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2086 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
2088 IBSP_TRACE_EXIT( IBSP_DBG_SI,
\r
2089 ("returning socket handle %p\n", socket_info) );
\r
2091 return (SOCKET) socket_info;
\r
2095 /* Function: IBSPCleanup
\r
2098 * Decrement the entry count. If equal to zero then we can prepare to have us
\r
2099 * unloaded. Close any outstanding sockets and free up allocated memory.
\r
2107 IBSP_ENTER( IBSP_DBG_INIT );
\r
2109 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2111 if( !g_ibsp.entry_count )
\r
2113 cl_spinlock_release( &g_ibsp.mutex );
\r
2115 *lpErrno = WSANOTINITIALISED;
\r
2117 IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") );
\r
2119 return SOCKET_ERROR;
\r
2122 /* Decrement the entry count */
\r
2123 g_ibsp.entry_count--;
\r
2125 IBSP_TRACE( IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) );
\r
2127 if( g_ibsp.entry_count == 0 )
\r
2129 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") );
\r
2133 cl_spinlock_release( &g_ibsp.mutex );
\r
2135 IBSP_EXIT( IBSP_DBG_INIT );
\r
2142 * Function: WSPStartupEx
\r
2145 * This function intializes the service provider. We maintain a ref count to keep track
\r
2146 * of how many times this function has been called.
\r
2151 LPWSPDATA lpWSPData,
\r
2152 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2153 LPWSPUPCALLTABLEEX UpCallTable,
\r
2154 LPWSPPROC_TABLE lpProcTable )
\r
2156 static WSPPROC_TABLE gProcTable;
\r
2157 static WSPDATA gWSPData;
\r
2159 IBSP_ENTER( IBSP_DBG_INIT );
\r
2161 /* Make sure that the version requested is >= 2.2. The low byte is the
\r
2162 major version and the high byte is the minor version. */
\r
2163 if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )
\r
2166 ("Invalid winsock version requested %x\n", wVersion) );
\r
2168 return WSAVERNOTSUPPORTED;
\r
2171 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) );
\r
2173 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2175 if( g_ibsp.entry_count == 0 )
\r
2179 /* Save the global WSPData */
\r
2180 gWSPData.wVersion = MAKEWORD(2, 2);
\r
2181 gWSPData.wHighVersion = MAKEWORD(2, 2);
\r
2182 wcscpy( gWSPData.szDescription, Description );
\r
2184 /* provide Service provider's entry points in proc table */
\r
2185 memset( &gProcTable, 0, sizeof(gProcTable) );
\r
2186 gProcTable.lpWSPAccept = IBSPAccept;
\r
2187 gProcTable.lpWSPBind = IBSPBind;
\r
2188 gProcTable.lpWSPCleanup = IBSPCleanup;
\r
2189 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;
\r
2190 gProcTable.lpWSPConnect = IBSPConnect;
\r
2191 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;
\r
2192 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;
\r
2193 gProcTable.lpWSPEventSelect = IBSPEventSelect;
\r
2194 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;
\r
2195 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;
\r
2196 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;
\r
2197 gProcTable.lpWSPIoctl = IBSPIoctl;
\r
2198 gProcTable.lpWSPListen = IBSPListen;
\r
2199 gProcTable.lpWSPRecv = IBSPRecv;
\r
2200 gProcTable.lpWSPSend = IBSPSend;
\r
2201 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;
\r
2202 gProcTable.lpWSPSocket = IBSPSocket;
\r
2204 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */
\r
2205 lpWSPData->wVersion = MAKEWORD(2, 2);
\r
2206 lpWSPData->wHighVersion = MAKEWORD(2, 2);
\r
2207 wcscpy( lpWSPData->szDescription, Description );
\r
2210 /* TODO: remove? */
\r
2211 cl_qlist_init( &g_ibsp.cq_thread_info_list );
\r
2212 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );
\r
2215 g_ibsp.protocol_info = *lpProtocolInfo;
\r
2217 /* Initialize Infiniband */
\r
2218 ret = ibsp_initialize();
\r
2222 ("ibsp_initialize failed (%d)\n", ret) );
\r
2226 g_ibsp.entry_count++;
\r
2228 cl_spinlock_release( &g_ibsp.mutex );
\r
2230 /* Set the return parameters */
\r
2231 *lpWSPData = gWSPData;
\r
2232 *lpProcTable = gProcTable;
\r
2234 /* store the upcall function table */
\r
2235 g_ibsp.up_call_table = *UpCallTable;
\r
2237 IBSP_EXIT( IBSP_DBG_INIT );
\r