/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME: ** ** dgsoc.h ** ** FACILITY: ** ** Remote Procedure Call (RPC) ** ** ABSTRACT: ** ** Routines for managing the socket pool. ** ** */ #ifndef _DGSOC_H #define _DGSOC_H /* * The Socket Pool * * Sockets are allocated by a call to rpc__dg_network_use_protseq_<cl,sv>. * For servers, a new socket is opened on each call. Clients will reuse * an already open socket if it is of the correct protocol sequence, * and it was opened as a client socket. Either way, we start by * finding/creating a suitable new/used entry in the socket pool. * * Pool elements are reference counted. When the only remaining reference * count is the pool's internal table, the pool element is freed (including * closing its associated socket descriptor). Thus, socket users holding * a reference are not forced to lock the socket pool before using a * descriptor to prevent the descriptor from disappearing. * * In the event of multiple consecutive errors, a socket can be set to * disabled. Disabling removes the socket from the pool of descriptors * being listened on by the listener thread. For socket users, the * disabled flag is advisory. Since the socket user has a refcnt, it * needn't worry that the socket could be closed between the check of * the disabled flag and the actual use of the socket. * * Before performing a socket operation, threads should always check * that the socket they are using has not been marked disabled. This * condition is advisory, but it does indicate that subsequent use of the * socket is pointless; use RPC_DG_NETWORK_IS_DISABLED_DESC(). * * Locking considerations: * * All fields within the socket pool and its entries are protected by * the the socket pool lock except: * * The error_cnt field can be updated by any thread with a reference * to the pool entry. We accept the possibility that an update may * get lost. However, it is presumed that while a socket is * functioning correctly, all writers to this field will be writing * 0, and if the socket fails, all writers will be doing increments * until the maximum number of consecutive errors has been reached. * It is not critical that every increment be successful, whereas * it is critical, for performance reasons, that we don't force socket * users to take a lock to update this field every time they read/write * from a socket. * * Note that we force storage unit alignment of the "error_cnt". This * is done because we must worry about hardware environments in which * the code that references less-than-memory-word units ends up * dragging some larger unit from main memory, modifying some portion * and storing the unit back. This would end up reading and writing * other pool_elt bits which are protected by the pool mutex (which * we won't be holding). * * The disabled flag for a pool entry can be read at anytime by threads * which hold a reference to the entry. The reference count guarantees * the socket is still open, the disabled flag is merely an effort * to inform users of the socket that they needn't bother trying * to use the socket any further. However, no harm will result if * they miss the flag and try to use the the socket anyway. * * Similarly, the is_private field can be read by any call with a * reference to the entry. This value never changes. * * The xqe and rqe pointers are only used by private sockets. They * are initialized at the time the socket pool element is created. * After that, they are protected by the call handle lock of the * call that is using (holds the reference to) the private socket. */ typedef struct rpc_dg_sock_pool_elt_t { struct rpc_dg_sock_pool_elt_t *next; rpc_protseq_id_t pseq_id; rpc_socket_t sock; unsigned32 rcvbuf; unsigned32 sndbuf; rpc_addr_vector_p_t brd_addrs; rpc_dg_recvq_elt_p_t rqe; rpc_dg_xmitq_elt_p_t xqe; rpc_dg_recvq_elt_p_t rqe_list; /* cached pkts */ unsigned32 rqe_list_len; rpc_dg_ccall_p_t ccall; /* only valid if is_private */ unsigned32 refcnt; unsigned : 0; /* force alignment; see above */ unsigned8 error_cnt; unsigned : 0; /* force alignment; see above */ unsigned is_server: 1; unsigned is_disabled: 1; unsigned is_private: 1; unsigned rqe_available: 1; } rpc_dg_sock_pool_elt_t, *rpc_dg_sock_pool_elt_p_t; typedef struct rpc_dg_sock_pool_t { unsigned32 num_entries; rpc_mutex_t sp_mutex; rpc_dg_sock_pool_elt_p_t private_sockets; rpc_dg_sock_pool_elt_p_t shared_sockets; } rpc_dg_sock_pool_t; /* * Number of consecutive EIO errors we'll allow before disabling a socket. */ #ifndef RPC_C_DG_SOCK_MAX_ERRORS #define RPC_C_DG_SOCK_MAX_ERRORS 10 #endif /* * Number of private client sockets allowed for each address family. * Currently disabled for kernel RPC */ #ifndef RPC_C_DG_SOCK_MAX_PRIV_SOCKS #define RPC_C_DG_SOCK_MAX_PRIV_SOCKS 3 #endif /* * Return whether or not the sock pool elt's descriptor is disabled. * Done as a macro just to isolate users in case we want to change * the locking requirements (see above). */ #define RPC_DG_SOCK_IS_DISABLED(sp_elt) ((sp_elt)->is_disabled) /* * This macro should be called after each send/receive on a socket. If * the call was successful, the count of consecutive errors is reset. * On error, the count is incremented, and if the count exceeds the maximum * allowed, the socket is disabled. * * We only check for EIO errors. In the future we may want to check * for other errors as well. */ #define RPC_DG_SOCK_UPDATE_ERR_COUNT(sp_elt, serr) \ { \ if ((serr) != RPC_C_SOCKET_EIO) \ (sp_elt)->error_cnt = 0; \ else \ { \ if (++((sp_elt)->error_cnt) >= RPC_C_DG_SOCK_MAX_ERRORS) \ rpc__dg_network_disable_desc(sp_elt); \ } \ } /* * Macros for locking/unlocking the socket pool's mutex. */ #define RPC_DG_SOCK_POOL_LOCK(junk) RPC_MUTEX_LOCK(rpc_g_dg_sock_pool.sp_mutex) #define RPC_DG_SOCK_POOL_UNLOCK(junk) RPC_MUTEX_UNLOCK(rpc_g_dg_sock_pool.sp_mutex) #define RPC_DG_SOCK_POOL_LOCK_ASSERT(junk) \ RPC_MUTEX_LOCK_ASSERT(rpc_g_dg_sock_pool.sp_mutex) /* ======================================================================== */ PRIVATE void rpc__dg_network_use_protseq_sv ( rpc_protseq_id_t /*pseq_id*/, unsigned32 /*max_calls*/, rpc_addr_p_t /*rpc_addr*/, unsigned_char_p_t /*endpoint*/, unsigned32 * /*st*/ ); PRIVATE void rpc__dg_network_use_protseq_cl ( rpc_protseq_id_t /*pseq_id*/, rpc_dg_sock_pool_elt_p_t * /*sp_elt*/ ); PRIVATE void rpc__dg_network_disable_desc ( rpc_dg_sock_pool_elt_p_t /*sp_elt*/ ); PRIVATE void rpc__dg_network_init (void); PRIVATE void rpc__dg_network_fork_handler ( rpc_fork_stage_id_t /*stage*/ ); PRIVATE void rpc__dg_network_sock_release ( rpc_dg_sock_pool_elt_p_t * /*sp*/ ); PRIVATE void rpc__dg_network_sock_reference ( rpc_dg_sock_pool_elt_p_t /*sp*/ ); #endif /* _DGSOC_H */