1/*
2  This software is available to you under a choice of one of two
3  licenses.  You may choose to be licensed under the terms of the GNU
4  General Public License (GPL) Version 2, available at
5  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6  license, available in the LICENSE.TXT file accompanying this
7  software.  These details are also available at
8  <http://openib.org/license.html>.
9
10  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17  SOFTWARE.
18
19  Copyright (c) 2004 Topspin Communications.  All rights reserved.
20  Copyright (c) 2005-2006 Mellanox Technologies Ltd.  All rights reserved.
21
22  $Id$
23*/
24
25/*
26 * system includes
27 */
28#if HAVE_CONFIG_H
29#  include <config.h>
30#endif							/* HAVE_CONFIG_H */
31
32#ifdef SOLARIS_BUILD
33/* Our prototypes for ioctl, get*name and accept do not strictly
34   match the headers - we use the following lines to move the header
35   versions 'out of the way' temporarily. */
36#define ioctl __real_ioctl
37#define getsockname __real_getsockname
38#define getpeername __real_getpeername
39#define accept __real_accept
40#define FASYNC 0
41#include <libgen.h>
42#endif
43#include <unistd.h>
44#include <errno.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#define __USE_GNU
49#define _GNU_SOURCE				/* define RTLD_NEXT */
50#include <dlfcn.h>
51#include <sys/types.h>
52#include <sys/socket.h>
53#include <netinet/tcp.h>
54#include <arpa/inet.h>
55#include <netinet/in.h>
56#include <stdarg.h>
57#include <sys/time.h>
58#include <sys/resource.h>
59#include <sys/stat.h>
60#include <fcntl.h>
61#include <signal.h>
62#include <sys/poll.h>
63#ifdef __linux__
64#include <sys/epoll.h>
65#endif
66
67#ifdef SOLARIS_BUILD
68/* We're done protecting ourselves from the header prototypes */
69#undef ioctl
70#undef getsockname
71#undef getpeername
72#undef accept
73#endif
74
75/*
76 * SDP specific includes
77 */
78#include "libsdp.h"
79
80/* We can not use sizeof(sockaddr_in6) as the extra scope_id field is not a must have */
81#define IPV6_ADDR_IN_MIN_LEN 24
82
83/* setsockopt() level and optname declarations */
84#define SOL_SDP		1025
85#define SDP_UNBIND	259			/* Unbind socket */
86
87/* Solaris has two entry socket creation functions */
88#define SOCKET_SEMANTIC_DEFAULT 0
89#define SOCKET_SEMANTIC_XNET 1
90
91/* HACK: filter ioctl errors for FIONREAD */
92#define FIONREAD 0x541B
93
94void __attribute__ ((constructor)) __sdp_init(void);
95void __attribute__ ((destructor)) __sdp_fini(void);
96
97/* --------------------------------------------------------------------- */
98/* library type definitions.                                             */
99/* --------------------------------------------------------------------- */
100
101typedef int (*ioctl_func_t) (int fd,
102							 int request,
103							 void *arg0,
104							 void *arg1,
105							 void *arg2,
106							 void *arg3,
107							 void *arg4, void *arg5, void *arg6, void *arg7);
108
109typedef int (*fcntl_func_t) (int fd, int cmd, ...);
110
111typedef int (*socket_func_t) (int domain, int type, int protocol);
112
113typedef int (*setsockopt_func_t) (int s,
114								  int level,
115								  int optname,
116								  const void *optval, socklen_t optlen);
117
118typedef int (*connect_func_t) (int sockfd,
119							   const struct sockaddr * serv_addr,
120							   socklen_t addrlen);
121
122typedef int (*listen_func_t) (int s, int backlog);
123
124typedef int (*bind_func_t) (int sockfd,
125							const struct sockaddr * my_addr, socklen_t addrlen);
126
127typedef int (*close_func_t) (int fd);
128
129typedef int (*dup_func_t) (int fd);
130
131typedef int (*dup2_func_t) (int oldfd, int newfd);
132
133typedef int (*getsockname_func_t) (int fd,
134								   struct sockaddr * name, socklen_t * namelen);
135
136typedef int (*getpeername_func_t) (int fd,
137								   struct sockaddr * name, socklen_t * namelen);
138
139typedef int (*accept_func_t) (int fd,
140							  struct sockaddr * addr, socklen_t * addrlen);
141
142typedef int (*select_func_t) (int n,
143							  fd_set * readfds,
144							  fd_set * writefds,
145							  fd_set * exceptfds, struct timeval * timeout);
146
147typedef int (*pselect_func_t) (int n,
148							   fd_set * readfds,
149							   fd_set * writefds,
150							   fd_set * exceptfds,
151							   const struct timespec * timeout,
152							   const sigset_t * sigmask);
153
154typedef int (*poll_func_t) (struct pollfd * ufds,
155							unsigned long int nfds, int timeout);
156
157#ifdef __linux__
158typedef int (*epoll_create_func_t) (int size);
159
160typedef int (*epoll_ctl_func_t) (int epfd,
161								 int op, int fd, struct epoll_event * event);
162
163typedef int (*epoll_wait_func_t) (int epfd,
164								  struct epoll_event * events,
165								  int maxevents, int timeout);
166
167typedef int (*epoll_pwait_func_t) (int epfd,
168								   struct epoll_event * events,
169								   int maxevents,
170								   int timeout, const sigset_t * sigmask);
171#endif
172
173
174struct socket_lib_funcs {
175	ioctl_func_t ioctl;
176	fcntl_func_t fcntl;
177	socket_func_t socket;
178	setsockopt_func_t setsockopt;
179	connect_func_t connect;
180	listen_func_t listen;
181	bind_func_t bind;
182	close_func_t close;
183	dup_func_t dup;
184	dup2_func_t dup2;
185	getpeername_func_t getpeername;
186	getsockname_func_t getsockname;
187	accept_func_t accept;
188	select_func_t select;
189	pselect_func_t pselect;
190	poll_func_t poll;
191#ifdef __linux__
192	epoll_create_func_t epoll_create;
193	epoll_ctl_func_t epoll_ctl;
194	epoll_wait_func_t epoll_wait;
195	epoll_pwait_func_t epoll_pwait;
196#endif
197};								/* socket_lib_funcs */
198
199#ifdef SOLARIS_BUILD
200/* Solaris has another interface to socket functions prefixed with __xnet_ */
201struct socket_lib_xnet_funcs {
202	socket_func_t socket;
203	connect_func_t connect;
204	listen_func_t listen;
205	bind_func_t bind;
206};
207#endif
208
209static int simple_sdp_library;
210static int max_file_descriptors;
211static int dev_null_fd;
212volatile static int init_status = 0;	/* 0: idle, 1:during, 2:ready */
213
214/* --------------------------------------------------------------------- */
215/* library static and global variables                                   */
216/* --------------------------------------------------------------------- */
217
218/* glibc provides these symbols - for Solaris builds we fake them
219 * until _init is called, at which point we quiz libdl.. */
220#ifdef SOLARIS_BUILD
221char *program_invocation_name = "[progname]", *program_invocation_short_name =
222	"[short_progname]";
223#else
224extern char *program_invocation_name, *program_invocation_short_name;
225#endif
226
227#ifdef RTLD_NEXT
228static void *__libc_dl_handle = RTLD_NEXT;
229#else
230static void *__libc_dl_handle;
231#endif
232
233/* extra fd attributes we need for our algorithms */
234struct sdp_extra_fd_attributes {
235	int shadow_fd;				/* file descriptor of shadow sdp socket    */
236	short last_accept_was_tcp;	/* used by accept to alternate tcp and sdp */
237	short is_sdp;				/* 1 if the fd represents an sdp socket    */
238};								/* sdp_extra_fd_attributes */
239
240/* stores the extra attributes struct by fd */
241static struct sdp_extra_fd_attributes *libsdp_fd_attributes;
242
243static struct socket_lib_funcs _socket_funcs = {
244	.socket = NULL,
245	/* Automatically sets all other elements to NULL */
246};								/* _socket_funcs */
247
248#ifdef SOLARIS_BUILD
249static struct socket_lib_xnet_funcs _socket_xnet_funcs = {
250	.socket = NULL,
251	/* Automatically sets all other elements to NULL */
252};
253#endif
254
255/* --------------------------------------------------------------------- */
256/* Prototypes                                                            */
257/* --------------------------------------------------------------------- */
258void __sdp_init(void);
259
260/* --------------------------------------------------------------------- */
261/*                                                                       */
262/* local static functions.                                               */
263/*                                                                       */
264/* --------------------------------------------------------------------- */
265
266/* ========================================================================= */
267/*..init_extra_attribute -- initialize the set of extra attributes for a fd */
268static void init_extra_attribute(int fd)
269{
270	if ((0 <= fd) && (max_file_descriptors > fd)) {
271		libsdp_fd_attributes[fd].shadow_fd = -1;
272		libsdp_fd_attributes[fd].is_sdp = 0;
273		libsdp_fd_attributes[fd].last_accept_was_tcp = -1;
274	}
275}
276
277static inline int is_valid_fd(int fd)
278{
279	return (0 <= fd) && (fd < max_file_descriptors);
280}
281
282/* ========================================================================= */
283/*..get_shadow_fd_by_fd -- given an fd return its shadow fd if exists        */
284static inline int get_shadow_fd_by_fd(int fd)
285{
286	if (is_valid_fd(fd))
287		return libsdp_fd_attributes[fd].shadow_fd;
288	else
289		return -1;
290}
291
292/* ========================================================================= */
293/*..set_shadow_for_fd --                                                     */
294static inline void set_shadow_for_fd(int fd, int shadow_fd)
295{
296	if (is_valid_fd(fd))
297		libsdp_fd_attributes[fd].shadow_fd = shadow_fd;
298}
299
300/* ========================================================================= */
301/*..set_is_sdp_socket --                                                     */
302static inline void set_is_sdp_socket(int fd, short is_sdp)
303{
304	if (is_valid_fd(fd))
305		libsdp_fd_attributes[fd].is_sdp = is_sdp;
306}
307
308/* ========================================================================= */
309/*..get_is_sdp_socket -- given an fd return 1 if it is an SDP socket         */
310static inline int get_is_sdp_socket(int fd)
311{
312	if (is_valid_fd(fd))
313		return libsdp_fd_attributes[fd].is_sdp;
314	else
315		return 0;
316}
317
318/* ========================================================================= */
319/*..last_accept_was_tcp -- given an fd return 1 if last accept was tcp       */
320static inline int last_accept_was_tcp(int fd)
321{
322	if (is_valid_fd(fd))
323		return libsdp_fd_attributes[fd].last_accept_was_tcp;
324	else
325		return 0;
326}
327
328/* ========================================================================= */
329/*..set_last_accept -- given an fd set last accept was tcp                   */
330static inline void set_last_accept(int fd, int was_tcp)
331{
332	if (is_valid_fd(fd))
333		libsdp_fd_attributes[fd].last_accept_was_tcp = was_tcp;
334}
335
336/* ========================================================================= */
337/*..cleanup_shadow -- an error occured on an SDP socket, cleanup             */
338static int cleanup_shadow(int fd)
339{
340	int shadow_fd = get_shadow_fd_by_fd(fd);
341
342	if (shadow_fd == -1)
343		return 0;
344	libsdp_fd_attributes[fd].shadow_fd = -1;
345	libsdp_fd_attributes[fd].last_accept_was_tcp = 0;
346	return (_socket_funcs.close(shadow_fd));
347}								/* cleanup_shadow */
348
349/* ========================================================================= */
350/*..replace_fd_with_its_shadow -- perform all required for such promotion    */
351static int replace_fd_with_its_shadow(int fd)
352{
353	int shadow_fd = libsdp_fd_attributes[fd].shadow_fd;
354
355	if (shadow_fd == -1) {
356		__sdp_log(9, "Error replace_fd_with_its_shadow: no shadow for fd:%d\n",
357				  fd);
358		return EINVAL;
359	}
360
361	/* copy the attributes of the shadow before we clean them up */
362	libsdp_fd_attributes[fd] = libsdp_fd_attributes[shadow_fd];
363	libsdp_fd_attributes[fd].shadow_fd = -1;
364	if (_socket_funcs.dup2(shadow_fd, fd) < 0) {
365		init_extra_attribute(fd);
366		_socket_funcs.close(shadow_fd);
367		return EINVAL;
368	}
369	_socket_funcs.close(shadow_fd);
370	return 0;
371}
372
373static sa_family_t get_sdp_domain(int domain)
374{
375	if (AF_INET_SDP == domain || AF_INET6_SDP == domain)
376		return domain;
377
378	if (AF_INET == domain)
379		return AF_INET_SDP;
380	else if (AF_INET6 == domain)
381		return AF_INET6_SDP;
382
383	__sdp_log(9, "Error %s: unknown TCP domain: %d\n", __func__, domain);
384
385	return -1;
386}
387
388static int get_sock_domain(int sd)
389{
390	struct sockaddr_storage tmp_sin;
391	socklen_t tmp_sinlen = sizeof(tmp_sin);
392
393	if (_socket_funcs.getsockname(sd, (struct sockaddr *) &tmp_sin, &tmp_sinlen) < 0) {
394		__sdp_log(9, "Error %s: getsockname return <%d> for socket\n", __func__, errno);
395		return -1;
396	}
397
398	return ((struct sockaddr *)&tmp_sin)->sa_family;
399}
400
401/* ========================================================================= */
402/*..is_filtered_unsuported_sockopt -- return 1 if to filter sockopt failure  */
403static inline int is_filtered_unsuported_sockopt(int level, int optname)
404{
405	/*
406	 * TODO: until we know exactly which unsupported opts are really
407	 * a don't care we always pass the error
408	 */
409	return 0;
410#if 0
411	/* these are the SOL_TCP OPTS we should consider filterring */
412	TCP_NODELAY 1				/* Don't delay send to coalesce packets  */
413		TCP_MAXSEG 2			/* Set maximum segment size  */
414		TCP_CORK 3				/* Control sending of partial frames  */
415		TCP_KEEPIDLE 4			/* Start keeplives after this period */
416		TCP_KEEPINTVL 5			/* Interval between keepalives */
417		TCP_KEEPCNT 6			/* Number of keepalives before death */
418		TCP_SYNCNT 7			/* Number of SYN retransmits */
419		TCP_LINGER2 8			/* Life time of orphaned FIN-WAIT-2 state */
420		TCP_DEFER_ACCEPT 9		/* Wake up listener only when data arrive */
421		TCP_WINDOW_CLAMP 10		/* Bound advertised window */
422		TCP_INFO 11				/* Information about this connection. */
423		TCP_QUICKACK 12			/* Bock/reenable quick ACKs.  */
424#endif
425}
426
427/* ========================================================================= */
428/*..is_invalid_addr -- return 1 if given pointer is not valid                */
429/* NOTE: invalidation of the size is going to happen during actual call      */
430static inline int is_invalid_addr(const void *p)
431{
432	/* HACK: on some systems we can not write to check for pointer validity */
433	size_t ret = fcntl(dev_null_fd, F_GETLK, p);
434
435	ret = (errno == EFAULT);
436	errno = 0;
437	return ret;
438}
439
440/* ========================================================================= */
441/*..get_addr_str -- fill in the given buffer with addr str or return 1       */
442static int get_addr_str(const struct sockaddr *addr, char *buf, size_t len)
443{
444	const struct sockaddr_in *sin = (struct sockaddr_in *) addr;
445	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
446	char const *conv_res;
447
448	if (sin->sin_family == AF_INET) {
449		conv_res = inet_ntop(AF_INET, (void *) &(sin->sin_addr), buf, len);
450	} else if (sin6->sin6_family == AF_INET6) {
451		conv_res = inet_ntop(AF_INET6, (void *) &sin6->sin6_addr, buf, len);
452	} else {
453		strncpy(buf, "unknown address family", len);
454		conv_res = (char *) 1;
455	}
456	return conv_res == NULL;
457}
458
459/* --------------------------------------------------------------------- */
460/*                                                                       */
461/* Socket library function overrides.                                    */
462/*                                                                       */
463/* --------------------------------------------------------------------- */
464
465/* ========================================================================= */
466/*..ioctl -- replacement ioctl call. */
467int
468ioctl(int fd,
469	  int request,
470	  void *arg0,
471	  void *arg1,
472	  void *arg2, void *arg3, void *arg4, void *arg5, void *arg6, void *arg7)
473{
474	int shadow_fd;
475	int sret = 0;
476	int ret = 0;
477
478	if (init_status == 0)
479		__sdp_init();
480
481	if (NULL == _socket_funcs.ioctl) {
482		__sdp_log(9, "Error ioctl: no implementation for ioctl found\n");
483		return -1;
484	}
485
486	shadow_fd = get_shadow_fd_by_fd(fd);
487
488	__sdp_log(2, "IOCTL: <%s:%d:%d> request <%d>\n",
489			  program_invocation_short_name, fd, shadow_fd, request);
490
491	ret = _socket_funcs.ioctl(fd, request,
492							  arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
493
494	/* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */
495	if ((ret < 0) && get_is_sdp_socket(fd) && (request == FIONREAD)) {
496		__sdp_log(8, "Warning ioctl: "
497				  "Ignoring FIONREAD error for SDP socket.\n");
498		ret = 0;
499	}
500
501	/* if shadow and no error on tcp */
502	if ((ret >= 0) && (-1 != shadow_fd)) {
503		sret = _socket_funcs.ioctl(shadow_fd, request,
504								   arg0, arg1, arg2, arg3, arg4, arg5, arg6,
505								   arg7);
506		/* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */
507		if ((sret < 0) && (request == FIONREAD)) {
508			__sdp_log(8, "Warning ioctl: "
509					  "Ignoring FIONREAD error for shadow SDP socket.\n");
510			sret = 0;
511		}
512
513		if (sret < 0) {
514			__sdp_log(9, "Error ioctl: "
515					  "<%d> calling ioctl for SDP socket, closing it.\n",
516					  errno);
517			cleanup_shadow(fd);
518		}
519	}
520
521	__sdp_log(2, "IOCTL: <%s:%d:%d> result <%d:%d>\n",
522			  program_invocation_short_name, fd, shadow_fd, ret, sret);
523
524	return ret;
525}								/* ioctl */
526
527/* ========================================================================= */
528/*..fcntl -- replacement fcntl call.                                         */
529int fcntl(int fd, int cmd, ...)
530{
531	int shadow_fd;
532	int sret = 0;
533	int ret = 0;
534
535	void *arg;
536	va_list ap;
537
538	va_start(ap, cmd);
539	arg = va_arg(ap, void *);
540	va_end(ap);
541
542
543	if (init_status == 0)
544		__sdp_init();
545
546	if (NULL == _socket_funcs.fcntl) {
547		__sdp_log(9, "Error fcntl: no implementation for fcntl found\n");
548		return -1;
549	}
550
551	shadow_fd = get_shadow_fd_by_fd(fd);
552
553	__sdp_log(2, "FCNTL: <%s:%d:%d> command <%d> argument <%p>\n",
554			  program_invocation_short_name, fd, shadow_fd, cmd, arg);
555
556	ret = _socket_funcs.fcntl(fd, cmd, arg);
557	if ((ret >= 0) && (-1 != shadow_fd)) {
558		sret = _socket_funcs.fcntl(shadow_fd, cmd, arg);
559		if (sret < 0) {
560			__sdp_log(9, "Error fcntl:"
561					  " <%d> calling fcntl(%d, %d, %p) for SDP socket. Closing it.\n",
562					  shadow_fd, cmd, arg, errno);
563			cleanup_shadow(fd);
564		}
565	}
566
567	__sdp_log(2, "FCNTL: <%s:%d:%d> result <%d:%d>\n",
568			  program_invocation_short_name, fd, shadow_fd, ret, sret);
569
570	return ret;
571}								/* fcntl */
572
573/* ========================================================================= */
574/*..setsockopt -- replacement setsockopt call.                               */
575int
576setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
577{
578	int shadow_fd;
579	int sret = 0;
580	int ret = 0;
581
582	if (init_status == 0)
583		__sdp_init();
584
585	if (NULL == _socket_funcs.setsockopt) {
586		__sdp_log(9, "Error setsockopt:"
587				  " no implementation for setsockopt found\n");
588		return -1;
589	}
590
591	shadow_fd = get_shadow_fd_by_fd(fd);
592
593	__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> level <%d> name <%d>\n",
594			  program_invocation_short_name, fd, shadow_fd, level, optname);
595
596	if (level == SOL_SOCKET && optname == SO_KEEPALIVE && get_is_sdp_socket(fd)) {
597		level = AF_INET_SDP;
598		__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n",
599				  program_invocation_short_name, fd, shadow_fd, level);
600	}
601
602	ret = _socket_funcs.setsockopt(fd, level, optname, optval, optlen);
603	if ((ret >= 0) && (shadow_fd != -1)) {
604		if (level == SOL_SOCKET && optname == SO_KEEPALIVE &&
605			get_is_sdp_socket(shadow_fd)) {
606			level = AF_INET_SDP;
607			__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n",
608					  program_invocation_short_name, fd, shadow_fd, level);
609		}
610
611		sret = _socket_funcs.setsockopt(shadow_fd, level, optname, optval, optlen);
612		if (sret < 0) {
613			__sdp_log(8, "Warning sockopts:"
614					  " ignoring error on shadow SDP socket fd:<%d>\n", fd);
615			/*
616			 * HACK: we should allow some errors as some sock opts are unsupported
617			 * __sdp_log(9, "Error %d calling setsockopt for SDP socket, closing\n", errno);
618			 * cleanup_shadow(fd);
619			 */
620		}
621	}
622
623	/* Due to SDP limited implmentation of sockopts we ignore some errors */
624	if ((ret < 0) && get_is_sdp_socket(fd) &&
625		is_filtered_unsuported_sockopt(level, optname)) {
626		__sdp_log(8, "Warning sockopts: "
627				  "ignoring error on non implemented sockopt on SDP socket"
628				  " fd:<%d> level:<%d> opt:<%d>\n", fd, level, optval);
629		ret = 0;
630	}
631
632	__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> result <%d:%d>\n",
633			  program_invocation_short_name, fd, shadow_fd, ret, sret);
634
635	return ret;
636}								/* setsockopt */
637
638/* ========================================================================= */
639/*..socket -- replacement socket call.                                       */
640
641static inline int __create_socket_semantic(int domain,
642										   int type,
643										   int protocol, int semantics)
644{
645	return
646#ifdef SOLARIS_BUILD
647		(semantics == SOCKET_SEMANTIC_XNET) ?
648		_socket_xnet_funcs.socket(domain, type, protocol) :
649#endif
650		_socket_funcs.socket(domain, type, protocol);
651}
652
653/* Contains the main logic for creating shadow SDP sockets */
654static int __create_socket(int domain, int type, int protocol, int semantics)
655{
656	int s = -1;
657	int shadow_fd = -1;
658	use_family_t family_by_prog;
659	int sdp_domain;
660
661	if (init_status == 0)
662		__sdp_init();
663
664	if (NULL == _socket_funcs.socket) {
665		__sdp_log(9, "Error socket: no implementation for socket found\n");
666		return -1;
667	}
668
669	__sdp_log(2, "SOCKET: <%s> domain <%d> type <%d> protocol <%d>\n",
670			  program_invocation_short_name, domain, type, protocol);
671
672	sdp_domain = get_sdp_domain(domain);
673	if (sdp_domain < 0) {
674		errno = EAFNOSUPPORT;
675		s = -1;
676		goto done;
677	}
678
679	/* check to see if we can skip the shadow */
680	if ((AF_INET == domain || AF_INET6 == domain) && (SOCK_STREAM == type))
681		if (simple_sdp_library)
682			family_by_prog = USE_SDP;
683		else
684			family_by_prog = __sdp_match_by_program();
685	else if (AF_INET_SDP == domain || AF_INET6_SDP == domain)
686		family_by_prog = USE_SDP;
687	else
688		family_by_prog = USE_TCP;
689
690	if (family_by_prog == USE_TCP) {
691		__sdp_log(1, "SOCKET: making TCP only socket (no shadow)\n");
692		s = __create_socket_semantic(domain, type, protocol, semantics);
693		init_extra_attribute(s);
694		set_is_sdp_socket(s, 0);
695		goto done;
696	}
697
698	if (family_by_prog == USE_SDP) {
699		/* HACK: convert the protocol if IPPROTO_IP */
700		if (protocol == 0)
701			protocol = IPPROTO_TCP;
702
703		__sdp_log(1, "SOCKET: making SDP socket type:%d proto:%d\n",
704				  type, protocol);
705		s = __create_socket_semantic(sdp_domain, type, protocol, semantics);
706		init_extra_attribute(s);
707		set_is_sdp_socket(s, 1);
708		goto done;
709	}
710
711	/* HACK: if we fail creating the TCP socket should we abort ? */
712	__sdp_log(1, "SOCKET: making TCP socket\n");
713	s = __create_socket_semantic(domain, type, protocol, semantics);
714	init_extra_attribute(s);
715	set_is_sdp_socket(s, 0);
716	if (is_valid_fd(s)) {
717		if (((AF_INET == domain) || (AF_INET6 == domain)) &&
718			(SOCK_STREAM == type)) {
719
720			if (protocol == 0)
721				protocol = IPPROTO_TCP;
722			__sdp_log(1, "SOCKET: making SDP shadow socket type:%d proto:%d\n",
723					  type, protocol);
724			shadow_fd =
725				__create_socket_semantic(sdp_domain, type, protocol,
726										 semantics);
727			if (is_valid_fd(shadow_fd)) {
728				init_extra_attribute(shadow_fd);
729				if (libsdp_fd_attributes[s].shadow_fd != -1) {
730					__sdp_log(8, "Warning socket: "
731							  "overriding existing shadow fd:%d for fd:%d\n",
732							  libsdp_fd_attributes[s].shadow_fd, s);
733				}
734				set_is_sdp_socket(shadow_fd, 1);
735				set_shadow_for_fd(s, shadow_fd);
736			} else {
737				__sdp_log(9,
738						  "Error socket: <%d> calling socket for SDP socket\n",
739						  errno);
740				/* fail if we did not make the SDP socket */
741				__sdp_log(1, "SOCKET: closing TCP socket:<%d>\n", s);
742				_socket_funcs.close(s);
743				s = -1;
744			}
745		}
746	} else {
747		__sdp_log(9, "Error socket: "
748				  "ignoring SDP socket since TCP fd:%d out of range\n", s);
749	}
750
751done:
752	__sdp_log(2, "SOCKET: <%s:%d:%d>\n",
753			  program_invocation_short_name, s, shadow_fd);
754
755	return s;
756}								/* socket */
757
758int socket(int domain, int type, int protocol)
759{
760	return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_DEFAULT);
761}
762
763#ifdef SOLARIS_BUILD
764int __xnet_socket(int domain, int type, int protocol)
765{
766	return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_XNET);
767}
768#endif
769
770/* ========================================================================= */
771/*..get_fd_addr_port_num - obtain the port the fd is attached to             */
772static int get_fd_addr_port_num(int sd)
773{
774	struct sockaddr_storage addr;
775	int ret;
776	const struct sockaddr_in *sin;
777	socklen_t addrlen = sizeof(addr);
778
779	ret = _socket_funcs.getsockname(sd, (struct sockaddr *) &addr, &addrlen);
780
781	if (ret) {
782		__sdp_log(9, "Error: in get_fd_addr_port_num - Failed to get getsockname\n");
783		return -1;
784	}
785
786	/* port num is in same location for IPv4 and IPv6 */
787	sin = (const struct sockaddr_in *) &addr;
788	return ntohs(sin->sin_port);
789}
790
791/* ========================================================================= */
792/*..set_addr_port_num - sets the port in the given address                   */
793static int set_addr_port_num(const struct sockaddr *addr, int port)
794{
795	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
796
797	/* port num is in same location for IPv4 and IPv6 */
798	sin->sin_port = htons(port);
799	return 0;
800}
801
802/* ========================================================================= */
803/*  perform a bind with the given socket semantics                           */
804static inline int
805__bind_semantics(int fd,
806				 const struct sockaddr *my_addr,
807				 socklen_t addrlen, int semantics)
808{
809	return
810#ifdef SOLARIS_BUILD
811		(semantics == SOCKET_SEMANTIC_XNET) ?
812		_socket_xnet_funcs.bind(fd, my_addr, addrlen) :
813#endif
814		_socket_funcs.bind(fd, my_addr, addrlen);
815}
816
817/* ========================================================================= */
818/*..find_free_port - find same free port on both TCP and SDP                 */
819#define MAX_BIND_ANY_PORT_TRIES 20000
820static int
821find_free_port(const struct sockaddr *sin_addr,
822			   const socklen_t addrlen,
823			   int orig_sd,
824			   int *sdp_sd, int *tcp_sd, int semantics)
825{
826	static int tcp_turn = 1;
827	int tmp_turn = tcp_turn;
828	int num_of_loops = 0;
829	int port = -1;
830	int tmp_sd[2];
831	unsigned int yes = 1;
832	int ret;
833	int domain, sdp_domain;
834
835	__sdp_log(2, "find_free_port: starting search for common free port\n");
836
837	/* need to obtain the address family from the fd */
838	domain = get_sock_domain(orig_sd);
839	if (domain == -1) {
840		errno = EFAULT;
841		goto done;
842	}
843
844	sdp_domain = get_sdp_domain(domain);
845	if (sdp_domain < 0) {
846		errno = EFAULT;
847		goto done;
848	}
849
850	do {
851		__sdp_log(1, "find_free_port: taking loop (%d)\n", ++num_of_loops);
852
853		__sdp_log(1, "find_free_port: creating the two sockets\n");
854		tmp_sd[0] = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP);
855		if (tmp_sd[0] < 0) {
856			__sdp_log(8, "Warning find_free_port: creating first socket failed\n");
857			goto done;
858		}
859
860		_socket_funcs.setsockopt(tmp_sd[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
861
862		tmp_sd[1] = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP);
863		if (tmp_sd[1] < 0) {
864			__sdp_log(8, "Warning find_free_port: creating second socket failed\n");
865			_socket_funcs.close(tmp_sd[0]);
866			goto done;
867		}
868
869		_socket_funcs.setsockopt(tmp_sd[1], SOL_SOCKET, SO_REUSEADDR, &yes,
870								 sizeof(yes));
871
872		__sdp_log(1, "find_free_port: binding first %s socket\n",
873				  tmp_turn ? "tcp" : "sdp");
874		ret = __bind_semantics(tmp_sd[tmp_turn], sin_addr, addrlen, semantics);
875		if (ret < 0) {
876			__sdp_log(8,
877					  "Warning find_free_port: binding first socket failed:%s\n",
878					  strerror(errno));
879			_socket_funcs.close(tmp_sd[0]);
880			_socket_funcs.close(tmp_sd[1]);
881			goto done;
882		}
883
884		__sdp_log(1, "find_free_port: listening on first socket\n");
885		ret = _socket_funcs.listen(tmp_sd[tmp_turn], 5);
886		if (ret < 0) {
887			__sdp_log(8, "Warning find_free_port: listening on first socket failed:%s\n",
888					strerror(errno));
889			_socket_funcs.close(tmp_sd[0]);
890			_socket_funcs.close(tmp_sd[1]);
891			goto done;
892		}
893
894		port = get_fd_addr_port_num(tmp_sd[tmp_turn]);
895		if (port < 0) {
896			__sdp_log(8, "Warning find_free_port: first socket port:%d < 0\n",
897					port);
898			_socket_funcs.close(tmp_sd[0]);
899			_socket_funcs.close(tmp_sd[1]);
900			goto done;
901		}
902		__sdp_log(1, "find_free_port: first socket port:%u\n", port);
903
904		set_addr_port_num(sin_addr, port);
905
906		__sdp_log(1, "find_free_port: binding second socket\n");
907		ret = __bind_semantics(tmp_sd[1 - tmp_turn], sin_addr, addrlen, semantics);
908		if (ret < 0) {
909			/* bind() for sdp socket failed. It is acceptable only
910			 * if the IP is not part of IB network. */
911
912			if (errno != EADDRINUSE) {
913				__sdp_log(8, "Warning find_free_port: "
914						  "binding second socket failed with %s\n",
915						  strerror(errno));
916				goto close_and_mark;
917			} else {
918				int err;
919#ifdef __linux__
920				socklen_t len = sizeof(int);
921
922				ret = getsockopt(tmp_sd[1 - tmp_turn], SOL_TCP,
923								 SDP_LAST_BIND_ERR, &err, &len);
924				if (-1 == ret) {
925					__sdp_log(9, "Error %s:getsockopt: %s\n",
926							  __func__, strerror(errno));
927					goto close_and_mark;
928				}
929#else
930				err = -errno;
931#endif
932				if (-ENOENT == err || -EADDRINUSE != err) {
933					/* bind() failed due to either:
934					 * 1. IP is ETH, not IB, so can't bind() to sdp socket.
935					 * 2. real error.
936					 * Continue only with TCP */
937					goto close_and_mark;
938				}
939				__sdp_log(1, "find_free_port: %s port %u was busy\n",
940					  1 - tmp_turn ? "tcp" : "sdp",
941					  ntohs(((const struct sockaddr_in *)sin_addr)->sin_port));
942			}
943
944			/* close the sockets - we will need new ones ... */
945			__sdp_log(1,
946					  "find_free_port: closing the two sockets before next loop\n");
947			_socket_funcs.close(tmp_sd[0]);
948			_socket_funcs.close(tmp_sd[1]);
949
950			port = -1;
951			/* we always start with tcp so we keep the original setting for now */
952			/* tmp_turn = 1 - tmp_turn; */
953		}
954
955	} while ((port < 0) && (num_of_loops < MAX_BIND_ANY_PORT_TRIES));
956
957setfds:
958	tcp_turn = tmp_turn;
959	*sdp_sd = tmp_sd[0];
960	*tcp_sd = tmp_sd[1];
961
962done:
963	__sdp_log(2, "find_free_port: return port:<%d>\n", port);
964	return port;
965
966close_and_mark:
967	_socket_funcs.close(tmp_sd[0]);
968	tmp_sd[0] = -1;				/* mark with error */
969	goto setfds;
970
971}
972
973/* ========================================================================= */
974/*..check_legal_bind - check if given address is okay for both TCP and SDP   */
975static int
976check_legal_bind(const struct sockaddr *sin_addr,
977				 const socklen_t addrlen,
978				 int orig_sd,
979				 int *sdp_sd, int *tcp_sd, int semantics)
980{
981	unsigned int yes = 1;
982	int ret = -1;
983	int sret = -1;
984	int domain, sdp_domain;
985
986	/* need to obtain the address family from the fd */
987	domain = get_sock_domain(orig_sd);
988	if (domain == -1) {
989		errno = EFAULT;
990		ret = -1;
991		goto done;
992	}
993
994	sdp_domain = get_sdp_domain(domain);
995	if (sdp_domain < 0) {
996		errno = EFAULT;
997		goto done;
998	}
999
1000	__sdp_log(2, "check_legal_bind: binding two temporary sockets\n");
1001	*sdp_sd = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP);
1002	if (*sdp_sd < 0) {
1003		__sdp_log(9, "Error check_legal_bind: " "creating SDP socket failed\n");
1004		goto done;
1005	}
1006
1007	__sdp_log(2, "check_legal_bind: reusing <%d> \n", *sdp_sd);
1008	sret =
1009		_socket_funcs.setsockopt(*sdp_sd, SOL_SOCKET, SO_REUSEADDR, &yes,
1010								 sizeof(yes));
1011	if (sret < 0) {
1012		__sdp_log(9, "Error bind: Could not setsockopt sdp_sd\n");
1013	}
1014
1015	*tcp_sd = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP);
1016	if (*tcp_sd < 0) {
1017		__sdp_log(9, "Error check_legal_bind: "
1018				  "creating second socket failed:%s\n", strerror(errno));
1019		_socket_funcs.close(*sdp_sd);
1020		goto done;
1021	}
1022
1023	__sdp_log(2, "check_legal_bind: reusing <%d> \n", *tcp_sd);
1024	sret =
1025		_socket_funcs.setsockopt(*tcp_sd, SOL_SOCKET, SO_REUSEADDR, &yes,
1026								 sizeof(yes));
1027	if (sret < 0) {
1028		__sdp_log(9, "Error bind: Could not setsockopt tcp_sd\n");
1029	}
1030
1031	__sdp_log(1, "check_legal_bind: binding SDP socket\n");
1032	ret = __bind_semantics(*sdp_sd, sin_addr, addrlen, semantics);
1033	if (ret < 0) {
1034		/* bind() for sdp socket failed. It is acceptable only if
1035		 * the IP is not part of IB network. */
1036		int err;
1037		socklen_t len = sizeof(int);
1038
1039		if (EADDRINUSE != errno)
1040			goto done;
1041#ifdef __linux__
1042		if (-1 == getsockopt(*sdp_sd, SOL_TCP, SDP_LAST_BIND_ERR, &err, &len)) {
1043			__sdp_log(9, "Error check_legal_bind:getsockopt: %s\n",
1044					  strerror(errno));
1045			goto done;
1046		}
1047#else
1048		err = -errno;
1049#endif
1050		if (-ENOENT != err) {
1051			/* bind() failed due to real error. Can't continue */
1052			__sdp_log(9, "Error check_legal_bind: "
1053					  "binding SDP socket failed:%s\n", strerror(errno));
1054			_socket_funcs.close(*sdp_sd);
1055			_socket_funcs.close(*tcp_sd);
1056
1057			/* TCP and SDP without library return EINVAL */
1058			if (errno == EADDRINUSE)
1059				errno = EINVAL;
1060
1061			goto done;
1062		}
1063		/* IP is ETH, not IB, so can't bind() to sdp socket */
1064		/* Continue only with TCP */
1065		_socket_funcs.close(*sdp_sd);
1066		*sdp_sd = -1;
1067	}
1068
1069	__sdp_log(1, "check_legal_bind: binding TCP socket\n");
1070	ret = __bind_semantics(*tcp_sd, sin_addr, addrlen, semantics);
1071	if (ret < 0) {
1072		__sdp_log(9, "Error check_legal_bind: "
1073				  "binding TCP socket failed:%s\n", strerror(errno));
1074		if (-1 != *sdp_sd)
1075			_socket_funcs.close(*sdp_sd);
1076		_socket_funcs.close(*tcp_sd);
1077		goto done;
1078	}
1079	ret = 0;
1080	__sdp_log(2, "check_legal_bind: result:<%d>\n", ret);
1081done:
1082	return ret;
1083}
1084
1085/* ========================================================================= */
1086/*..close_and_bind - close an open fd and bind another one immediately       */
1087static int
1088close_and_bind(int old_sd,
1089			   int new_sd,
1090			   const struct sockaddr *addr, socklen_t addrlen, int semantics)
1091{
1092	int ret;
1093
1094	__sdp_log(2, "close_and_bind: closing <%d> binding <%d>\n", old_sd, new_sd);
1095	ret = _socket_funcs.close(old_sd);
1096	if (ret < 0) {
1097		__sdp_log(9, "Error bind: Could not close old_sd\n");
1098		goto done;
1099	}
1100
1101	ret = __bind_semantics(new_sd, addr, addrlen, semantics);
1102	if (ret < 0)
1103		__sdp_log(9, "Error bind: Could not bind new_sd\n");
1104
1105done:
1106	__sdp_log(2, "close_and_bind: returning <%d>\n", ret);
1107	return ret;
1108}
1109
1110/* ========================================================================= */
1111/*..bind -- replacement bind call.                                           */
1112/*
1113   As we do not know the role of this socket yet so we cannot choose AF.
1114   We need to be able to handle shadow too.
1115   SDP sockets (may be shadow or not) must be using converted address
1116
1117	Since there is no way to "rebind" a socket we have to avoid "false" bind:
1118	1. When the given address for the bind includes a port we need to
1119	   guarantee the port is free on both address families. We do that
1120      by creating temporary sockets and biding them first. Then we close and
1121		re-use the address on the real sockets.
1122	2. When ANY_PORT is requested we need to make sure the port we obtain from
1123	   the first address family is also free on the second one. We use temporary
1124		sockets for that task too. We loop several times to find such common
1125		available socket
1126*/
1127static int
1128__perform_bind(int fd,
1129			   const struct sockaddr *addr, socklen_t addrlen, int semantics)
1130{
1131	int shadow_fd;
1132	struct sockaddr_in *sin_addr = (struct sockaddr_in *) addr;
1133	int ret, sret = -1;
1134	char buf[MAX_ADDR_STR_LEN];
1135
1136	if (init_status == 0)
1137		__sdp_init();
1138
1139	if (NULL == _socket_funcs.bind) {
1140		__sdp_log(9, "Error bind: no implementation for bind found\n");
1141		return -1;
1142	}
1143
1144	shadow_fd = get_shadow_fd_by_fd(fd);
1145
1146	if ((addr == NULL) || is_invalid_addr(addr)) {
1147		errno = EFAULT;
1148		__sdp_log(9, "Error bind: illegal address provided\n");
1149		return -1;
1150	}
1151
1152	if (get_addr_str(addr, buf, MAX_ADDR_STR_LEN)) {
1153		__sdp_log(9, "Error bind: provided illegal address: %s\n",
1154				  strerror(errno));
1155		return -1;
1156	}
1157
1158	__sdp_log(2, "BIND: <%s:%d:%d> type <%d> IP <%s> port <%d>\n",
1159			  program_invocation_short_name, fd, shadow_fd,
1160			  sin_addr->sin_family, buf, ntohs(sin_addr->sin_port));
1161
1162	if (get_is_sdp_socket(fd)) {
1163		__sdp_log(1, "BIND: binding SDP socket:<%d>\n", fd);
1164		ret = __bind_semantics(fd, addr, addrlen, semantics);
1165		goto done;
1166	} else if (shadow_fd != -1) {
1167		/* has shadow */
1168		/* we need to validate the given address or find a common port
1169		 * so we use the following tmp address and sockets */
1170		struct sockaddr_storage tmp_addr;
1171		int sdp_sd = -1, tcp_sd = -1, port;
1172
1173		memcpy(&tmp_addr, addr, addrlen);
1174		ret = 0;
1175		if (ntohs(sin_addr->sin_port) == 0) {
1176			/* When we get ANY_PORT we need to make sure that both TCP
1177			 * and SDP sockets will use the same port */
1178
1179			port = find_free_port(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics);
1180			if (port < 0) {
1181				ret = -1;
1182				__sdp_log(9, "BIND: Failed to find common free port\n");
1183				/* We cannot bind both tcp and sdp on the same port, we will close
1184				 * the sdp and continue with tcp only */
1185				goto done;
1186			} else {
1187				/* copy the port to the tmp address */
1188				set_addr_port_num((struct sockaddr *) &tmp_addr, port);
1189			}
1190		} else {
1191			/* have a shadow but requested specific port - check that we
1192			 * can actually bind the two addresses and then reuse */
1193			ret = check_legal_bind(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics);
1194			if (ret < 0) {
1195				__sdp_log(9, "Error bind: "
1196						  "Provided address can not bind on the two sockets\n");
1197			}
1198		}
1199
1200		/* if we fail to find a common port or given address can not be used
1201		 * we return error */
1202		if (ret < 0) {
1203			/* Temporary sockets already closed by check_legal_bind or
1204			 * find_free_port */
1205			errno = EADDRINUSE;
1206			goto done;
1207		}
1208
1209		/* close temporary sockets and reuse their address */
1210		/* HACK: close_and_bind might race with other applications. */
1211		/* When the race occur we return EADDRINUSE */
1212		ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) &tmp_addr,
1213						   addrlen, semantics);
1214		if (ret < 0) {
1215			__sdp_log(9, "Error bind: " "Could not close_and_bind TCP side\n");
1216			if (-1 != sdp_sd)
1217				_socket_funcs.close(sdp_sd);
1218			goto done;
1219		}
1220
1221		if (-1 != sdp_sd) {
1222			ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) &tmp_addr,
1223							   addrlen, semantics);
1224
1225			if (ret < 0) {
1226				__sdp_log(9,
1227						  "Error bind: " "Could not close_and_bind sdp side\n");
1228				goto done;
1229			}
1230		}
1231		goto done;
1232	}
1233
1234	/* we can only get here on single TCP socket */
1235	__sdp_log(1, "BIND: binding TCP socket:<%d>\n", fd);
1236	ret = __bind_semantics(fd, addr, addrlen, semantics);
1237
1238done:
1239	__sdp_log(2, "BIND: <%s:%d:%d> result <%d:%d>\n",
1240			  program_invocation_short_name, fd, shadow_fd, ret, sret);
1241
1242	return ret;
1243}								/* bind */
1244
1245
1246int bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
1247{
1248	return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_DEFAULT);
1249}
1250
1251#ifdef SOLARIS_BUILD
1252int __xnet_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
1253{
1254	return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_XNET);
1255}
1256#endif
1257
1258
1259/* ========================================================================= */
1260/*..connect -- replacement connect call.                                     */
1261/*
1262  Given the connect address we can take out AF decision
1263  if target AF == both it means SDP and fall back to TCP
1264  if any connect worked we are fine
1265*/
1266static inline int
1267__connect_semantics(int fd,
1268					const struct sockaddr *serv_addr,
1269					socklen_t addrlen, int semantics)
1270{
1271	return
1272#ifdef SOLARIS_BUILD
1273		(semantics == SOCKET_SEMANTIC_XNET) ?
1274		_socket_xnet_funcs.connect(fd, serv_addr, addrlen) :
1275#endif
1276		_socket_funcs.connect(fd, serv_addr, addrlen);
1277}
1278
1279static int
1280__perform_connect(int fd, const struct sockaddr *serv_addr,
1281		socklen_t addrlen, int semantics)
1282{
1283	struct sockaddr_in *serv_sin = (struct sockaddr_in *) serv_addr;
1284	char buf[MAX_ADDR_STR_LEN];
1285	int shadow_fd;
1286	int ret = -1, dup_ret;
1287	use_family_t target_family;
1288	int fopts;
1289
1290	if (init_status == 0)
1291		__sdp_init();
1292
1293	if (NULL == _socket_funcs.connect) {
1294		__sdp_log(9, "Error connect: no implementation for connect found\n");
1295		return -1;
1296	}
1297
1298	shadow_fd = get_shadow_fd_by_fd(fd);
1299
1300	if ((serv_addr == NULL) || is_invalid_addr(serv_addr)) {
1301		errno = EFAULT;
1302		__sdp_log(9, "Error connect: illegal address provided\n");
1303		return -1;
1304	}
1305
1306	if (get_addr_str(serv_addr, buf, MAX_ADDR_STR_LEN)) {
1307		__sdp_log(9, "Error connect: provided illegal address: %s\n",
1308				  strerror(errno));
1309		return EADDRNOTAVAIL;
1310	}
1311
1312	__sdp_log(2, "CONNECT: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n",
1313			  program_invocation_short_name, fd, shadow_fd,
1314			  serv_sin->sin_family, buf, ntohs(serv_sin->sin_port));
1315
1316
1317	/* obtain the target address family */
1318	target_family = __sdp_match_connect(serv_addr, addrlen);
1319
1320	/* if we do not have a shadow - just do the work */
1321	if (shadow_fd == -1) {
1322		__sdp_log(1, "CONNECT: connectingthrough %s\n",
1323				get_is_sdp_socket(fd) ? "SDP" : "TCP");
1324		ret = __connect_semantics(fd, serv_addr, addrlen, semantics);
1325		if ((ret == 0) || (errno == EINPROGRESS)) {
1326			__sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n",
1327					fd, buf, ntohs(serv_sin->sin_port));
1328		}
1329		goto done;
1330	}
1331
1332	if ((target_family == USE_SDP) || (target_family == USE_BOTH)) {
1333		/* NOTE: the entire if sequence is negative logic */
1334		__sdp_log(1, "CONNECT: connecting SDP fd:%d\n", shadow_fd);
1335
1336		/* make the socket blocking on shadow SDP */
1337		fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL);
1338		if ((target_family == USE_BOTH) && (fopts & O_NONBLOCK)) {
1339			__sdp_log(1,
1340					  "CONNECT: shadow_fd <%d> will be blocking during connect\n",
1341					  shadow_fd);
1342			_socket_funcs.fcntl(shadow_fd, F_SETFL, fopts & (~O_NONBLOCK));
1343		}
1344
1345		ret = __connect_semantics(shadow_fd, serv_addr, addrlen, semantics);
1346		if ((ret < 0) && (errno != EINPROGRESS)) {
1347			__sdp_log(9, "Error connect: "
1348					  "failed for SDP fd:%d with error:%m\n", shadow_fd);
1349		} else {
1350			__sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n",
1351					  fd, buf, ntohs(serv_sin->sin_port));
1352		}
1353
1354		/* restore socket options */
1355		_socket_funcs.fcntl(shadow_fd, F_SETFL, fopts);
1356
1357		/* if target is SDP or we succeeded we need to dup SDP fd into TCP fd */
1358		if ((target_family == USE_SDP) || (ret >= 0)) {
1359			dup_ret = replace_fd_with_its_shadow(fd);
1360			if (dup_ret < 0) {
1361				__sdp_log(9, "Error connect: "
1362						  "failed to dup2 shadow into orig fd:%d\n", fd);
1363				ret = dup_ret;
1364			} else {
1365				/* we can skip the TCP option if we are done */
1366				__sdp_log(1, "CONNECT: "
1367						  "matched SDP fd:%d so shadow dup into TCP\n", fd);
1368				goto done;
1369			}
1370		}
1371	}
1372
1373	if ((target_family == USE_TCP) || (target_family == USE_BOTH)) {
1374		__sdp_log(1, "CONNECT: connecting TCP fd:%d\n", fd);
1375		ret = __connect_semantics(fd, serv_addr, addrlen, semantics);
1376		if ((ret < 0) && (errno != EINPROGRESS))
1377			__sdp_log(9, "Error connect: for TCP fd:%d failed with error:%m\n",
1378					  fd);
1379		else
1380			__sdp_log(7, "CONNECT: connected TCP fd:%d to:%s port %d\n",
1381					  fd, buf, ntohs(serv_sin->sin_port));
1382
1383		if ((target_family == USE_TCP) || (ret >= 0) || (errno == EINPROGRESS)) {
1384			if (cleanup_shadow(fd) < 0)
1385				__sdp_log(9,
1386						  "Error connect: failed to cleanup shadow for fd:%d\n",
1387						  fd);
1388		}
1389	}
1390
1391done:
1392	__sdp_log(2, "CONNECT: <%s:%d:%d> result <%d>\n",
1393			  program_invocation_short_name, fd, shadow_fd, ret);
1394
1395	return ret;
1396}								/* connect */
1397
1398int connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
1399{
1400	return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_DEFAULT);
1401}
1402
1403#if defined( SOLARIS_BUILD )
1404int __xnet_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
1405{
1406	return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_XNET);
1407}
1408#endif
1409
1410/* ========================================================================= */
1411/*..listen -- replacement listen call.                                       */
1412/*
1413   Now we know our role (passive/server) and our address so we can get AF.
1414   If both we should try listening on both
1415*/
1416
1417static inline int __listen_semantics(int fd, int backlog, int semantics)
1418{
1419	return
1420#ifdef SOLARIS_BUILD
1421		(semantics == SOCKET_SEMANTIC_XNET) ?
1422		_socket_xnet_funcs.listen(fd, backlog) :
1423#endif
1424		_socket_funcs.listen(fd, backlog);
1425}
1426
1427static int __perform_listen(int fd, int backlog, int semantics)
1428{
1429	use_family_t target_family;
1430	int shadow_fd;
1431	int ret = 0, sret = 0;
1432	struct sockaddr_storage tmp_sin;
1433	socklen_t tmp_sinlen = sizeof(tmp_sin);
1434	struct sockaddr_in *sin4 = (struct sockaddr_in *) &tmp_sin;
1435	char buf[MAX_ADDR_STR_LEN];
1436	int actual_port;
1437
1438	if (init_status == 0)
1439		__sdp_init();
1440
1441	if (NULL == _socket_funcs.listen) {
1442		__sdp_log(9, "Error listen: no implementation for listen found\n");
1443		return -1;
1444	}
1445
1446	shadow_fd = get_shadow_fd_by_fd(fd);
1447	__sdp_log(2, "LISTEN: <%s:%d:%d>\n",
1448			  program_invocation_short_name, fd, shadow_fd);
1449
1450	/* if there is no shadow - simply call listen */
1451	if (shadow_fd == -1) {
1452		__sdp_log(1, "LISTEN: calling listen on fd:%d\n", fd);
1453		ret = __listen_semantics(fd, backlog, semantics);
1454		goto done;
1455	}
1456
1457	/* we need to obtain the address from the fd */
1458	if (_socket_funcs.getsockname(fd, (struct sockaddr *) &tmp_sin, &tmp_sinlen)
1459		< 0) {
1460		__sdp_log(9, "Error listen: getsockname return <%d> for TCP socket\n",
1461				  errno);
1462		errno = EADDRNOTAVAIL;
1463		sret = -1;
1464		goto done;
1465	}
1466
1467	if (get_addr_str((struct sockaddr *) &tmp_sin, buf, MAX_ADDR_STR_LEN)) {
1468		__sdp_log(9, "Error listen: provided illegal address: %s\n",
1469				  strerror(errno));
1470	}
1471
1472	__sdp_log(2, "LISTEN: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n",
1473			  program_invocation_short_name, fd, shadow_fd,
1474			  sin4->sin_family, buf, ntohs(sin4->sin_port));
1475
1476	target_family =
1477		__sdp_match_listen((struct sockaddr *) &tmp_sin, sizeof(tmp_sin));
1478
1479	/*
1480	 * in case of an implicit bind and "USE_BOTH" rule we need to first bind the
1481	 * two sockets to the same port number
1482	 */
1483	actual_port = ntohs(sin4->sin_port);
1484
1485	/* do we need to implicit bind both */
1486	if ((actual_port == 0) && (target_family == USE_BOTH)) {
1487		int sdp_sd = -1, tcp_sd = -1;
1488
1489		actual_port = find_free_port((struct sockaddr *) &tmp_sin, tmp_sinlen,
1490				fd, &sdp_sd, &tcp_sd, semantics);
1491		if (actual_port < 0) {
1492			ret = -1;
1493			__sdp_log(8, "LISTEN: Failed to find common free port. Only TCP will be used.\n");
1494			target_family = USE_TCP;
1495		} else {
1496			/* copy the port to the tmp address */
1497			set_addr_port_num((struct sockaddr *) sin4, actual_port);
1498
1499			__sdp_log(2, "LISTEN: BOTH on IP <%s> port <%d>\n",
1500					  buf, actual_port);
1501			/* perform the bind */
1502			ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) sin4,
1503					tmp_sinlen, semantics);
1504			if (ret < 0) {
1505				__sdp_log(9, "Error listen: "
1506						  "Could not close_and_bind TCP side\n");
1507			}
1508
1509			ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) sin4,
1510					tmp_sinlen, semantics);
1511			if (ret < 0) {
1512				__sdp_log(9, "Error listen: "
1513						  "Could not close_and_bind SDP side\n");
1514			}
1515		}
1516	}
1517
1518	if ((target_family == USE_TCP) || (target_family == USE_BOTH)) {
1519		__sdp_log(1, "LISTEN: calling listen on TCP fd:%d\n", fd);
1520		ret = __listen_semantics(fd, backlog, semantics);
1521		if (ret < 0) {
1522			__sdp_log(9, "Error listen: failed with code <%d> on TCP fd:<%d>\n",
1523					  errno, fd);
1524		} else {
1525			__sdp_log(7, "LISTEN: fd:%d listening on TCP bound to:%s port:%d\n",
1526					  fd, buf, actual_port);
1527		}
1528	}
1529
1530	if ((target_family == USE_SDP) || (target_family == USE_BOTH)) {
1531		__sdp_log(1, "LISTEN: calling listen on SDP fd:<%d>\n", shadow_fd);
1532		sret = __listen_semantics(shadow_fd, backlog, semantics);
1533		if (sret < 0) {
1534			__sdp_log(9, "Error listen: failed with code <%d> SDP fd:<%d>\n",
1535					  errno, shadow_fd);
1536		} else {
1537			__sdp_log(7, "LISTEN: fd:%d listening on SDP bound to:%s port:%d\n",
1538					  fd, buf, actual_port);
1539		}
1540	}
1541
1542	/* cleanup the un-needed shadow if TCP and did not fail */
1543	if ((target_family == USE_TCP) && (ret >= 0)) {
1544		__sdp_log(1, "LISTEN: cleaning up shadow SDP\n");
1545		if (cleanup_shadow(fd) < 0)
1546			__sdp_log(9, "Error listen: failed to cleanup shadow for fd:%d\n",
1547					  fd);
1548	}
1549
1550	/* cleanup the TCP socket and replace with SDP */
1551	if ((target_family == USE_SDP) && (sret >= 0)) {
1552		__sdp_log(1, "LISTEN: cleaning TCP socket and dup2 SDP into it\n");
1553		if (0 > (sret = replace_fd_with_its_shadow(fd)))
1554			__sdp_log(9, "Error listen: "
1555					  "failed to dup2 shadow into orig fd:%d\n", fd);
1556	}
1557
1558done:
1559	__sdp_log(2, "LISTEN: <%s:%d:%d> result <%d>\n",
1560			  program_invocation_short_name, fd, shadow_fd, ret);
1561	/* its a success only if both are ok */
1562	if (ret < 0)
1563		return (ret);
1564	if (sret < 0)
1565		return (sret);
1566	return 0;
1567}								/* listen */
1568
1569int listen(int fd, int backlog)
1570{
1571	return __perform_listen(fd, backlog, SOCKET_SEMANTIC_DEFAULT);
1572}
1573
1574#ifdef SOLARIS_BUILD
1575int __xnet_listen(int fd, int backlog)
1576{
1577	return __perform_listen(fd, backlog, SOCKET_SEMANTIC_XNET);
1578}
1579#endif
1580
1581/* ========================================================================= */
1582/*..close -- replacement close call. */
1583int close(int fd)
1584{
1585	int shadow_fd;
1586	int ret;
1587
1588	if (init_status == 0)
1589		__sdp_init();
1590
1591	if (NULL == _socket_funcs.close) {
1592		__sdp_log(9, "Error close: no implementation for close found\n");
1593		return -1;
1594	}
1595
1596	shadow_fd = get_shadow_fd_by_fd(fd);
1597
1598	__sdp_log(2, "CLOSE: <%s:%d:%d>\n",
1599			  program_invocation_short_name, fd, shadow_fd);
1600
1601	if (shadow_fd != -1) {
1602		__sdp_log(1, "CLOSE: closing shadow fd:<%d>\n", shadow_fd);
1603		if (cleanup_shadow(fd) < 0)
1604			__sdp_log(9, "Error close: failed to cleanup shadow for fd:%d\n",
1605					  fd);
1606	}
1607
1608	init_extra_attribute(fd);
1609	ret = _socket_funcs.close(fd);
1610	__sdp_log(2, "CLOSE: <%s:%d:%d> result <%d>\n",
1611			  program_invocation_short_name, fd, shadow_fd, ret);
1612	return ret;
1613}								/* close */
1614
1615/* ========================================================================= */
1616/*..dup -- replacement dup call.                                             */
1617/* we duplicate the fd and its shadow if exists - ok if the main worked      */
1618int dup(int fd)
1619{
1620	int newfd, new_shadow_fd = -1;
1621	int shadow_fd;
1622
1623	if (init_status == 0)
1624		__sdp_init();
1625
1626	if (NULL == _socket_funcs.dup) {
1627		__sdp_log(9, "Error dup: no implementation for dup found\n");
1628		return -1;
1629	}
1630
1631	shadow_fd = get_shadow_fd_by_fd(fd);
1632
1633	__sdp_log(2, "DUP: <%s:%d:%d>\n",
1634			  program_invocation_short_name, fd, shadow_fd);
1635
1636	__sdp_log(1, "DUP: duplication fd:<%d>\n", fd);
1637	newfd = _socket_funcs.dup(fd);
1638
1639	if (newfd == fd)
1640		return (fd);
1641
1642	if (!is_valid_fd(newfd)) {
1643		__sdp_log(9, "Error dup: new fd <%d> out of range.\n", newfd);
1644	} else {
1645		/* copy attributes from old fd */
1646		libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd];
1647		libsdp_fd_attributes[newfd].shadow_fd = -1;
1648
1649		if (shadow_fd != -1) {
1650			__sdp_log(1, "DUP: duplication shadow fd:<%d>\n", shadow_fd);
1651			new_shadow_fd = _socket_funcs.dup(shadow_fd);
1652			if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) {
1653				__sdp_log(9, "Error dup: new shadow fd <%d> out of range.\n",
1654						  new_shadow_fd);
1655			} else {
1656				libsdp_fd_attributes[new_shadow_fd] =
1657					libsdp_fd_attributes[shadow_fd];
1658				libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd;
1659			}
1660		}						/* shadow exists */
1661	}
1662
1663	__sdp_log(2, "DUP: <%s:%d:%d> return <%d:%d>\n",
1664			  program_invocation_short_name, fd, shadow_fd, newfd,
1665			  new_shadow_fd);
1666
1667	return newfd;
1668}								/* dup */
1669
1670/* ========================================================================= */
1671/*..dup2 -- replacement dup2 call.                                           */
1672/* since only the main new fd is given we only move the shadow if exists     */
1673int dup2(int fd, int newfd)
1674{
1675	int shadow_fd;
1676	int shadow_newfd;
1677	int new_shadow_fd = -1;
1678	int ret = 0;
1679
1680	if (init_status == 0)
1681		__sdp_init();
1682
1683	if (NULL == _socket_funcs.dup2) {
1684		__sdp_log(9, "Error dup2: no implementation for dup2 found\n");
1685		return -1;
1686	}
1687
1688	shadow_fd = get_shadow_fd_by_fd(fd);
1689	shadow_newfd = get_shadow_fd_by_fd(newfd);
1690
1691	__sdp_log(2, "DUP2: <%s:%d:%d>\n",
1692			  program_invocation_short_name, fd, shadow_fd);
1693
1694	if (newfd == fd) {
1695		__sdp_log(1, "DUP2: skip duplicating fd:<%d> into:<%d>\n", fd, newfd);
1696		goto done;
1697	}
1698
1699	/* dup2 closes the target file desc if it is a valid fd */
1700	if (shadow_newfd != -1) {
1701		__sdp_log(1, "DUP2: closing newfd:<%d> shadow:<%d>\n", newfd,
1702				  shadow_newfd);
1703		ret = _socket_funcs.close(shadow_newfd);
1704		if (ret != 0) {
1705			__sdp_log(9,
1706					  "DUP2: fail to close newfd:<%d> shadow:<%d> with: %d %s\n",
1707					  newfd, shadow_newfd, ret, strerror(errno));
1708		}
1709	}
1710
1711	__sdp_log(1, "DUP2: duplicating fd:<%d> into:<%d>\n", fd, newfd);
1712	newfd = _socket_funcs.dup2(fd, newfd);
1713	if ((newfd > max_file_descriptors) || (newfd < 0)) {
1714		__sdp_log(9, "Error dup2: new fd <%d> out of range.\n", newfd);
1715	} else {
1716		/* copy attributes from old fd */
1717		libsdp_fd_attributes[fd].shadow_fd = -1;
1718		libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd];
1719
1720		/* if it had a shadow create a new shadow */
1721		if (shadow_fd != -1) {
1722			__sdp_log(1, "DUP2: duplication shadow fd:<%d>\n", shadow_fd);
1723			new_shadow_fd = _socket_funcs.dup(shadow_fd);
1724			if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) {
1725				__sdp_log(9, "Error dup2: new shadow fd <%d> out of range.\n",
1726						  new_shadow_fd);
1727			} else {
1728				libsdp_fd_attributes[new_shadow_fd] =
1729					libsdp_fd_attributes[shadow_fd];
1730				libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd;
1731			}
1732		}						/* newfd is ok */
1733	}
1734
1735done:
1736	__sdp_log(2, "DUP2: <%s:%d:%d> return <%d:%d>\n",
1737			  program_invocation_short_name, fd, shadow_fd, newfd,
1738			  new_shadow_fd);
1739
1740	return newfd;
1741}								/* dup */
1742
1743/* ========================================================================= */
1744/*..getsockname -- replacement getsocknanme call.                            */
1745int getsockname(int fd, struct sockaddr *name, socklen_t * namelen)
1746{
1747	int ret = 0;
1748	char buf[MAX_ADDR_STR_LEN];
1749
1750	if (init_status == 0)
1751		__sdp_init();
1752
1753	/*
1754	 * ensure the SDP protocol family is not exposed to the user, since
1755	 * this is meant to be a transparency layer.
1756	 */
1757	if (NULL == _socket_funcs.getsockname) {
1758		__sdp_log(9,
1759				  "Error getsockname: no implementation for getsockname found\n");
1760		return -1;
1761	}
1762
1763	/* double check provided pointers */
1764	if ((name == NULL) || is_invalid_addr(name)) {
1765		errno = EFAULT;
1766		__sdp_log(9, "Error getsockname: illegal address provided\n");
1767		return -1;
1768	}
1769
1770	if ((namelen != NULL) && is_invalid_addr(namelen)) {
1771		errno = EFAULT;
1772		__sdp_log(9, "Error getsockname: illegal address length pointer provided\n");
1773		return -1;
1774	}
1775
1776	__sdp_log(2, "GETSOCKNAME <%s:%d>\n", program_invocation_short_name, fd);
1777
1778	ret = _socket_funcs.getsockname(fd, name, namelen);
1779
1780	if (__sdp_log_get_level() <= 1) {
1781		if (get_addr_str(name, buf, MAX_ADDR_STR_LEN)) {
1782			__sdp_log(1, "GETSOCKNAME: " "address is illegal\n");
1783		} else {
1784			__sdp_log(1, "GETSOCKNAME: address is:%s port:%d\n", buf,
1785					  ntohs(((struct sockaddr_in *) name)->sin_port));
1786		}
1787	}
1788	__sdp_log(2, "GETSOCKNAME <%s:%d> result <%d>\n",
1789			  program_invocation_short_name, fd, ret);
1790
1791	return ret;
1792}								/* getsockname */
1793
1794/* ========================================================================= */
1795/*..getpeername -- replacement getpeername call. */
1796int getpeername(int fd, struct sockaddr *name, socklen_t * namelen)
1797{
1798	int ret = 0;
1799
1800	if (init_status == 0)
1801		__sdp_init();
1802
1803	if (NULL == _socket_funcs.getpeername) {
1804		__sdp_log(9, "Error getpeername: "
1805				  "no implementation for getpeername found\n");
1806		return -1;
1807	}
1808
1809	/* double check provided pointers */
1810	if ((name == NULL) || is_invalid_addr(name)) {
1811		errno = EFAULT;
1812		__sdp_log(9, "Error getsockname: illegal address provided\n");
1813		return -1;
1814	}
1815
1816	if ((namelen != NULL) && is_invalid_addr(namelen)) {
1817		errno = EFAULT;
1818		__sdp_log(9,
1819				  "Error getsockname: illegal address length pointer provided\n");
1820		return -1;
1821	}
1822
1823	__sdp_log(2, "GETPEERNAME <%s:%d>\n", program_invocation_short_name, fd);
1824
1825	ret = _socket_funcs.getpeername(fd, name, namelen);
1826
1827	__sdp_log(2, "GETPEERNAME <%s:%d> result <%d:%d> family=%d s_addr=%d\n",
1828			  program_invocation_short_name, fd, ret,
1829			  (!(0 > ret) ? 0 : -1), name->sa_family,
1830			  ((struct sockaddr_in *) name)->sin_addr.s_addr);
1831
1832	return ret;
1833}								/* getpeername */
1834
1835
1836
1837/* ========================================================================= */
1838/*..accept -- replacement accept call.                                       */
1839/*
1840  If we have a shadow we need to decide which socket we want to accept on
1841  so we select first and then give priority based on previous selection
1842*/
1843int accept(int fd, struct sockaddr *addr, socklen_t * addrlen)
1844{
1845	int shadow_fd;
1846	int ret = 0;
1847	fd_set fds;
1848	socklen_t saved_addrlen = 0;
1849	int fopts;
1850	char buf[MAX_ADDR_STR_LEN];
1851
1852	if (init_status == 0)
1853		__sdp_init();
1854
1855	shadow_fd = get_shadow_fd_by_fd(fd);
1856
1857	/*
1858	 * ensure the SDP protocol family is not exposed to the user, since
1859	 * this is meant to be a transparency layer.
1860	 */
1861	if (NULL == _socket_funcs.accept) {
1862		__sdp_log(9, "Error accept: no implementation for accept found\n");
1863		return -1;
1864	}
1865
1866	/* double check provided pointers */
1867	if ((addr != NULL) && is_invalid_addr(addr)) {
1868		errno = EINVAL;
1869		__sdp_log(9, "Error accept: illegal address provided\n");
1870		return -1;
1871	}
1872
1873	if ((addrlen != NULL) && is_invalid_addr(addrlen)) {
1874		errno = EINVAL;
1875		__sdp_log(9, "Error accept: illegal address length pointer provided\n");
1876		return -1;
1877	}
1878
1879	if (addr && addrlen)
1880		saved_addrlen = *addrlen;
1881
1882	__sdp_log(2, "ACCEPT: <%s:%d>\n", program_invocation_short_name, fd);
1883
1884	if (shadow_fd == -1) {
1885		fopts = _socket_funcs.fcntl(fd, F_GETFL);
1886		__sdp_log(1, "ACCEPT: fd <%d> opts are <0x%x>\n", fd, fopts);
1887
1888		__sdp_log(7, "ACCEPT: accepting on single fd:<%d>\n", fd);
1889		ret = _socket_funcs.accept(fd, addr, addrlen);
1890		if (ret < 0) {
1891			if (!(fopts & O_NONBLOCK && errno == EWOULDBLOCK))
1892				__sdp_log(9, "Error accept: accept returned :<%d> %s\n",
1893						  ret, strerror(errno));
1894		} else {
1895			set_is_sdp_socket(ret, get_is_sdp_socket(fd));
1896		}
1897	} else {
1898
1899		fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL);
1900		__sdp_log(1, "ACCEPT: shadow_fd <%d> opts are <0x%x>\n",
1901				  shadow_fd, fopts);
1902
1903		/* we need different behavior for NONBLOCK or signal IO and BLOCK */
1904		if ((fopts > 0) && (fopts & (O_NONBLOCK | FASYNC))) {
1905			__sdp_log(1, "ACCEPT: accepting (nonblock) on SDP fd:<%d>\n", shadow_fd);
1906
1907			ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1908			if (ret >= 0) {
1909				set_is_sdp_socket(ret, 1);
1910
1911				__sdp_log(7, "ACCEPT: accepted (nonblock) SDP fd:<%d>\n",
1912						  shadow_fd);
1913			} else {
1914				__sdp_log(1, "ACCEPT: accept on SDP fd:<%d> return:%d errno:%d\n",
1915						  shadow_fd, ret, errno);
1916
1917				__sdp_log(1, "ACCEPT: accepting (nonblock) on TCP fd:<%d>\n", fd);
1918				ret = _socket_funcs.accept(fd, addr, addrlen);
1919				if (ret >= 0) {
1920					__sdp_log(7, "ACCEPT: accepted (nonblock) TCP fd:<%d>\n",
1921							  shadow_fd);
1922				} else {
1923					__sdp_log(1, "ACCEPT: accept on TCP fd:<%d> "
1924							  "return:%d errno:%d\n", fd, ret, errno);
1925				}
1926			}
1927		} else {
1928			__sdp_log(1, "ACCEPT: selecting both fd:<%d> and shadow:<%d>\n",
1929					  fd, shadow_fd);
1930			FD_ZERO(&fds);
1931			FD_SET(fd, &fds);
1932			FD_SET(shadow_fd, &fds);
1933			ret =
1934				_socket_funcs.select(1 + ((fd > shadow_fd) ? fd : shadow_fd),
1935									 &fds, NULL, NULL, NULL);
1936			if (ret >= 0) {
1937				if (last_accept_was_tcp(fd) == 0) {
1938					if (FD_ISSET(fd, &fds)) {
1939						set_last_accept(fd, 1);
1940						__sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd);
1941						ret = _socket_funcs.accept(fd, addr, addrlen);
1942					} else {
1943						__sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n",
1944								  shadow_fd);
1945						ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1946						if (ret >= 0)
1947							set_is_sdp_socket(ret, 1);
1948					}
1949				} else {
1950					if (FD_ISSET(shadow_fd, &fds)) {
1951						set_last_accept(fd, 1);
1952						__sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n",
1953								  shadow_fd);
1954						ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1955						if (ret >= 0)
1956							set_is_sdp_socket(ret, 1);
1957					} else {
1958						__sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd);
1959						ret = _socket_funcs.accept(fd, addr, addrlen);
1960					}
1961				}
1962			} else {
1963				if (errno != EINTR) {
1964					__sdp_log(9,
1965							  "Error accept: select returned :<%d> (%d) %s\n",
1966							  ret, errno, strerror(errno));
1967				} else {
1968					__sdp_log(1, "ACCEPT: select returned :<%d> (%d) %s\n",
1969							  ret, errno, strerror(errno));
1970				}
1971			}
1972		}						/* blocking mode */
1973	}							/* shadow fd */
1974
1975	if ((__sdp_log_get_level() <= 1) && (ret >= 0) && addr && addrlen) {
1976		get_addr_str(addr, buf, *addrlen);
1977		__sdp_log(1, "ACCEPT: accepted from:%s port:%d into fd:%d\n",
1978				  buf, ntohs(((struct sockaddr_in *) addr)->sin_port), ret);
1979	}
1980	__sdp_log(2, "ACCEPT: <%s:%d> return <%d>\n",
1981			  program_invocation_short_name, fd, ret);
1982
1983	return ret;
1984}								/* accept */
1985
1986/* ========================================================================= */
1987/*..select -- replacement socket call.                                       */
1988/*
1989   if we have shadow we must select on it too - which requires a hack back
1990   and forth
1991*/
1992int
1993select(int n,
1994	   fd_set * readfds,
1995	   fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
1996{
1997	int shadow_fd;
1998	int ret;
1999	int current;
2000	int maxi = 0;
2001	fd_set new_fds;
2002
2003	if (init_status == 0)
2004		__sdp_init();
2005
2006	if (NULL == _socket_funcs.select) {
2007		__sdp_log(9, "Error select: no implementation for select found\n");
2008		return -1;
2009	}
2010
2011	__sdp_log(2, "SELECT: <%s:%d>\n", program_invocation_short_name, n);
2012
2013	/* if we do not read - nothing to do */
2014	if (readfds == NULL) {
2015		ret = _socket_funcs.select(n, readfds, writefds, exceptfds, timeout);
2016		goto done;
2017	}
2018
2019	FD_ZERO(&new_fds);
2020	if (n > 0) {
2021		maxi = n - 1;
2022	}
2023
2024	/* add shadow bits */
2025	for (current = 0; current < n; current++) {
2026		if (FD_ISSET(current, readfds)) {
2027			FD_SET(current, &new_fds);
2028			if (current > maxi) {
2029				maxi = current;
2030			}
2031			shadow_fd = get_shadow_fd_by_fd(current);
2032			if (shadow_fd != -1) {
2033				__sdp_log(1,
2034						  "SELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2035						  current, shadow_fd);
2036				FD_SET(shadow_fd, &new_fds);
2037				if (shadow_fd > maxi) {
2038					maxi = shadow_fd;
2039				}
2040			}
2041		}
2042	}
2043
2044	__sdp_log(1, "SELECT: invoking select n=<%d>\n", 1 + maxi);
2045	ret = _socket_funcs.select(1 + maxi,
2046							   &new_fds, writefds, exceptfds, timeout);
2047
2048	/* remove the count and bits of the shadows */
2049	if (ret >= 0) {
2050		for (current = 0; current < n; current++) {
2051			shadow_fd = get_shadow_fd_by_fd(current);
2052			if (shadow_fd == -1) {
2053				if (FD_ISSET(current, readfds) &&
2054					FD_ISSET(current, &new_fds) == 0) {
2055					FD_CLR(current, readfds);
2056				}
2057			} else {
2058				if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds)
2059					&& FD_ISSET(shadow_fd, &new_fds)) {
2060					ret -= 1;
2061				}
2062				if (FD_ISSET(current, readfds) &&
2063					FD_ISSET(current, &new_fds) == 0 &&
2064					FD_ISSET(shadow_fd, &new_fds) == 0) {
2065					FD_CLR(current, readfds);
2066				}
2067			}
2068		}
2069	}
2070
2071done:
2072
2073	__sdp_log(2, "SELECT: <%s:%d> return <%d>\n",
2074			  program_invocation_short_name, n, ret);
2075	return ret;
2076}								/* select */
2077
2078/* ========================================================================= */
2079/*..pselect -- replacement socket call.                                      */
2080/*
2081   if we have shadow we must pselect on it too - which requires a hack back
2082   and forth
2083*/
2084int
2085pselect(int n,
2086		fd_set * readfds,
2087		fd_set * writefds,
2088		fd_set * exceptfds,
2089		const struct timespec *timeout, const sigset_t * sigmask)
2090{
2091	int shadow_fd;
2092	int ret;
2093	int current;
2094	int maxi = 0;
2095	fd_set new_fds;
2096
2097	if (init_status == 0)
2098		__sdp_init();
2099
2100	if (NULL == _socket_funcs.pselect) {
2101		__sdp_log(9, "Error pselect: no implementation for pselect found\n");
2102		return -1;
2103	}
2104
2105	__sdp_log(2, "PSELECT: <%s:%d>\n", program_invocation_short_name, n);
2106
2107	/* if we do not read - nothing to do */
2108	if (readfds == NULL) {
2109		ret =
2110			_socket_funcs.pselect(n, readfds, writefds, exceptfds, timeout,
2111								  sigmask);
2112		goto done;
2113	}
2114
2115	FD_ZERO(&new_fds);
2116	if (n > 0) {
2117		maxi = n - 1;
2118	}
2119
2120	/* add shadow bits */
2121	for (current = 0; current < n; current++) {
2122		if (FD_ISSET(current, readfds)) {
2123			FD_SET(current, &new_fds);
2124			if (current > maxi) {
2125				maxi = current;
2126			}
2127			shadow_fd = get_shadow_fd_by_fd(current);
2128			if (shadow_fd != -1) {
2129				__sdp_log(1,
2130						  "PSELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2131						  current, shadow_fd);
2132				FD_SET(shadow_fd, &new_fds);
2133				if (shadow_fd > maxi) {
2134					maxi = shadow_fd;
2135				}
2136			}
2137		}
2138	}
2139
2140	__sdp_log(1, "PSELECT: invoking pselect n=<%d>\n", 1 + maxi);
2141	ret = _socket_funcs.pselect(1 + maxi,
2142								&new_fds, writefds, exceptfds,
2143								timeout, sigmask);
2144
2145	/* remove the count and bits of the shadows */
2146	if (ret >= 0) {
2147		for (current = 0; current < n; current++) {
2148			shadow_fd = get_shadow_fd_by_fd(current);
2149			if (shadow_fd == -1) {
2150				if (FD_ISSET(current, readfds) &&
2151					FD_ISSET(current, &new_fds) == 0) {
2152					FD_CLR(current, readfds);
2153				}
2154			} else {
2155				if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds)
2156					&& FD_ISSET(shadow_fd, &new_fds)) {
2157					ret -= 1;
2158				}
2159				if (FD_ISSET(current, readfds) &&
2160					FD_ISSET(current, &new_fds) == 0 &&
2161					FD_ISSET(shadow_fd, &new_fds) == 0) {
2162					FD_CLR(current, readfds);
2163				}
2164			}
2165		}
2166	}
2167
2168done:
2169
2170	__sdp_log(2, "PSELECT: <%s:%d> return <%d>\n",
2171			  program_invocation_short_name, n, ret);
2172	return ret;
2173}								/* pselect */
2174
2175/* ========================================================================= */
2176/*..poll -- replacement socket call.                                      */
2177/*
2178   if we have shadow we must poll on it too - which requires a hack back
2179   and forth
2180*/
2181int poll(struct pollfd *ufds, nfds_t nfds, int timeout)
2182{
2183	int ret;
2184	int shadow_fd;
2185	int current;
2186	int extra = 0;
2187	struct pollfd *poll_fds = NULL;
2188	struct pollfd *poll_fd_ptr = NULL;
2189
2190	if (init_status == 0)
2191		__sdp_init();
2192
2193	if (NULL == _socket_funcs.poll) {
2194		__sdp_log(9, "Error poll: no implementation for poll found\n");
2195		return -1;
2196	}
2197
2198	__sdp_log(2, "POLL: <%s:%d>\n", program_invocation_short_name, nfds);
2199
2200	/* if we do not have any file desc - nothing to do */
2201	if (ufds == NULL) {
2202		ret = _socket_funcs.poll(ufds, nfds, timeout);
2203		goto done;
2204	}
2205
2206	/* scan for how many extra fds are required */
2207	for (current = 0; current < nfds; current++) {
2208		shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2209		if (shadow_fd != -1)
2210			extra++;
2211	}
2212
2213	if (!extra) {
2214		poll_fds = ufds;
2215	} else {
2216		poll_fds =
2217			(struct pollfd *) malloc((nfds + extra) * sizeof(struct pollfd));
2218		if (!poll_fds) {
2219			__sdp_log(9,
2220					  "Error poll: malloc of extended pollfd array failed\n");
2221			ret = -1;
2222			errno = ENOMEM;
2223			goto done;
2224		}
2225		poll_fd_ptr = poll_fds;
2226		for (current = 0; current < nfds; current++) {
2227			*poll_fd_ptr = ufds[current];
2228			poll_fd_ptr++;
2229			shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2230			if (shadow_fd != -1) {
2231				__sdp_log(1, "POLL: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2232						  current, shadow_fd);
2233				*poll_fd_ptr = ufds[current];
2234				poll_fd_ptr->fd = shadow_fd;
2235				poll_fd_ptr++;
2236			}
2237		}
2238	}
2239
2240	__sdp_log(1, "POLL: invoking poll nfds=<%d>\n", nfds + extra);
2241	ret = _socket_funcs.poll(poll_fds, nfds + extra, timeout);
2242
2243	/* refactor into original list if any events */
2244	if ((ret > 0) && extra) {
2245		poll_fd_ptr = poll_fds;
2246		for (current = 0; current < nfds; current++) {
2247			shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2248			if (shadow_fd == -1) {
2249				ufds[current] = *poll_fd_ptr;
2250			} else {
2251				ufds[current] = *poll_fd_ptr;
2252				poll_fd_ptr++;
2253				if (poll_fd_ptr->revents) {
2254					if (ufds[current].revents)
2255						ret--;
2256					ufds[current].revents |= poll_fd_ptr->revents;
2257				}
2258			}
2259			poll_fd_ptr++;
2260		}
2261	}
2262
2263	if (extra)
2264		free(poll_fds);
2265done:
2266
2267	__sdp_log(2, "POLL: <%s:%d> return <%d>\n",
2268			  program_invocation_short_name, nfds, ret);
2269	return ret;
2270}								/* poll */
2271
2272#ifdef __linux__
2273/* ========================================================================= */
2274/*..epoll_create -- replacement socket call.                                 */
2275/*
2276   Need to make the size twice as large for shadow fds
2277*/
2278int epoll_create(int size)
2279{
2280	int epfd;
2281
2282	if (init_status == 0)
2283		__sdp_init();
2284
2285	if (NULL == _socket_funcs.epoll_create) {
2286		__sdp_log(9,
2287				  "Error epoll_create: no implementation for epoll_create found\n");
2288		return -1;
2289	}
2290
2291	__sdp_log(2, "EPOLL_CREATE: <%s:%d>\n", program_invocation_short_name,
2292			  size);
2293
2294	epfd = _socket_funcs.epoll_create(size * 2);
2295
2296	__sdp_log(2, "EPOLL_CREATE: <%s:%d> return %d\n",
2297			  program_invocation_short_name, size, epfd);
2298	return epfd;
2299}								/* epoll_create */
2300
2301/* ========================================================================= */
2302/*..epoll_ctl -- replacement socket call.                                   */
2303/*
2304   Need to add/delete/modify shadow fds as well
2305*/
2306int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
2307{
2308	int ret, shadow_fd, ret2;
2309
2310	if (init_status == 0)
2311		__sdp_init();
2312
2313	if (NULL == _socket_funcs.epoll_ctl) {
2314		__sdp_log(9,
2315				  "Error epoll_ctl: no implementation for epoll_ctl found\n");
2316		return -1;
2317	}
2318
2319	__sdp_log(2, "EPOLL_CTL: <%s:%d> op <%d:%d>\n",
2320			  program_invocation_short_name, epfd, op, fd);
2321
2322	ret = _socket_funcs.epoll_ctl(epfd, op, fd, event);
2323
2324	shadow_fd = get_shadow_fd_by_fd(fd);
2325	if (shadow_fd != -1) {
2326		ret2 = _socket_funcs.epoll_ctl(epfd, op, shadow_fd, event);
2327		if (ret2 < 0) {
2328			__sdp_log(9, "Error epoll_ctl <%s:%d:%d>",
2329					  program_invocation_short_name, fd, shadow_fd);
2330			return ret2;
2331		}
2332	}
2333
2334	__sdp_log(2, "EPOLL_CTL: <%s:%d> return <%d>\n",
2335			  program_invocation_short_name, epfd, ret);
2336	return ret;
2337}								/* epoll_ctl */
2338
2339/* ========================================================================= */
2340/*..epoll_wait -- replacement socket call.                                   */
2341/*
2342   We don't care who generated the event because all we get is user-context
2343   values.
2344*/
2345int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
2346{
2347	int ret;
2348
2349	if (init_status == 0)
2350		__sdp_init();
2351
2352	if (NULL == _socket_funcs.epoll_wait) {
2353		__sdp_log(9,
2354				  "Error epoll_wait: no implementation for epoll_wait found\n");
2355		return -1;
2356	}
2357
2358	__sdp_log(2, "EPOLL_WAIT: <%s:%d>\n", program_invocation_short_name, epfd);
2359
2360	ret = _socket_funcs.epoll_wait(epfd, events, maxevents, timeout);
2361
2362	__sdp_log(2, "EPOLL_WAIT: <%s:%d> return <%d>\n",
2363			  program_invocation_short_name, epfd, ret);
2364	return ret;
2365}								/* epoll_wait */
2366
2367/* ========================================================================= */
2368/*..epoll_pwait -- replacement socket call.                                  */
2369/*
2370   We don't care who generated the event because all we get is user-context
2371   values.
2372*/
2373int
2374epoll_pwait(int epfd,
2375			struct epoll_event *events,
2376			int maxevents, int timeout, const sigset_t * sigmask)
2377{
2378	int ret;
2379
2380	if (init_status == 0)
2381		__sdp_init();
2382
2383	if (NULL == _socket_funcs.epoll_pwait) {
2384		__sdp_log(9,
2385				  "Error epoll_pwait: no implementation for epoll_pwait found\n");
2386		return -1;
2387	}
2388
2389	__sdp_log(2, "EPOLL_PWAIT: <%s:%d>\n", program_invocation_short_name, epfd);
2390
2391	ret = _socket_funcs.epoll_pwait(epfd, events, maxevents, timeout, sigmask);
2392
2393	__sdp_log(2, "EPOLL_PWAIT: <%s:%d> return <%d>\n",
2394			  program_invocation_short_name, epfd, ret);
2395	return ret;
2396}								/* epoll_pwait */
2397#endif
2398
2399/* ========================================================================= */
2400
2401/* --------------------------------------------------------------------- */
2402/*                                                                       */
2403/* Library load/unload initialization/cleanup                            */
2404/*                                                                       */
2405/* --------------------------------------------------------------------- */
2406/* ========================================================================= */
2407/*..__sdp_init -- intialize the library */
2408void __sdp_init(void)
2409{
2410	char *config_file, *error_str;
2411	int fd;
2412	struct rlimit nofiles_limit;
2413
2414	/* HACK: races might apply here: can we assume init is happening
2415	   only within one thread ? */
2416	if (init_status != 0)
2417		return;
2418	init_status = 1;
2419
2420	dev_null_fd = open("/dev/null", O_WRONLY);
2421
2422	/* figure out the max number of file descriptors */
2423	if (getrlimit(RLIMIT_NOFILE, &nofiles_limit))
2424		max_file_descriptors = 1024;
2425	else
2426		max_file_descriptors = nofiles_limit.rlim_cur;
2427
2428	/* allocate and initialize the shadow sdp sockets array */
2429	libsdp_fd_attributes =
2430		(struct sdp_extra_fd_attributes *) calloc(max_file_descriptors,
2431												  sizeof(struct
2432														 sdp_extra_fd_attributes));
2433	for (fd = 0; fd < max_file_descriptors; fd++)
2434		init_extra_attribute(fd);
2435
2436#ifndef RTLD_NEXT
2437	/*
2438	 * open libc for original socket call.
2439	 * Solaris relies on RTLD next - since the socket calls are
2440	 * actually in libsocket rather than libc.
2441	 */
2442	__libc_dl_handle = dlopen("/lib64/libc.so.6", RTLD_LAZY);
2443	if (NULL == __libc_dl_handle) {
2444		__libc_dl_handle = dlopen("/lib/libc.so.6", RTLD_LAZY);
2445		if (NULL == __libc_dl_handle) {
2446			fprintf(stderr, "%s\n", dlerror());
2447			return;
2448		}
2449	}
2450#endif
2451
2452	/*
2453	 * Get the original functions
2454	 */
2455	_socket_funcs.ioctl = dlsym(__libc_dl_handle, "ioctl");
2456	if (NULL != (error_str = dlerror())) {
2457		fprintf(stderr, "%s\n", error_str);
2458	}
2459
2460	_socket_funcs.fcntl = dlsym(__libc_dl_handle, "fcntl");
2461	if (NULL != (error_str = dlerror())) {
2462		fprintf(stderr, "%s\n", error_str);
2463	}
2464
2465	_socket_funcs.socket = dlsym(__libc_dl_handle, "socket");
2466	if (NULL != (error_str = dlerror())) {
2467		fprintf(stderr, "%s\n", error_str);
2468	}
2469
2470	_socket_funcs.setsockopt = dlsym(__libc_dl_handle, "setsockopt");
2471	if (NULL != (error_str = dlerror())) {
2472		fprintf(stderr, "%s\n", error_str);
2473	}
2474
2475	_socket_funcs.connect = dlsym(__libc_dl_handle, "connect");
2476	if (NULL != (error_str = dlerror())) {
2477		fprintf(stderr, "%s\n", error_str);
2478	}
2479
2480	_socket_funcs.listen = dlsym(__libc_dl_handle, "listen");
2481	if (NULL != (error_str = dlerror())) {
2482		fprintf(stderr, "%s\n", error_str);
2483	}
2484
2485	_socket_funcs.bind = dlsym(__libc_dl_handle, "bind");
2486	if (NULL != (error_str = dlerror())) {
2487		fprintf(stderr, "%s\n", error_str);
2488	}
2489
2490	_socket_funcs.close = dlsym(__libc_dl_handle, "close");
2491	if (NULL != (error_str = dlerror())) {
2492		fprintf(stderr, "%s\n", error_str);
2493	}
2494
2495	_socket_funcs.dup = dlsym(__libc_dl_handle, "dup");
2496	if (NULL != (error_str = dlerror())) {
2497		fprintf(stderr, "%s\n", error_str);
2498	}
2499
2500	_socket_funcs.dup2 = dlsym(__libc_dl_handle, "dup2");
2501	if (NULL != (error_str = dlerror())) {
2502		fprintf(stderr, "%s\n", error_str);
2503	}
2504
2505	_socket_funcs.getpeername = dlsym(__libc_dl_handle, "getpeername");
2506	if (NULL != (error_str = dlerror())) {
2507		fprintf(stderr, "%s\n", error_str);
2508	}
2509
2510	_socket_funcs.getsockname = dlsym(__libc_dl_handle, "getsockname");
2511	if (NULL != (error_str = dlerror())) {
2512		fprintf(stderr, "%s\n", error_str);
2513	}
2514
2515	_socket_funcs.accept = dlsym(__libc_dl_handle, "accept");
2516	if (NULL != (error_str = dlerror())) {
2517		fprintf(stderr, "%s\n", error_str);
2518	}
2519
2520	_socket_funcs.select = dlsym(__libc_dl_handle, "select");
2521	if (NULL != (error_str = dlerror())) {
2522		fprintf(stderr, "%s\n", error_str);
2523	}
2524
2525	_socket_funcs.pselect = dlsym(__libc_dl_handle, "pselect");
2526	if (NULL != (error_str = dlerror())) {
2527		fprintf(stderr, "%s\n", error_str);
2528	}
2529
2530	_socket_funcs.poll = dlsym(__libc_dl_handle, "poll");
2531	if (NULL != (error_str = dlerror())) {
2532		fprintf(stderr, "%s\n", error_str);
2533	}
2534
2535#ifdef __linux__
2536	_socket_funcs.epoll_create = dlsym(__libc_dl_handle, "epoll_create");
2537	if (NULL != (error_str = dlerror())) {
2538		fprintf(stderr, "%s\n", error_str);
2539	}
2540
2541	_socket_funcs.epoll_ctl = dlsym(__libc_dl_handle, "epoll_ctl");
2542	if (NULL != (error_str = dlerror())) {
2543		fprintf(stderr, "%s\n", error_str);
2544	}
2545
2546	_socket_funcs.epoll_wait = dlsym(__libc_dl_handle, "epoll_wait");
2547	if (NULL != (error_str = dlerror())) {
2548		fprintf(stderr, "%s\n", error_str);
2549	}
2550
2551	_socket_funcs.epoll_pwait = dlsym(__libc_dl_handle, "epoll_pwait");
2552	if (NULL != (error_str = dlerror())) {
2553		fprintf(stderr, "%s\n", error_str);
2554	}
2555#endif
2556#ifdef SOLARIS_BUILD
2557	_socket_xnet_funcs.socket = dlsym(__libc_dl_handle, "__xnet_socket");
2558	if (NULL != (error_str = dlerror())) {
2559		fprintf(stderr, "%s\n", error_str);
2560	}
2561
2562	_socket_xnet_funcs.connect = dlsym(__libc_dl_handle, "__xnet_connect");
2563	if (NULL != (error_str = dlerror())) {
2564		fprintf(stderr, "%s\n", error_str);
2565	}
2566
2567	_socket_xnet_funcs.listen = dlsym(__libc_dl_handle, "__xnet_listen");
2568	if (NULL != (error_str = dlerror())) {
2569		fprintf(stderr, "%s\n", error_str);
2570	}
2571
2572	_socket_xnet_funcs.bind = dlsym(__libc_dl_handle, "__xnet_bind");
2573	if (NULL != (error_str = dlerror())) {
2574		fprintf(stderr, "%s\n", error_str);
2575	}
2576
2577	/* Determine program name by asking libdl */
2578	Dl_argsinfo args_info;
2579	if (NULL != dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args_info)) {
2580		fprintf(stderr, "args_info: %s\n", dlerror());
2581	} else {
2582		program_invocation_name = args_info.dla_argv[0];
2583		program_invocation_short_name = basename(args_info.dla_argv[0]);
2584	}
2585#endif
2586
2587	if (getenv("SIMPLE_LIBSDP") != NULL) {
2588		simple_sdp_library = 1;
2589	}
2590
2591	if (getenv("ALWAYS_USE_SDP") != NULL) {
2592		simple_sdp_library = 1;
2593	}
2594#define LIBSDP_DEFAULT_CONFIG_FILE  SYSCONFDIR "/libsdp.conf"
2595	if (!simple_sdp_library) {
2596		config_file = getenv("LIBSDP_CONFIG_FILE");
2597		if (!config_file)
2598			config_file = LIBSDP_DEFAULT_CONFIG_FILE;
2599
2600		if (__sdp_parse_config(config_file)) {
2601			fprintf(stderr,
2602					"libsdp Error: failed to parse config file:%s. Using defaults.\n",
2603					config_file);
2604		}
2605	}
2606
2607	__sdp_log(1, "Max file descriptors:%d\n", max_file_descriptors);
2608	init_status = 2;
2609
2610}								/* __sdp_init */
2611
2612/* ========================================================================= */
2613/*..__sdp_fini -- when the library is unloaded this is called */
2614void __sdp_fini(void)
2615{
2616	struct use_family_rule *rule;
2617	for (rule = __sdp_clients_family_rules_head; rule != NULL;
2618		 rule = rule->next)
2619		free(rule->prog_name_expr);
2620	for (rule = __sdp_servers_family_rules_head; rule != NULL;
2621		 rule = rule->next)
2622		free(rule->prog_name_expr);
2623
2624	free(libsdp_fd_attributes);
2625
2626#ifndef RTLD_NEXT
2627	dlclose(__libc_dl_handle);
2628#endif
2629}								/* _fini */
2630