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
147 #ifdef IBSP_LOGGING
\r
148 DataLogger_Shutdown(&socket_info->SendDataLogger);
\r
149 DataLogger_Shutdown(&socket_info->RecvDataLogger);
\r
153 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
155 IBSP_ERROR( ("Statistics:\n") );
\r
157 (" overlap_h0_count = %d\n", g_ibsp.overlap_h0_count) );
\r
159 (" max_comp_count = %d\n", g_ibsp.max_comp_count) );
\r
161 (" overlap_h1_count = %d\n", g_ibsp.overlap_h1_count) );
\r
163 IBSP_ERROR( (" send_count = %d\n", g_ibsp.send_count) );
\r
166 (" number of QPs left = %d\n", g_ibsp.qp_num) );
\r
168 (" number of CQs left = %d\n", g_ibsp.cq_num) );
\r
170 (" number of PDs left = %d\n", g_ibsp.pd_num) );
\r
172 (" number of ALs left = %d\n", g_ibsp.al_num) );
\r
174 (" number of MRs left = %d\n", g_ibsp.mr_num) );
\r
176 (" number of listens left = %d\n", g_ibsp.listen_num) );
\r
178 (" number of PNPs left = %d\n", g_ibsp.pnp_num) );
\r
180 (" number of threads left = %d\n", g_ibsp.thread_num) );
\r
182 (" number of WPU sockets left = %d\n", g_ibsp.wpusocket_num) );
\r
185 (" CloseSocket_count = %d\n", g_ibsp.CloseSocket_count) );
\r
193 IBSP_EXIT( IBSP_DBG_DLL );
\r
197 #pragma auto_inline( off )
\r
200 extern BOOL APIENTRY
\r
201 _DllMainCRTStartupForGS(
\r
202 IN HINSTANCE h_module,
\r
203 IN DWORD ul_reason_for_call,
\r
204 IN LPVOID lp_reserved );
\r
209 IN HINSTANCE h_module,
\r
210 IN DWORD ul_reason_for_call,
\r
211 IN LPVOID lp_reserved )
\r
213 switch( ul_reason_for_call )
\r
215 case DLL_PROCESS_ATTACH:
\r
216 if( !_DllMainCRTStartupForGS(
\r
217 h_module, ul_reason_for_call, lp_reserved ) )
\r
222 return _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
224 case DLL_PROCESS_DETACH:
\r
225 _DllMain( h_module, ul_reason_for_call, lp_reserved );
\r
227 return _DllMainCRTStartupForGS(
\r
228 h_module, ul_reason_for_call, lp_reserved );
\r
236 IN struct ibsp_socket_info *p_socket,
\r
237 IN struct listen_incoming *p_incoming,
\r
238 IN struct ibsp_port *p_port,
\r
239 OUT LPINT lpErrno )
\r
241 struct ibsp_socket_info *new_socket_info;
\r
244 IBSP_ENTER( IBSP_DBG_CONN );
\r
246 /* Create a new socket here */
\r
247 new_socket_info = create_socket_info( lpErrno );
\r
248 if( !new_socket_info )
\r
251 p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_RESOURCES );
\r
253 IBSP_ERROR_EXIT( ("create_socket_info failed (%d)\n", *lpErrno) );
\r
254 return INVALID_SOCKET;
\r
257 /* Time to allocate our IB QP */
\r
258 new_socket_info->port = p_port;
\r
259 *lpErrno = ib_create_socket( new_socket_info );
\r
262 deref_socket_info( new_socket_info );
\r
265 p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
267 IBSP_ERROR_EXIT( ("ib_create_socket failed (%d)\n", *lpErrno) );
\r
268 return INVALID_SOCKET;
\r
271 /* Store the IP address and port number in the socket context */
\r
272 new_socket_info->local_addr = p_incoming->params.dest;
\r
274 /* Copy the socket context info from parent socket context */
\r
275 new_socket_info->socket_options = p_socket->socket_options;
\r
277 IBSP_TRACE( IBSP_DBG_CONN,
\r
278 ("The socket address of connecting entity is\n") );
\r
279 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, &p_incoming->params.source );
\r
281 new_socket_info->peer_addr = p_incoming->params.source;
\r
283 #ifdef IBSP_LOGGING
\r
284 DataLogger_Init( &new_socket_info->SendDataLogger, "Send",
\r
285 &new_socket_info->peer_addr, &new_socket_info->local_addr );
\r
286 DataLogger_Init( &new_socket_info->RecvDataLogger, "Recv",
\r
287 &new_socket_info->local_addr, &new_socket_info->peer_addr );
\r
290 cl_spinlock_acquire( &new_socket_info->mutex );
\r
291 /* Update the state of the socket context */
\r
292 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CONNECTED );
\r
294 *lpErrno = ib_accept( new_socket_info, &p_incoming->cm_req_received );
\r
297 IBSP_CHANGE_SOCKET_STATE( new_socket_info, IBSP_CREATE );
\r
298 cl_spinlock_release( &new_socket_info->mutex );
\r
300 if( *lpErrno == WSAEADDRINUSE )
\r
302 /* Be nice and reject that connection. */
\r
303 ib_reject( p_incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
306 g_ibsp.up_call_table.lpWPUCloseSocketHandle(
\r
307 new_socket_info->switch_socket, &ret );
\r
308 new_socket_info->switch_socket = INVALID_SOCKET;
\r
309 STAT_DEC( wpusocket_num );
\r
311 ib_destroy_socket( new_socket_info );
\r
312 deref_socket_info( new_socket_info );
\r
313 return INVALID_SOCKET;
\r
316 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
317 cl_qlist_insert_tail(
\r
318 &g_ibsp.socket_info_list, &new_socket_info->item );
\r
319 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
321 cl_spinlock_release( &new_socket_info->mutex );
\r
323 IBSP_TRACE_EXIT( IBSP_DBG_CONN,
\r
324 ("returns new socket (0x%p)\n", new_socket_info) );
\r
325 return (SOCKET)new_socket_info;
\r
329 /* Function: IBSPAccept
\r
332 * Handle the WSAAccept function. The only special consideration here
\r
333 * is the conditional accept callback. You can choose to intercept
\r
334 * this by substituting your own callback (you'll need to keep track
\r
335 * of the user supplied callback so you can trigger that once your
\r
336 * substituted function is triggered).
\r
338 static SOCKET WSPAPI
\r
341 OUT struct sockaddr FAR *addr,
\r
342 IN OUT LPINT addrlen,
\r
343 IN LPCONDITIONPROC lpfnCondition,
\r
344 IN DWORD_PTR dwCallbackData,
\r
345 OUT LPINT lpErrno )
\r
347 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
350 struct listen_incoming *incoming;
\r
351 struct ibsp_port *port;
\r
354 IBSP_ENTER( IBSP_DBG_CONN );
\r
356 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
357 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
359 CL_ASSERT( lpfnCondition );
\r
361 if( *addrlen < sizeof(struct sockaddr_in) )
\r
363 IBSP_ERROR_EXIT( ("invalid addrlen (%d, %d)\n",
\r
364 *addrlen, sizeof(struct sockaddr_in)) );
\r
365 *lpErrno = WSAEFAULT;
\r
366 return INVALID_SOCKET;
\r
369 /* Check if there is any pending connection for this socket. If
\r
370 * there is one, create a socket, and then query the switch about
\r
371 * the pending connection */
\r
373 cl_spinlock_acquire( &socket_info->mutex );
\r
375 /* Verify the state of the socket */
\r
376 if( socket_info->socket_state != IBSP_LISTEN )
\r
378 cl_spinlock_release( &socket_info->mutex );
\r
379 IBSP_ERROR_EXIT( ("Socket is not in right socket_state (%s)\n",
\r
380 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
381 *lpErrno = WSAEINVAL;
\r
382 return INVALID_SOCKET;
\r
385 if( cl_qlist_count( &socket_info->listen.list ) == 0 )
\r
387 cl_spinlock_release( &socket_info->mutex );
\r
389 IBSP_ERROR_EXIT( ("No pending connection found for this socket\n") );
\r
390 *lpErrno = WSAEWOULDBLOCK;
\r
391 return INVALID_SOCKET;
\r
394 IBSP_TRACE( IBSP_DBG_CONN,
\r
395 ("IBSPAccept: Found pending connection on this socket\n") );
\r
397 incoming = PARENT_STRUCT(cl_qlist_remove_head( &socket_info->listen.list ),
\r
398 struct listen_incoming, item);
\r
400 /* Signal the event again if there are more connection requests. */
\r
401 if( cl_qlist_count( &socket_info->listen.list ) )
\r
402 ibsp_post_select_event( socket_info, FD_ACCEPT, 0 );
\r
403 cl_spinlock_release( &socket_info->mutex );
\r
405 port = socket_info->port;
\r
407 /* Find the destination IP address */
\r
410 /* The socket was bound to INADDR_ANY. We must find the correct port
\r
411 * for the new socket. */
\r
412 port = get_port_from_ip_address( incoming->params.dest.sin_addr );
\r
416 ("incoming destination IP address not local (%s)\n",
\r
417 inet_ntoa( incoming->params.dest.sin_addr )) );
\r
422 /* Cross-check with the path info to make sure we are conectiong correctly */
\r
423 if( port->guid != ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid ) )
\r
426 ("GUIDs of port for destination IP address and primary path do not match (%016I64x, %016I64x)\n",
\r
428 ib_gid_get_guid( &incoming->cm_req_received.primary_path.sgid )) );
\r
431 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_INSUF_QP );
\r
433 HeapFree( g_ibsp.heap, 0, incoming );
\r
434 IBSP_ERROR_EXIT( ("bad incoming parameter\n") );
\r
435 *lpErrno = WSAECONNREFUSED;
\r
436 return INVALID_SOCKET;
\r
440 * Check against the conditional routine if socket can be created
\r
444 /* Set the caller and callee data buffer */
\r
445 caller_id.buf = (char *)&incoming->params.source;
\r
446 caller_id.len = sizeof(incoming->params.source);
\r
448 callee_id.buf = (char *)&incoming->params.dest;
\r
449 callee_id.len = sizeof(incoming->params.dest);
\r
451 IBSP_TRACE( IBSP_DBG_CONN,
\r
452 ("Got incoming conn from %s/%d-%d to %s/%d-%d\n",
\r
453 inet_ntoa( incoming->params.source.sin_addr ),
\r
454 cl_ntoh16( incoming->params.source.sin_port ),
\r
455 incoming->params.source.sin_family,
\r
456 inet_ntoa( incoming->params.dest.sin_addr ),
\r
457 cl_ntoh16( incoming->params.dest.sin_port ),
\r
458 incoming->params.dest.sin_family) );
\r
460 /* Call the conditional function */
\r
461 switch( lpfnCondition( &caller_id, NULL, NULL, NULL,
\r
462 &callee_id, NULL, NULL, dwCallbackData ) )
\r
465 /* Should never happen */
\r
467 ("Conditional routine returned undocumented code\n") );
\r
468 /* Fall through. */
\r
471 IBSP_TRACE1( IBSP_DBG_CONN,
\r
472 ("Conditional routine returned CF_REJECT\n") );
\r
474 ib_reject( incoming->cm_req_received.h_cm_req, IB_REJ_USER_DEFINED );
\r
476 HeapFree( g_ibsp.heap, 0, incoming );
\r
477 *lpErrno = WSAECONNREFUSED;
\r
478 IBSP_EXIT( IBSP_DBG_CONN );
\r
479 return INVALID_SOCKET;
\r
483 mra.mra_length = 0;
\r
484 mra.p_mra_pdata = NULL;
\r
485 mra.svc_timeout = 0x15;
\r
486 ib_cm_mra( incoming->cm_req_received.h_cm_req, &mra );
\r
488 /* Put the item back at the head of the list. */
\r
489 cl_spinlock_acquire( &socket_info->mutex );
\r
490 cl_qlist_insert_head( &socket_info->listen.list, &incoming->item );
\r
491 cl_spinlock_release( &socket_info->mutex );
\r
493 IBSP_TRACE1( IBSP_DBG_CONN,
\r
494 ("Conditional routine returned CF_DEFER\n") );
\r
496 *lpErrno = WSATRY_AGAIN;
\r
497 IBSP_EXIT( IBSP_DBG_CONN );
\r
498 return INVALID_SOCKET;
\r
504 s = accept_socket( socket_info, incoming, port, lpErrno );
\r
505 if( s != INVALID_SOCKET )
\r
507 /* Store the client socket address information */
\r
508 memcpy( addr, &incoming->params.source, sizeof(struct sockaddr_in) );
\r
509 *addrlen = sizeof(struct sockaddr_in);
\r
512 HeapFree( g_ibsp.heap, 0, incoming );
\r
514 IBSP_EXIT( IBSP_DBG_CONN );
\r
519 /* Function: IBSPBind
\r
522 * Bind the socket to a local address.
\r
528 IN const struct sockaddr FAR *name,
\r
530 OUT LPINT lpErrno )
\r
532 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
533 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
534 struct ibsp_port *port;
\r
537 IBSP_ENTER( IBSP_DBG_CONN );
\r
539 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
540 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
542 IBSP_TRACE( IBSP_DBG_CONN, ("Address to bind to:\n") );
\r
543 DebugPrintSockAddr( IBSP_DBG_CONN, gdbg_lvl, addr );
\r
545 fzprint(("binding to IP %s\n", inet_ntoa( addr->sin_addr )));
\r
547 /* Sanity checks */
\r
548 if( namelen != sizeof(struct sockaddr_in) )
\r
551 ("invalid namelen (%d instead of %d)\n",
\r
552 namelen, sizeof(struct sockaddr_in)) );
\r
553 *lpErrno = WSAEFAULT;
\r
557 if( addr->sin_family != AF_INET )
\r
559 IBSP_ERROR( ("bad family for socket\n") );
\r
560 *lpErrno = WSAEFAULT;
\r
564 /* Check if the ip address is assigned to one of our IBoIB HCA. */
\r
565 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
567 port = get_port_from_ip_address( addr->sin_addr );
\r
571 ("This IP address does not belong to that host (%08x)\n",
\r
572 addr->sin_addr.S_un.S_addr) );
\r
573 *lpErrno = WSAEADDRNOTAVAIL;
\r
582 /* We are going to take this mutex for some time,
\r
583 * but at this stage, it shouldn't impact anything. */
\r
584 cl_spinlock_acquire( &socket_info->mutex );
\r
586 /* Verify the state of the socket */
\r
587 if( socket_info->socket_state != IBSP_CREATE )
\r
589 cl_spinlock_release( &socket_info->mutex );
\r
591 ("Invalid socket state (%s)\n",
\r
592 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
593 *lpErrno = WSAEINVAL;
\r
597 if( addr->sin_addr.S_un.S_addr != INADDR_ANY )
\r
599 /* Time to allocate our IB QP */
\r
600 socket_info->port = port;
\r
601 ret = ib_create_socket( socket_info );
\r
604 socket_info->port = NULL;
\r
605 cl_spinlock_release( &socket_info->mutex );
\r
606 IBSP_ERROR( ("ib_create socket failed with %d\n", ret) );
\r
607 *lpErrno = WSAENOBUFS;
\r
613 socket_info->local_addr = *addr;
\r
615 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
617 cl_spinlock_release( &socket_info->mutex );
\r
619 IBSP_EXIT( IBSP_DBG_CONN );
\r
623 CL_ASSERT( *lpErrno != 0 );
\r
624 IBSP_TRACE_EXIT( IBSP_DBG_CONN, ("failed with error %d\n", *lpErrno) );
\r
625 return SOCKET_ERROR;
\r
629 /* Function: IBSPCloseSocket
\r
632 * Close the socket handle of the app socket as well as the provider socket.
\r
633 * However, if there are outstanding async IO requests on the app socket
\r
634 * we only close the provider socket. Only when all the IO requests complete
\r
635 * (with error) will we then close the app socket.
\r
642 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
644 IBSP_ENTER( IBSP_DBG_CONN );
\r
646 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p \n", __FUNCTION__,
\r
647 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
649 if( s == INVALID_SOCKET )
\r
651 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
652 *lpErrno = WSAENOTSOCK;
\r
653 return SOCKET_ERROR;
\r
656 cl_atomic_inc( &g_ibsp.CloseSocket_count );
\r
659 shutdown_and_destroy_socket_info( socket_info );
\r
661 IBSP_EXIT( IBSP_DBG_CONN );
\r
668 /* Function: IBSPConnect
\r
671 * Performs a connect call. The only thing we need to do is translate
\r
672 * the socket handle.
\r
677 const struct sockaddr FAR *name,
\r
679 LPWSABUF lpCallerData,
\r
680 LPWSABUF lpCalleeData,
\r
685 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
686 struct sockaddr_in *addr = (struct sockaddr_in *)name;
\r
688 ib_net64_t dest_port_guid;
\r
689 ib_path_rec_t path_rec;
\r
691 IBSP_ENTER( IBSP_DBG_CONN );
\r
693 UNUSED_PARAM( lpCalleeData );
\r
694 UNUSED_PARAM( lpSQOS );
\r
695 UNUSED_PARAM( lpGQOS );
\r
697 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p state=%s\n", __FUNCTION__,
\r
698 __LINE__, GetCurrentProcessId(),
\r
699 GetCurrentThreadId(), s, IBSP_SOCKET_STATE_STR( socket_info->socket_state )));
\r
701 IBSP_TRACE( IBSP_DBG_CONN,
\r
702 ("lpCallerData=%p, lpCalleeData=%p\n", lpCallerData, lpCalleeData) );
\r
704 /* Sanity checks */
\r
707 /* We don't support that. The current switch does not use it. */
\r
708 IBSP_ERROR_EXIT( ("lpCallerData.len=%d\n", lpCallerData->len) );
\r
709 *lpErrno = WSAEINVAL;
\r
710 return SOCKET_ERROR;
\r
713 if( namelen < sizeof(struct sockaddr_in) )
\r
716 ("invalid remote address (%d)\n", socket_info->socket_state) );
\r
717 *lpErrno = WSAEFAULT;
\r
718 return SOCKET_ERROR;
\r
721 /* Check if the name (actually address) of peer entity is correct */
\r
722 if( addr->sin_family != AF_INET ||
\r
723 addr->sin_port == 0 || addr->sin_addr.s_addr == INADDR_ANY )
\r
726 ("peer entity address is invalid (%d, %d, %x)\n",
\r
727 addr->sin_family, addr->sin_port, addr->sin_addr.s_addr) );
\r
728 *lpErrno = WSAEADDRNOTAVAIL;
\r
729 return SOCKET_ERROR;
\r
732 if( socket_info->local_addr.sin_addr.S_un.S_addr == addr->sin_addr.S_un.S_addr )
\r
734 /* Loopback - let the regular stack take care of that. */
\r
735 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
736 *lpErrno = WSAEADDRNOTAVAIL;
\r
737 return SOCKET_ERROR;
\r
740 /* Get the GUID for that IP address. */
\r
741 ret = query_guid_address( socket_info->port, addr->sin_addr.s_addr, &dest_port_guid );
\r
745 ("query_guid_address failed for IP %08x\n",
\r
746 addr->sin_addr.s_addr) );
\r
747 *lpErrno = WSAEADDRNOTAVAIL;
\r
748 return SOCKET_ERROR;
\r
751 IBSP_TRACE( IBSP_DBG_CONN, ("got GUID %I64x for IP %s\n",
\r
752 CL_NTOH64( dest_port_guid ), inet_ntoa( addr->sin_addr )) );
\r
754 if( dest_port_guid == socket_info->port->guid )
\r
756 IBSP_ERROR_EXIT( ("Loopback!\n") );
\r
757 *lpErrno = WSAEADDRNOTAVAIL;
\r
758 return SOCKET_ERROR;
\r
761 /* Get the path record */
\r
762 ret = query_pr( socket_info->port, dest_port_guid, &path_rec );
\r
766 ("query_pr failed for IP %08x\n", addr->sin_addr.s_addr) );
\r
767 *lpErrno = WSAEADDRNOTAVAIL;
\r
768 return SOCKET_ERROR;
\r
771 cl_spinlock_acquire( &socket_info->mutex );
\r
773 /* Verify the state of the socket */
\r
774 switch( socket_info->socket_state )
\r
777 /* Good. That's the only valid state we want. */
\r
780 case IBSP_CONNECTED:
\r
781 IBSP_ERROR( ("Socket is already connected\n") );
\r
782 *lpErrno = WSAEISCONN;
\r
786 IBSP_ERROR( ("Socket is a listening socket\n") );
\r
787 *lpErrno = WSAEINVAL;
\r
791 IBSP_ERROR( ("Socket is not in the bound state (%s)\n",
\r
792 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
793 *lpErrno = WSAEINVAL;
\r
797 /* Store the peer entity's address in socket context */
\r
798 socket_info->peer_addr = *addr;
\r
800 #ifdef IBSP_LOGGING
\r
801 DataLogger_Init( &socket_info->SendDataLogger, "Send",
\r
802 &socket_info->peer_addr, &socket_info->local_addr );
\r
803 DataLogger_Init( &socket_info->RecvDataLogger, "Recv",
\r
804 &socket_info->local_addr, &socket_info->peer_addr );
\r
807 /* Update the socket state */
\r
808 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_CONNECT );
\r
811 *lpErrno = ib_connect( socket_info, &path_rec );
\r
812 if( *lpErrno != WSAEWOULDBLOCK )
\r
814 /* We must be sure none destroyed our socket */
\r
815 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
816 memset( &socket_info->peer_addr, 0, sizeof(struct sockaddr_in) );
\r
818 IBSP_ERROR( ("ib_connect failed (%d)\n", *lpErrno) );
\r
822 cl_spinlock_release( &socket_info->mutex );
\r
823 IBSP_EXIT( IBSP_DBG_CONN );
\r
824 return SOCKET_ERROR;
\r
828 /* Function: IBSPEnumNetworkEvents
\r
831 * Enumerate the network events for a socket. We only need to
\r
832 * translate the socket handle.
\r
835 IBSPEnumNetworkEvents(
\r
837 WSAEVENT hEventObject,
\r
838 LPWSANETWORKEVENTS lpNetworkEvents,
\r
841 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
843 IBSP_ENTER( IBSP_DBG_NEV );
\r
845 ResetEvent( hEventObject );
\r
847 lpNetworkEvents->lNetworkEvents =
\r
848 InterlockedExchange( &socket_info->network_events, 0 );
\r
850 if( lpNetworkEvents->lNetworkEvents & FD_ACCEPT )
\r
852 IBSP_TRACE1( IBSP_DBG_NEV,
\r
853 ("socket %p notify FD_ACCEPT at time %I64d\n",
\r
854 socket_info, cl_get_time_stamp()) );
\r
855 lpNetworkEvents->iErrorCode[FD_ACCEPT_BIT] = 0;
\r
858 if( lpNetworkEvents->lNetworkEvents & FD_CONNECT )
\r
860 IBSP_TRACE1( IBSP_DBG_NEV,
\r
861 ("socket %p notify FD_CONNECT %d at time %I64d\n",
\r
862 socket_info, socket_info->errno_connect, cl_get_time_stamp()) );
\r
863 lpNetworkEvents->iErrorCode[FD_CONNECT_BIT] = socket_info->errno_connect;
\r
867 IBSP_EXIT( IBSP_DBG_NEV );
\r
872 /* Function: IBSPEventSelect
\r
875 * Register the specified events on the socket with the given event handle.
\r
876 * All we need to do is translate the socket handle.
\r
881 WSAEVENT hEventObject,
\r
882 long lNetworkEvents,
\r
885 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
888 IBSP_ENTER( IBSP_DBG_NEV );
\r
890 IBSP_TRACE4( IBSP_DBG_NEV,
\r
891 ("Socket %p requesting notifiction of %d on event %p.\n",
\r
892 s, lNetworkEvents, hEventObject) );
\r
894 if( (lNetworkEvents & ~(FD_ACCEPT | FD_CONNECT)) != 0 )
\r
896 IBSP_TRACE_EXIT(IBSP_DBG_NEV,
\r
897 ("Unknown lNetworkEvents flag given (%x)\n", lNetworkEvents) );
\r
898 *lpErrno = WSAEINVAL;
\r
899 return SOCKET_ERROR;
\r
902 CL_ASSERT( lpErrno );
\r
904 socket_info->event_mask = lNetworkEvents;
\r
905 InterlockedExchangePointer( &socket_info->event_select, hEventObject );
\r
907 events = InterlockedCompareExchange( &socket_info->network_events, 0, 0 );
\r
908 /* Check for existing events and signal as appropriate. */
\r
909 if( (socket_info->event_mask & events) && hEventObject )
\r
911 IBSP_TRACE2( IBSP_DBG_NEV,
\r
912 ("Signaling eventHandle %p .\n", socket_info->event_select) );
\r
913 SetEvent( hEventObject );
\r
916 IBSP_EXIT( IBSP_DBG_NEV );
\r
921 /* Function: IBSPGetOverlappedResult
\r
924 * This function reports whether the specified overlapped call has
\r
925 * completed. If it has, return the requested information. If not,
\r
926 * and fWait is true, wait until completion. Otherwise return an
\r
927 * error immediately.
\r
930 IBSPGetOverlappedResult(
\r
932 IN LPWSAOVERLAPPED lpOverlapped,
\r
933 OUT LPDWORD lpcbTransfer,
\r
935 OUT LPDWORD lpdwFlags,
\r
936 OUT LPINT lpErrno )
\r
938 struct ibsp_socket_info *p_socket_info;
\r
941 IBSP_ENTER( IBSP_DBG_IO );
\r
943 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
945 CL_ASSERT( fWait == FALSE );
\r
946 if( fWait == TRUE )
\r
948 IBSP_ERROR_EXIT( ("fWait not supported\n") );
\r
949 *lpErrno = WSAENETDOWN;
\r
953 if( s == INVALID_SOCKET )
\r
955 /* Seen in real life with overlap/client test.
\r
956 * The switch closes a socket then calls this. Why? */
\r
957 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
958 *lpErrno = WSAENOTSOCK;
\r
959 return SOCKET_ERROR;
\r
962 if( lpOverlapped->Internal == WSS_OPERATION_IN_PROGRESS )
\r
964 p_socket_info = (struct ibsp_socket_info*)s;
\r
965 /* Poll just in case it's done. */
\r
966 ib_cq_comp( p_socket_info->cq_tinfo );
\r
969 if( lpOverlapped->Internal != WSS_OPERATION_IN_PROGRESS )
\r
971 /* Operation has completed, perhaps with error */
\r
972 *lpdwFlags = lpOverlapped->Offset;
\r
973 *lpErrno = lpOverlapped->OffsetHigh;
\r
976 if( ((uintptr_t) lpOverlapped->hEvent) & 0x00000001 )
\r
978 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
980 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
981 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(),
\r
982 lpOverlapped, g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
983 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
986 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
988 IBSP_TRACE1( IBSP_DBG_IO,
\r
989 ("socket=%p completed ov=%p\n", s, lpOverlapped) );
\r
993 /* Operation is still in progress */
\r
994 *lpErrno = WSA_IO_INCOMPLETE;
\r
995 IBSP_TRACE1( IBSP_DBG_IO,
\r
996 ("socket=%p ov=%p hEvent=%p, operation in progress\n",
\r
997 s, lpOverlapped, lpOverlapped->hEvent));
\r
1000 *lpcbTransfer = (DWORD)lpOverlapped->InternalHigh;
\r
1002 if( *lpErrno == 0 )
\r
1007 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlapped=0x%p lpErrno=%d rc=%d\n",
\r
1008 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1009 lpOverlapped, *lpErrno, rc));
\r
1011 IBSP_EXIT( IBSP_DBG_IO );
\r
1016 /* Function: IBSPGetSockOpt
\r
1019 * Get the specified socket option. All we need to do is translate the
\r
1031 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1033 IBSP_ENTER( IBSP_DBG_OPT );
\r
1035 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1036 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1038 if( level != SOL_SOCKET )
\r
1040 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
1041 *lpErrno = WSAENOPROTOOPT;
\r
1042 return SOCKET_ERROR;
\r
1045 if( optval == NULL || optlen == NULL )
\r
1048 ("invalid optval=%p or optlen=%p", optval, optlen) );
\r
1049 *lpErrno = WSAEFAULT;
\r
1050 return SOCKET_ERROR;
\r
1056 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
1057 if( *optlen < sizeof(BOOL) )
\r
1060 ("option len is invalid (0x%x)\n", *optlen) );
\r
1061 *optlen = sizeof(BOOL);
\r
1062 *lpErrno = WSAEFAULT;
\r
1063 return SOCKET_ERROR;
\r
1066 memcpy( optval, &socket_info->socket_options.debug, sizeof(BOOL) );
\r
1067 *optlen = sizeof(BOOL);
\r
1071 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_ID\n") );
\r
1072 if( *optlen < sizeof(GROUP) )
\r
1075 ("option len is invalid (0x%x)\n", *optlen) );
\r
1076 *optlen = sizeof(GROUP);
\r
1077 *lpErrno = WSAEFAULT;
\r
1078 return SOCKET_ERROR;
\r
1081 memcpy( optval, &socket_info->socket_options.group_id, sizeof(GROUP) );
\r
1082 *optlen = sizeof(GROUP);
\r
1085 case SO_GROUP_PRIORITY:
\r
1086 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
1088 if( *optlen < sizeof(int) )
\r
1091 ("option len is invalid (0x%x)\n", *optlen) );
\r
1092 *optlen = sizeof(int);
\r
1093 *lpErrno = WSAEFAULT;
\r
1094 return SOCKET_ERROR;
\r
1097 memcpy( optval, &socket_info->socket_options.group_priority, sizeof(int) );
\r
1098 *optlen = sizeof(int);
\r
1101 case SO_MAX_MSG_SIZE:
\r
1102 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_MSG_SIZE\n") );
\r
1104 if( *optlen < sizeof(unsigned int) )
\r
1107 ("option len is invalid (0x%x)\n", *optlen) );
\r
1108 *optlen = sizeof(unsigned int);
\r
1109 *lpErrno = WSAEFAULT;
\r
1110 return SOCKET_ERROR;
\r
1113 memcpy( optval, &socket_info->socket_options.max_msg_size, sizeof(unsigned int) );
\r
1114 *optlen = sizeof(unsigned int);
\r
1117 case SO_MAX_RDMA_SIZE:
\r
1118 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_MAX_RDMA_SIZE\n") );
\r
1120 if( *optlen < sizeof(unsigned int) )
\r
1123 ("option len is invalid (0x%x)\n", *optlen) );
\r
1124 *optlen = sizeof(unsigned int);
\r
1125 *lpErrno = WSAEFAULT;
\r
1126 return SOCKET_ERROR;
\r
1129 memcpy( optval, &socket_info->socket_options.max_rdma_size, sizeof(unsigned int) );
\r
1130 *optlen = sizeof(unsigned int);
\r
1133 case SO_RDMA_THRESHOLD_SIZE:
\r
1134 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_RDMA_THRESHOLD_SIZE\n") );
\r
1136 if( *optlen < sizeof(unsigned int) )
\r
1139 ("option len is invalid (0x%x)\n", *optlen) );
\r
1140 *optlen = sizeof(unsigned int);
\r
1141 *lpErrno = WSAEFAULT;
\r
1142 return SOCKET_ERROR;
\r
1145 memcpy( optval, &socket_info->socket_options.rdma_threshold_size,
\r
1146 sizeof(unsigned int) );
\r
1147 *optlen = sizeof(unsigned int);
\r
1151 *lpErrno = WSAENOPROTOOPT;
\r
1153 IBSP_ERROR_EXIT( ("unknown option 0x%x\n", optname) );
\r
1155 return SOCKET_ERROR;
\r
1159 IBSP_EXIT( IBSP_DBG_OPT );
\r
1164 /* Function: IBSPGetQOSByName
\r
1167 * Get a QOS template by name. All we need to do is translate the socket
\r
1170 static BOOL WSPAPI
\r
1173 LPWSABUF lpQOSName,
\r
1177 IBSP_ENTER( IBSP_DBG_OPT );
\r
1179 UNUSED_PARAM( s );
\r
1180 UNUSED_PARAM( lpQOSName );
\r
1181 UNUSED_PARAM( lpQOS );
\r
1183 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1184 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1186 *lpErrno = WSAEOPNOTSUPP;
\r
1188 IBSP_ERROR_EXIT( ("not supported\n") );
\r
1194 /* Function: IBSPIoctl
\r
1197 * Invoke an ioctl. In most cases, we just need to translate the socket
\r
1198 * handle. However, if the dwIoControlCode is SIO_GET_EXTENSION_FUNCTION_POINTER,
\r
1199 * we'll need to intercept this and return our own function pointers.
\r
1204 IN DWORD dwIoControlCode,
\r
1205 IN LPVOID lpvInBuffer,
\r
1206 IN DWORD cbInBuffer,
\r
1207 OUT LPVOID lpvOutBuffer,
\r
1208 IN DWORD cbOutBuffer,
\r
1209 OUT LPDWORD lpcbBytesReturned,
\r
1210 IN LPWSAOVERLAPPED lpOverlapped,
\r
1211 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1212 IN LPWSATHREADID lpThreadId,
\r
1213 OUT LPINT lpErrno )
\r
1215 struct ibsp_socket_info *socket_info;
\r
1216 GUID SANRegisterMemory = WSAID_REGISTERMEMORY;
\r
1217 GUID SANDeregisterMemory = WSAID_DEREGISTERMEMORY;
\r
1218 GUID SANRegisterRDMAMemory = WSAID_REGISTERRDMAMEMORY;
\r
1219 GUID SANDeregisterRDMAMemory = WSAID_DEREGISTERRDMAMEMORY;
\r
1220 GUID SANRDMAWrite = WSAID_RDMAWRITE;
\r
1221 GUID SANRDMARead = WSAID_RDMAREAD;
\r
1222 GUID SANMemoryRegistrationCacheCallback = WSAID_MEMORYREGISTRATIONCACHECALLBACK;
\r
1224 IBSP_ENTER( IBSP_DBG_OPT );
\r
1226 UNUSED_PARAM( cbInBuffer );
\r
1227 UNUSED_PARAM( lpOverlapped );
\r
1228 UNUSED_PARAM( lpCompletionRoutine );
\r
1229 UNUSED_PARAM( lpThreadId );
\r
1231 if( dwIoControlCode == SIO_GET_EXTENSION_FUNCTION_POINTER )
\r
1233 /* This a special case. The socket handle passed is not valid. */
\r
1234 IBSP_TRACE1( IBSP_DBG_OPT, ("Get extension function pointer\n") );
\r
1236 if( memcmp( lpvInBuffer, &SANRegisterMemory, sizeof(GUID) ) == 0 )
\r
1238 /* Return a pointer to our intermediate extension function */
\r
1239 *((LPFN_WSPREGISTERMEMORY *) lpvOutBuffer) = IBSPRegisterMemory;
\r
1241 else if( memcmp( lpvInBuffer, &SANDeregisterMemory, sizeof(GUID) ) == 0 )
\r
1243 /* Return a pointer to our intermediate extension function */
\r
1244 *((LPFN_WSPDEREGISTERMEMORY *) lpvOutBuffer) = IBSPDeregisterMemory;
\r
1246 else if( memcmp( lpvInBuffer, &SANRegisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1248 /* Return a pointer to our intermediate extension function */
\r
1249 *((LPFN_WSPREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPRegisterRdmaMemory;
\r
1251 else if( memcmp( lpvInBuffer, &SANDeregisterRDMAMemory, sizeof(GUID) ) == 0 )
\r
1253 /* Return a pointer to our intermediate extension function */
\r
1254 *((LPFN_WSPDEREGISTERRDMAMEMORY *) lpvOutBuffer) = IBSPDeregisterRdmaMemory;
\r
1256 else if( memcmp( lpvInBuffer, &SANRDMAWrite, sizeof(GUID) ) == 0 )
\r
1258 /* Return a pointer to our intermediate extension function */
\r
1259 *((LPFN_WSPRDMAWRITE *) lpvOutBuffer ) = IBSPRdmaWrite;
\r
1261 else if( memcmp( lpvInBuffer, &SANRDMARead, sizeof(GUID) ) == 0 )
\r
1265 IBSP_TRACE( IBSP_DBG_WARN | IBSP_DBG_OPT,
\r
1266 ("RDMA_READ disabled.\n") );
\r
1267 *lpErrno = WSAEOPNOTSUPP;
\r
1268 return SOCKET_ERROR;
\r
1272 /* Return a pointer to our intermediate extension function */
\r
1273 *((LPFN_WSPRDMAREAD *) lpvOutBuffer ) = IBSPRdmaRead;
\r
1276 else if( memcmp( lpvInBuffer, &SANMemoryRegistrationCacheCallback,
\r
1277 sizeof(GUID) ) == 0 )
\r
1279 /* Return a pointer to our intermediate extension function */
\r
1280 *((LPFN_WSPMEMORYREGISTRATIONCACHECALLBACK *) lpvOutBuffer ) =
\r
1281 IBSPMemoryRegistrationCacheCallback;
\r
1285 IBSP_ERROR_EXIT( ("invalid extension GUID\n") );
\r
1286 *lpErrno = WSAEINVAL;
\r
1287 return SOCKET_ERROR;
\r
1289 IBSP_EXIT( IBSP_DBG_OPT );
\r
1293 socket_info = (struct ibsp_socket_info *)s;
\r
1295 /* Verify the state of the socket */
\r
1296 /* Not sure which state socket should be in to receive this call */
\r
1297 DebugPrintIBSPIoctlParams( IBSP_DBG_OPT, gdbg_lvl,
\r
1302 cbOutBuffer, lpOverlapped, lpCompletionRoutine, lpThreadId );
\r
1304 switch( dwIoControlCode )
\r
1307 case SIO_GET_GROUP_QOS:
\r
1309 case SIO_SET_GROUP_QOS:
\r
1310 /* We don't support that. dwServiceFlags1 in installSP
\r
1313 ("unsupported dwIoControlCode %d\n", dwIoControlCode) );
\r
1314 *lpErrno = WSAENOPROTOOPT;
\r
1315 return SOCKET_ERROR;
\r
1318 case SIO_ADDRESS_LIST_QUERY:
\r
1322 *lpcbBytesReturned = cbOutBuffer;
\r
1323 ret = build_ip_list( (LPSOCKET_ADDRESS_LIST)lpvOutBuffer,
\r
1324 lpcbBytesReturned, lpErrno );
\r
1326 IBSP_EXIT( IBSP_DBG_OPT );
\r
1333 ("invalid dwIoControlCode %d\n", dwIoControlCode) );
\r
1335 *lpErrno = WSAENOPROTOOPT;
\r
1336 return SOCKET_ERROR;
\r
1344 /* Function: IBSPListen
\r
1347 * This function establishes a socket to listen for incoming connections. It sets
\r
1348 * the backlog value on a listening socket.
\r
1356 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1359 IBSP_ENTER( IBSP_DBG_CONN );
\r
1361 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1362 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1364 cl_spinlock_acquire( &socket_info->mutex );
\r
1366 IBSP_TRACE( IBSP_DBG_CONN, ("socket_state is %s\n",
\r
1367 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1369 /* Verify the state of the socket */
\r
1370 switch( socket_info->socket_state )
\r
1374 /* Store the backlog value in the context */
\r
1375 socket_info->listen.backlog = backlog;
\r
1376 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_LISTEN );
\r
1378 socket_info->listen.listen_req_param.dwProcessId = 0;
\r
1379 cl_memclr( &socket_info->listen.listen_req_param.identifier,
\r
1380 sizeof(socket_info->listen.listen_req_param.identifier) );
\r
1382 ret = ib_listen( socket_info );
\r
1385 IBSP_CHANGE_SOCKET_STATE( socket_info, IBSP_BIND );
\r
1386 IBSP_ERROR_EXIT( ("ib_listen failed with %d\n", ret) );
\r
1391 /* Change the backlog */
\r
1392 ib_listen_backlog( socket_info, backlog );
\r
1398 ("Invalid socket_state (%s)\n",
\r
1399 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1404 cl_spinlock_release( &socket_info->mutex );
\r
1408 IBSP_EXIT( IBSP_DBG_CONN );
\r
1410 return SOCKET_ERROR;
\r
1416 /* Function: IBSPRecv
\r
1419 * This function receives data on a given socket and also allows for asynchronous
\r
1420 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1421 * handle and then make the receive call. If called with overlap, post the operation
\r
1422 * to our IOCP or completion routine.
\r
1427 LPWSABUF lpBuffers,
\r
1428 DWORD dwBufferCount,
\r
1429 LPDWORD lpNumberOfBytesRecvd,
\r
1431 LPWSAOVERLAPPED lpOverlapped,
\r
1432 LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1433 LPWSATHREADID lpThreadId,
\r
1436 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1437 ib_api_status_t status;
\r
1438 struct memory_node *node;
\r
1439 struct _recv_wr *wr;
\r
1442 IBSP_ENTER( IBSP_DBG_IO );
\r
1444 UNUSED_PARAM( lpNumberOfBytesRecvd );
\r
1445 UNUSED_PARAM( lpCompletionRoutine );
\r
1446 UNUSED_PARAM( lpThreadId );
\r
1448 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1449 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1451 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1452 CL_ASSERT( lpOverlapped != NULL );
\r
1454 if( s == INVALID_SOCKET )
\r
1456 /* Seen in real life with overlap/client test.
\r
1457 * The switch closes a socket then calls this. Why? */
\r
1458 IBSP_TRACE_EXIT( IBSP_DBG_WARN | IBSP_DBG_IO,
\r
1459 ("invalid socket handle %x\n", s) );
\r
1460 *lpErrno = WSAENOTSOCK;
\r
1461 return SOCKET_ERROR;
\r
1464 cl_spinlock_acquire( &socket_info->mutex );
\r
1465 switch( socket_info->socket_state )
\r
1467 case IBSP_CONNECTED:
\r
1468 case IBSP_DISCONNECTED:
\r
1472 cl_spinlock_release( &socket_info->mutex );
\r
1474 ("Socket is not in connected socket_state state=%s\n",
\r
1475 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1476 *lpErrno = WSAENOTCONN;
\r
1477 return SOCKET_ERROR;
\r
1479 cl_spinlock_release( &socket_info->mutex );
\r
1481 if( socket_info->qp_error != 0 )
\r
1484 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1485 *lpErrno = socket_info->qp_error;
\r
1486 return SOCKET_ERROR;
\r
1489 /* This function only works for that case. Right now the switch is
\r
1490 * only using that. */
\r
1491 if( dwBufferCount > QP_ATTRIB_RQ_SGE )
\r
1493 CL_ASSERT( dwBufferCount <= QP_ATTRIB_RQ_SGE );
\r
1495 ("dwBufferCount is greater than %d\n", QP_ATTRIB_RQ_SGE) );
\r
1496 *lpErrno = WSAEINVAL;
\r
1497 return SOCKET_ERROR;
\r
1500 cl_spinlock_acquire( &socket_info->recv_lock );
\r
1501 if( socket_info->recv_cnt == QP_ATTRIB_RQ_DEPTH )
\r
1503 /* This should never happen */
\r
1504 cl_spinlock_release( &socket_info->recv_lock );
\r
1505 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1506 *lpErrno = WSAENETDOWN;
\r
1507 return SOCKET_ERROR;
\r
1510 wr = &socket_info->recv_wr[socket_info->recv_idx];
\r
1512 wr->wr.lpOverlapped = lpOverlapped;
\r
1513 wr->wr.socket_info = socket_info;
\r
1515 /* Looks good. Post the receive buffer. */
\r
1516 wr->recv.p_next = NULL;
\r
1517 wr->recv.wr_id = (uint64_t)(void* __ptr64)wr;
\r
1518 wr->recv.num_ds = dwBufferCount;
\r
1519 wr->recv.ds_array = wr->ds_array;
\r
1521 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1523 /* Get the memory region node */
\r
1524 node = lookup_partial_mr( socket_info, IB_AC_LOCAL_WRITE,
\r
1525 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1528 cl_spinlock_release( &socket_info->recv_lock );
\r
1530 * No mr fits. This should never happen. This error is not
\r
1531 * official, but seems to be the closest.
\r
1533 IBSP_ERROR_EXIT( ("no MR found\n") );
\r
1534 *lpErrno = WSAEFAULT;
\r
1535 return SOCKET_ERROR;
\r
1538 wr->ds_array[ds_idx].vaddr =
\r
1539 (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1540 wr->ds_array[ds_idx].length = lpBuffers[ds_idx].len;
\r
1541 wr->ds_array[ds_idx].lkey = node->p_reg->lkey;
\r
1545 * We must set this now, because the operation could complete
\r
1546 * before ib_post_Recv returns.
\r
1548 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1550 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1551 lpOverlapped->Offset = *lpFlags;
\r
1553 cl_atomic_inc( &socket_info->recv_cnt );
\r
1556 if( lpOverlapped->hEvent == 0 )
\r
1558 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1562 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1563 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1566 cl_atomic_inc( &g_ibsp.recv_count );
\r
1568 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1569 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1570 GetCurrentThreadId(), lpOverlapped,
\r
1571 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1572 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1575 #ifdef IBSP_LOGGING
\r
1576 wr->idx = socket_info->recv_log_idx++;
\r
1579 fzprint(("%s():%d:0x%x:0x%x: posting RECV socket=0x%p overlap=%p wr=0x%p\n",
\r
1580 __FUNCTION__, __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s,
\r
1581 lpOverlapped, wr));
\r
1583 status = ib_post_recv( socket_info->qp, &wr->recv, NULL );
\r
1585 if( status == IB_SUCCESS )
\r
1587 /* Update the index and wrap as needed */
\r
1588 #if QP_ATTRIB_RQ_DEPTH == 256 || QP_ATTRIB_RQ_DEPTH == 128 || \
\r
1589 QP_ATTRIB_RQ_DEPTH == 64 || QP_ATTRIB_RQ_DEPTH == 32 || \
\r
1590 QP_ATTRIB_RQ_DEPTH == 16 || QP_ATTRIB_RQ_DEPTH == 8
\r
1591 socket_info->recv_idx++;
\r
1592 socket_info->recv_idx &= (QP_ATTRIB_RQ_DEPTH - 1);
\r
1594 if( ++socket_info->recv_idx == QP_ATTRIB_RQ_DEPTH )
\r
1595 socket_info->recv_idx = 0;
\r
1598 IBSP_TRACE1( IBSP_DBG_IO,
\r
1599 ("Posted RECV: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1600 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1602 *lpErrno = WSA_IO_PENDING;
\r
1607 ("ib_post_recv returned %s\n", ib_get_err_str( status )) );
\r
1609 if( lpOverlapped->hEvent == 0 )
\r
1611 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1615 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1616 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1619 cl_atomic_dec( &g_ibsp.recv_count );
\r
1621 memset( wr, 0x33, sizeof(struct _recv_wr) );
\r
1624 cl_atomic_dec( &socket_info->recv_cnt );
\r
1625 *lpErrno = ibal_to_wsa_error( status );
\r
1628 cl_spinlock_release( &socket_info->recv_lock );
\r
1630 /* We never complete the operation here. */
\r
1631 IBSP_EXIT( IBSP_DBG_IO );
\r
1632 return SOCKET_ERROR;
\r
1636 /* Function: IBSPSend
\r
1639 * This function sends data on a given socket and also allows for asynchronous
\r
1640 * (overlapped) operation. First translate the socket handle to the lower provider
\r
1641 * handle and then make the send call.
\r
1646 IN LPWSABUF lpBuffers,
\r
1647 IN DWORD dwBufferCount,
\r
1648 OUT LPDWORD lpNumberOfBytesSent,
\r
1650 IN LPWSAOVERLAPPED lpOverlapped,
\r
1651 IN LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
\r
1652 IN LPWSATHREADID lpThreadId,
\r
1653 OUT LPINT lpErrno )
\r
1655 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1656 ib_api_status_t status;
\r
1657 struct memory_node *node;
\r
1659 ib_send_wr_t send_wr;
\r
1660 ib_local_ds_t local_ds[QP_ATTRIB_SQ_SGE];
\r
1663 IBSP_ENTER( IBSP_DBG_IO );
\r
1665 UNUSED_PARAM( lpNumberOfBytesSent );
\r
1666 UNUSED_PARAM( lpCompletionRoutine );
\r
1667 UNUSED_PARAM( lpThreadId );
\r
1669 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p overlap=%p\n", __FUNCTION__,
\r
1670 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s, lpOverlapped));
\r
1672 if( s == INVALID_SOCKET )
\r
1674 IBSP_ERROR_EXIT( ("invalid socket handle %x\n", s) );
\r
1675 *lpErrno = WSAENOTSOCK;
\r
1676 return SOCKET_ERROR;
\r
1679 CL_ASSERT( lpCompletionRoutine == NULL );
\r
1680 CL_ASSERT( lpOverlapped != NULL );
\r
1682 cl_spinlock_acquire( &socket_info->mutex );
\r
1683 switch( socket_info->socket_state )
\r
1685 case IBSP_CONNECTED:
\r
1686 case IBSP_DISCONNECTED:
\r
1690 cl_spinlock_release( &socket_info->mutex );
\r
1692 ("Socket is not in connected socket_state state=%s\n",
\r
1693 IBSP_SOCKET_STATE_STR( socket_info->socket_state )) );
\r
1694 *lpErrno = WSAENOTCONN;
\r
1695 return SOCKET_ERROR;
\r
1697 cl_spinlock_release( &socket_info->mutex );
\r
1699 if( socket_info->qp_error )
\r
1702 ("QP is in error state %d\n", socket_info->qp_error) );
\r
1703 *lpErrno = socket_info->qp_error;
\r
1704 return SOCKET_ERROR;
\r
1707 /* This function only works for that case. */
\r
1708 if( dwBufferCount > QP_ATTRIB_SQ_SGE )
\r
1710 CL_ASSERT( dwBufferCount <= QP_ATTRIB_SQ_SGE );
\r
1712 ("dwBufferCount is greater than %d\n", QP_ATTRIB_SQ_SGE) );
\r
1713 *lpErrno = WSAEINVAL;
\r
1714 return SOCKET_ERROR;
\r
1717 /* The send lock is only used to serialize posting. */
\r
1718 cl_spinlock_acquire( &socket_info->send_lock );
\r
1719 if( socket_info->send_cnt == QP_ATTRIB_SQ_DEPTH )
\r
1721 /* This should never happen */
\r
1722 cl_spinlock_release( &socket_info->send_lock );
\r
1723 IBSP_ERROR_EXIT( ("not enough wr on the free list\n") );
\r
1724 *lpErrno = WSAENETDOWN;
\r
1725 return SOCKET_ERROR;
\r
1728 wr = &socket_info->send_wr[socket_info->send_idx];
\r
1730 wr->lpOverlapped = lpOverlapped;
\r
1731 wr->socket_info = socket_info;
\r
1733 /* Looks good. Post the send buffer. */
\r
1734 send_wr.p_next = NULL;
\r
1735 send_wr.wr_id = (uint64_t) (uintptr_t) wr;
\r
1736 send_wr.wr_type = WR_SEND;
\r
1737 send_wr.send_opt = socket_info->send_opt;
\r
1738 socket_info->send_opt = 0;
\r
1740 send_wr.num_ds = dwBufferCount;
\r
1741 send_wr.ds_array = local_ds;
\r
1743 lpOverlapped->InternalHigh = 0;
\r
1744 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1746 local_ds[ds_idx].vaddr = (uint64_t)(void* __ptr64)lpBuffers[ds_idx].buf;
\r
1747 local_ds[ds_idx].length = lpBuffers[ds_idx].len;
\r
1749 lpOverlapped->InternalHigh += lpBuffers[ds_idx].len;
\r
1752 if( lpOverlapped->InternalHigh <= socket_info->max_inline )
\r
1754 send_wr.send_opt |= IB_SEND_OPT_INLINE;
\r
1758 for( ds_idx = 0; ds_idx < dwBufferCount; ds_idx++ )
\r
1760 /* Get the memory region node */
\r
1761 node = lookup_partial_mr( socket_info, 0, /* READ */
\r
1762 lpBuffers[ds_idx].buf, lpBuffers[ds_idx].len );
\r
1765 cl_spinlock_release( &socket_info->send_lock );
\r
1767 * No mr fits. This error is not official, but seems to be the
\r
1770 IBSP_ERROR_EXIT( ("mr lookup failed\n") );
\r
1771 *lpErrno = WSAEFAULT;
\r
1772 return SOCKET_ERROR;
\r
1775 local_ds[ds_idx].lkey = node->p_reg->lkey;
\r
1780 * We must set this now, because the operation could complete
\r
1781 * before ib_post_send returns.
\r
1783 lpOverlapped->Internal = WSS_OPERATION_IN_PROGRESS;
\r
1785 /* Store the flags for reporting back in IBSPGetOverlappedResult */
\r
1786 lpOverlapped->Offset = dwFlags;
\r
1788 cl_atomic_inc( &socket_info->send_cnt );
\r
1791 if( lpOverlapped->hEvent == 0)
\r
1793 cl_atomic_inc( &g_ibsp.overlap_h0_count );
\r
1797 cl_atomic_inc( &g_ibsp.overlap_h1_count );
\r
1798 cl_atomic_inc( &g_ibsp.overlap_h1_comp_count );
\r
1801 cl_atomic_inc( &g_ibsp.send_count );
\r
1803 fzprint(("%s():%d:0x%x:0x%x: ov=0x%p h0=%d h1=%d h1_c=%d send=%d recv=%d\n",
\r
1804 __FUNCTION__, __LINE__, GetCurrentProcessId(),
\r
1805 GetCurrentThreadId(), lpOverlapped,
\r
1806 g_ibsp.overlap_h0_count, g_ibsp.overlap_h1_count,
\r
1807 g_ibsp.overlap_h1_comp_count, g_ibsp.send_count, g_ibsp.recv_count));
\r
1813 fzprint(("%s():%d:0x%x:0x%x: posting SEND %p, mr handle=%p, addr=%p, len=%d\n",
\r
1815 __LINE__, GetCurrentProcessId(),
\r
1816 GetCurrentThreadId(),
\r
1817 lpOverlapped, node, lpBuffers[0].buf, lpBuffers[0].len));
\r
1820 if( lpBuffers[0].len >= 40 )
\r
1822 debug_dump_buffer( IBSP_DBG_WQ | IBSP_DBG_LEVEL4, "SEND",
\r
1823 lpBuffers[0].buf, 40 );
\r
1827 #ifdef IBSP_LOGGING
\r
1831 for( i=0; i < dwBufferCount; i++ )
\r
1833 DataLogger_WriteData( &socket_info->SendDataLogger,
\r
1834 socket_info->send_log_idx++, lpBuffers[i].buf,
\r
1835 lpBuffers[i].len);
\r
1840 status = ib_post_send( socket_info->qp, &send_wr, NULL );
\r
1842 if( status == IB_SUCCESS )
\r
1844 /* Update the index and wrap as needed */
\r
1845 #if QP_ATTRIB_SQ_DEPTH == 256 || QP_ATTRIB_SQ_DEPTH == 128 || \
\r
1846 QP_ATTRIB_SQ_DEPTH == 64 || QP_ATTRIB_SQ_DEPTH == 32 || \
\r
1847 QP_ATTRIB_SQ_DEPTH == 16 || QP_ATTRIB_SQ_DEPTH == 8
\r
1848 socket_info->send_idx++;
\r
1849 socket_info->send_idx &= (QP_ATTRIB_SQ_DEPTH - 1);
\r
1851 if( ++socket_info->send_idx == QP_ATTRIB_SQ_DEPTH )
\r
1852 socket_info->send_idx = 0;
\r
1856 IBSP_TRACE1( IBSP_DBG_IO,
\r
1857 ("Posted SEND: socket=%p, ov=%p, addr=%p, len=%d\n",
\r
1858 s, lpOverlapped, lpBuffers[0].buf, lpBuffers[0].len) );
\r
1860 *lpErrno = WSA_IO_PENDING;
\r
1864 IBSP_ERROR( ("ib_post_send returned %s\n", ib_get_err_str( status )) );
\r
1867 if( lpOverlapped->hEvent == 0 )
\r
1869 cl_atomic_dec( &g_ibsp.overlap_h0_count );
\r
1873 cl_atomic_dec( &g_ibsp.overlap_h1_count );
\r
1874 cl_atomic_dec( &g_ibsp.overlap_h1_comp_count );
\r
1876 cl_atomic_dec( &g_ibsp.send_count );
\r
1878 memset( wr, 0x37, sizeof(struct _wr) );
\r
1880 cl_atomic_dec( &socket_info->send_cnt );
\r
1882 *lpErrno = ibal_to_wsa_error( status );
\r
1884 cl_spinlock_release( &socket_info->send_lock );
\r
1886 /* We never complete the operation here. */
\r
1887 IBSP_EXIT( IBSP_DBG_IO );
\r
1888 return SOCKET_ERROR;
\r
1892 /* Function: IBSPSetSockOpt
\r
1895 * Set a socket option. For most all options we just have to translate the
\r
1896 * socket option and call the lower provider. The only special case is for
\r
1897 * SO_UPDATE_ACCEPT_CONTEXT in which case a socket handle is passed as the
\r
1898 * argument which we need to translate before calling the lower provider.
\r
1905 const char FAR *optval,
\r
1909 struct ibsp_socket_info *socket_info = (struct ibsp_socket_info *)s;
\r
1911 IBSP_ENTER( IBSP_DBG_OPT );
\r
1913 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
1914 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), s));
\r
1916 if( level != SOL_SOCKET )
\r
1918 IBSP_ERROR_EXIT( ("invalid level %d", level) );
\r
1919 *lpErrno = WSAENOPROTOOPT;
\r
1920 return SOCKET_ERROR;
\r
1923 if( optval == NULL )
\r
1925 IBSP_ERROR_EXIT( ("invalid optval=%p", optval) );
\r
1926 *lpErrno = WSAEFAULT;
\r
1927 return SOCKET_ERROR;
\r
1933 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_DEBUG\n") );
\r
1934 if( optlen != sizeof(BOOL) )
\r
1937 ("option len is invalid (0x%x)\n", optlen) );
\r
1938 *lpErrno = WSAEFAULT;
\r
1939 return SOCKET_ERROR;
\r
1941 memcpy( &socket_info->socket_options.debug, optval, sizeof(BOOL) );
\r
1944 case SO_GROUP_PRIORITY:
\r
1945 IBSP_TRACE( IBSP_DBG_OPT, ("Option name SO_GROUP_PRIORITY\n") );
\r
1946 if( optlen != sizeof(int) )
\r
1949 ("option len is invalid (0x%x)\n", optlen) );
\r
1950 *lpErrno = WSAEFAULT;
\r
1951 return SOCKET_ERROR;
\r
1953 memcpy( &socket_info->socket_options.group_priority, optval, sizeof(int) );
\r
1957 IBSP_ERROR_EXIT( ("invalid option %x\n", optname) );
\r
1958 *lpErrno = WSAENOPROTOOPT;
\r
1959 return SOCKET_ERROR;
\r
1963 IBSP_EXIT( IBSP_DBG_OPT );
\r
1969 /* Function: IBSPSocket
\r
1972 * This function creates a socket. There are two sockets created. The first
\r
1973 * socket is created by calling the lower providers WSPSocket. This is the
\r
1974 * handle that we use internally within our LSP. We then create a second
\r
1975 * socket with WPUCreateSocketHandle which will be returned to the calling
\r
1976 * application. We will also create a socket context structure which will
\r
1977 * maintain information on each socket. This context is associated with the
\r
1978 * socket handle passed to the application.
\r
1980 static SOCKET WSPAPI
\r
1985 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
1990 struct ibsp_socket_info *socket_info = NULL;
\r
1992 IBSP_ENTER( IBSP_DBG_SI );
\r
1994 UNUSED_PARAM( g );
\r
1996 if( af != AF_INET )
\r
1999 ("bad family %d instead of %d\n", af, AF_INET) );
\r
2000 *lpErrno = WSAEAFNOSUPPORT;
\r
2001 return INVALID_SOCKET;
\r
2004 if( type != SOCK_STREAM )
\r
2007 ("bad type %d instead of %d\n", type, SOCK_STREAM) );
\r
2008 *lpErrno = WSAEPROTOTYPE;
\r
2009 return INVALID_SOCKET;
\r
2012 if( protocol != IPPROTO_TCP )
\r
2015 ("bad protocol %d instead of %d\n", protocol, IPPROTO_TCP) );
\r
2016 *lpErrno = WSAEPROTONOSUPPORT;
\r
2017 return INVALID_SOCKET;
\r
2020 if( (dwFlags != WSA_FLAG_OVERLAPPED) )
\r
2023 ("dwFlags is not WSA_FLAG_OVERLAPPED (%x)\n", dwFlags) );
\r
2024 *lpErrno = WSAEINVAL;
\r
2025 return INVALID_SOCKET;
\r
2028 socket_info = create_socket_info( lpErrno );
\r
2029 if( socket_info == NULL )
\r
2031 IBSP_ERROR_EXIT( ("create_socket_info return NULL\n") );
\r
2032 return INVALID_SOCKET;
\r
2035 if( lpProtocolInfo->dwProviderReserved != 0 )
\r
2037 /* This is a duplicate socket. */
\r
2038 *lpErrno = setup_duplicate_socket( socket_info,
\r
2039 (HANDLE)(ULONG_PTR)lpProtocolInfo->dwProviderReserved );
\r
2042 deref_socket_info( socket_info );
\r
2044 ("setup_duplicate_socket failed with %d\n", *lpErrno) );
\r
2045 return INVALID_SOCKET;
\r
2050 socket_info->socket_state = IBSP_CREATE;
\r
2052 /* Set the (non-zero) default socket options for that socket */
\r
2053 socket_info->socket_options.max_msg_size = IB_MAX_MSG_SIZE;
\r
2054 socket_info->socket_options.max_rdma_size = IB_MAX_RDMA_SIZE;
\r
2055 socket_info->socket_options.rdma_threshold_size = IB_RDMA_THRESHOLD_SIZE;
\r
2058 cl_spinlock_acquire( &g_ibsp.socket_info_mutex );
\r
2059 cl_qlist_insert_tail( &g_ibsp.socket_info_list, &socket_info->item );
\r
2060 cl_spinlock_release( &g_ibsp.socket_info_mutex );
\r
2064 fzprint(("%s():%d:0x%x:0x%x: socket=0x%p\n", __FUNCTION__,
\r
2065 __LINE__, GetCurrentProcessId(), GetCurrentThreadId(), socket_info));
\r
2067 IBSP_TRACE_EXIT( IBSP_DBG_SI,
\r
2068 ("returning socket handle %p\n", socket_info) );
\r
2070 return (SOCKET) socket_info;
\r
2074 /* Function: IBSPCleanup
\r
2077 * Decrement the entry count. If equal to zero then we can prepare to have us
\r
2078 * unloaded. Close any outstanding sockets and free up allocated memory.
\r
2086 IBSP_ENTER( IBSP_DBG_INIT );
\r
2088 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2090 if( !g_ibsp.entry_count )
\r
2092 cl_spinlock_release( &g_ibsp.mutex );
\r
2094 *lpErrno = WSANOTINITIALISED;
\r
2096 IBSP_ERROR_EXIT( ("returning WSAENOTINITIALISED\n") );
\r
2098 return SOCKET_ERROR;
\r
2101 /* Decrement the entry count */
\r
2102 g_ibsp.entry_count--;
\r
2104 IBSP_TRACE( IBSP_DBG_INIT, ("WSPCleanup: %d\n", g_ibsp.entry_count) );
\r
2106 if( g_ibsp.entry_count == 0 )
\r
2108 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count is 0 => cleaning up\n") );
\r
2112 cl_spinlock_release( &g_ibsp.mutex );
\r
2114 IBSP_EXIT( IBSP_DBG_INIT );
\r
2121 * Function: WSPStartupEx
\r
2124 * This function intializes the service provider. We maintain a ref count to keep track
\r
2125 * of how many times this function has been called.
\r
2130 LPWSPDATA lpWSPData,
\r
2131 LPWSAPROTOCOL_INFOW lpProtocolInfo,
\r
2132 LPWSPUPCALLTABLEEX UpCallTable,
\r
2133 LPWSPPROC_TABLE lpProcTable )
\r
2135 static WSPPROC_TABLE gProcTable;
\r
2136 static WSPDATA gWSPData;
\r
2138 IBSP_ENTER( IBSP_DBG_INIT );
\r
2140 /* Make sure that the version requested is >= 2.2. The low byte is the
\r
2141 major version and the high byte is the minor version. */
\r
2142 if( (LOBYTE(wVersion) < 2) || ((LOBYTE(wVersion) == 2) && (HIBYTE(wVersion) < 2)) )
\r
2145 ("Invalid winsock version requested %x\n", wVersion) );
\r
2147 return WSAVERNOTSUPPORTED;
\r
2150 IBSP_TRACE( IBSP_DBG_INIT, ("entry_count=%d)\n", g_ibsp.entry_count) );
\r
2152 cl_spinlock_acquire( &g_ibsp.mutex );
\r
2154 if( g_ibsp.entry_count == 0 )
\r
2158 /* Save the global WSPData */
\r
2159 gWSPData.wVersion = MAKEWORD(2, 2);
\r
2160 gWSPData.wHighVersion = MAKEWORD(2, 2);
\r
2161 wcscpy( gWSPData.szDescription, Description );
\r
2163 /* provide Service provider's entry points in proc table */
\r
2164 memset( &gProcTable, 0, sizeof(gProcTable) );
\r
2165 gProcTable.lpWSPAccept = IBSPAccept;
\r
2166 gProcTable.lpWSPBind = IBSPBind;
\r
2167 gProcTable.lpWSPCleanup = IBSPCleanup;
\r
2168 gProcTable.lpWSPCloseSocket = IBSPCloseSocket;
\r
2169 gProcTable.lpWSPConnect = IBSPConnect;
\r
2170 gProcTable.lpWSPDuplicateSocket = IBSPDuplicateSocket;
\r
2171 gProcTable.lpWSPEnumNetworkEvents = IBSPEnumNetworkEvents;
\r
2172 gProcTable.lpWSPEventSelect = IBSPEventSelect;
\r
2173 gProcTable.lpWSPGetOverlappedResult = IBSPGetOverlappedResult;
\r
2174 gProcTable.lpWSPGetSockOpt = IBSPGetSockOpt;
\r
2175 gProcTable.lpWSPGetQOSByName = IBSPGetQOSByName;
\r
2176 gProcTable.lpWSPIoctl = IBSPIoctl;
\r
2177 gProcTable.lpWSPListen = IBSPListen;
\r
2178 gProcTable.lpWSPRecv = IBSPRecv;
\r
2179 gProcTable.lpWSPSend = IBSPSend;
\r
2180 gProcTable.lpWSPSetSockOpt = IBSPSetSockOpt;
\r
2181 gProcTable.lpWSPSocket = IBSPSocket;
\r
2183 /* Since we only support 2.2, set both wVersion and wHighVersion to 2.2. */
\r
2184 lpWSPData->wVersion = MAKEWORD(2, 2);
\r
2185 lpWSPData->wHighVersion = MAKEWORD(2, 2);
\r
2186 wcscpy( lpWSPData->szDescription, Description );
\r
2189 /* TODO: remove? */
\r
2190 cl_qlist_init( &g_ibsp.cq_thread_info_list );
\r
2191 cl_spinlock_init( &g_ibsp.cq_thread_info_mutex );
\r
2194 g_ibsp.protocol_info = *lpProtocolInfo;
\r
2196 /* Initialize Infiniband */
\r
2197 ret = ibsp_initialize();
\r
2201 ("ibsp_initialize failed (%d)\n", ret) );
\r
2205 g_ibsp.entry_count++;
\r
2207 cl_spinlock_release( &g_ibsp.mutex );
\r
2209 /* Set the return parameters */
\r
2210 *lpWSPData = gWSPData;
\r
2211 *lpProcTable = gProcTable;
\r
2213 /* store the upcall function table */
\r
2214 g_ibsp.up_call_table = *UpCallTable;
\r
2216 IBSP_EXIT( IBSP_DBG_INIT );
\r