1219820Sjeff/*
2219820Sjeff  This software is available to you under a choice of one of two
3219820Sjeff  licenses.  You may choose to be licensed under the terms of the GNU
4219820Sjeff  General Public License (GPL) Version 2, available at
5219820Sjeff  <http://www.fsf.org/copyleft/gpl.html>, or the OpenIB.org BSD
6219820Sjeff  license, available in the LICENSE.TXT file accompanying this
7219820Sjeff  software.  These details are also available at
8219820Sjeff  <http://openib.org/license.html>.
9219820Sjeff
10219820Sjeff  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
11219820Sjeff  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
12219820Sjeff  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13219820Sjeff  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
14219820Sjeff  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
15219820Sjeff  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
16219820Sjeff  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17219820Sjeff  SOFTWARE.
18219820Sjeff
19219820Sjeff  Copyright (c) 2004 Topspin Communications.  All rights reserved.
20219820Sjeff  Copyright (c) 2005-2006 Mellanox Technologies Ltd.  All rights reserved.
21219820Sjeff
22219820Sjeff  $Id$
23219820Sjeff*/
24219820Sjeff
25219820Sjeff/*
26219820Sjeff * system includes
27219820Sjeff */
28219820Sjeff#if HAVE_CONFIG_H
29219820Sjeff#  include <config.h>
30219820Sjeff#endif							/* HAVE_CONFIG_H */
31219820Sjeff
32219820Sjeff#ifdef SOLARIS_BUILD
33219820Sjeff/* Our prototypes for ioctl, get*name and accept do not strictly
34219820Sjeff   match the headers - we use the following lines to move the header
35219820Sjeff   versions 'out of the way' temporarily. */
36219820Sjeff#define ioctl __real_ioctl
37219820Sjeff#define getsockname __real_getsockname
38219820Sjeff#define getpeername __real_getpeername
39219820Sjeff#define accept __real_accept
40219820Sjeff#define FASYNC 0
41219820Sjeff#include <libgen.h>
42219820Sjeff#endif
43219820Sjeff#include <unistd.h>
44219820Sjeff#include <errno.h>
45219820Sjeff#include <stdio.h>
46219820Sjeff#include <stdlib.h>
47219820Sjeff#include <string.h>
48219820Sjeff#define __USE_GNU
49219820Sjeff#define _GNU_SOURCE				/* define RTLD_NEXT */
50219820Sjeff#include <dlfcn.h>
51219820Sjeff#include <sys/types.h>
52219820Sjeff#include <sys/socket.h>
53219820Sjeff#include <netinet/tcp.h>
54219820Sjeff#include <arpa/inet.h>
55219820Sjeff#include <netinet/in.h>
56219820Sjeff#include <stdarg.h>
57219820Sjeff#include <sys/time.h>
58219820Sjeff#include <sys/resource.h>
59219820Sjeff#include <sys/stat.h>
60219820Sjeff#include <fcntl.h>
61219820Sjeff#include <signal.h>
62219820Sjeff#include <sys/poll.h>
63219820Sjeff#ifdef __linux__
64219820Sjeff#include <sys/epoll.h>
65219820Sjeff#endif
66219820Sjeff
67219820Sjeff#ifdef SOLARIS_BUILD
68219820Sjeff/* We're done protecting ourselves from the header prototypes */
69219820Sjeff#undef ioctl
70219820Sjeff#undef getsockname
71219820Sjeff#undef getpeername
72219820Sjeff#undef accept
73219820Sjeff#endif
74219820Sjeff
75219820Sjeff/*
76219820Sjeff * SDP specific includes
77219820Sjeff */
78219820Sjeff#include "libsdp.h"
79219820Sjeff
80219820Sjeff/* We can not use sizeof(sockaddr_in6) as the extra scope_id field is not a must have */
81219820Sjeff#define IPV6_ADDR_IN_MIN_LEN 24
82219820Sjeff
83219820Sjeff/* setsockopt() level and optname declarations */
84219820Sjeff#define SOL_SDP		1025
85219820Sjeff#define SDP_UNBIND	259			/* Unbind socket */
86219820Sjeff
87219820Sjeff/* Solaris has two entry socket creation functions */
88219820Sjeff#define SOCKET_SEMANTIC_DEFAULT 0
89219820Sjeff#define SOCKET_SEMANTIC_XNET 1
90219820Sjeff
91219820Sjeff/* HACK: filter ioctl errors for FIONREAD */
92219820Sjeff#define FIONREAD 0x541B
93219820Sjeff
94219820Sjeffvoid __attribute__ ((constructor)) __sdp_init(void);
95219820Sjeffvoid __attribute__ ((destructor)) __sdp_fini(void);
96219820Sjeff
97219820Sjeff/* --------------------------------------------------------------------- */
98219820Sjeff/* library type definitions.                                             */
99219820Sjeff/* --------------------------------------------------------------------- */
100219820Sjeff
101219820Sjefftypedef int (*ioctl_func_t) (int fd,
102219820Sjeff							 int request,
103219820Sjeff							 void *arg0,
104219820Sjeff							 void *arg1,
105219820Sjeff							 void *arg2,
106219820Sjeff							 void *arg3,
107219820Sjeff							 void *arg4, void *arg5, void *arg6, void *arg7);
108219820Sjeff
109219820Sjefftypedef int (*fcntl_func_t) (int fd, int cmd, ...);
110219820Sjeff
111219820Sjefftypedef int (*socket_func_t) (int domain, int type, int protocol);
112219820Sjeff
113219820Sjefftypedef int (*setsockopt_func_t) (int s,
114219820Sjeff								  int level,
115219820Sjeff								  int optname,
116219820Sjeff								  const void *optval, socklen_t optlen);
117219820Sjeff
118219820Sjefftypedef int (*connect_func_t) (int sockfd,
119219820Sjeff							   const struct sockaddr * serv_addr,
120219820Sjeff							   socklen_t addrlen);
121219820Sjeff
122219820Sjefftypedef int (*listen_func_t) (int s, int backlog);
123219820Sjeff
124219820Sjefftypedef int (*bind_func_t) (int sockfd,
125219820Sjeff							const struct sockaddr * my_addr, socklen_t addrlen);
126219820Sjeff
127219820Sjefftypedef int (*close_func_t) (int fd);
128219820Sjeff
129219820Sjefftypedef int (*dup_func_t) (int fd);
130219820Sjeff
131219820Sjefftypedef int (*dup2_func_t) (int oldfd, int newfd);
132219820Sjeff
133219820Sjefftypedef int (*getsockname_func_t) (int fd,
134219820Sjeff								   struct sockaddr * name, socklen_t * namelen);
135219820Sjeff
136219820Sjefftypedef int (*getpeername_func_t) (int fd,
137219820Sjeff								   struct sockaddr * name, socklen_t * namelen);
138219820Sjeff
139219820Sjefftypedef int (*accept_func_t) (int fd,
140219820Sjeff							  struct sockaddr * addr, socklen_t * addrlen);
141219820Sjeff
142219820Sjefftypedef int (*select_func_t) (int n,
143219820Sjeff							  fd_set * readfds,
144219820Sjeff							  fd_set * writefds,
145219820Sjeff							  fd_set * exceptfds, struct timeval * timeout);
146219820Sjeff
147219820Sjefftypedef int (*pselect_func_t) (int n,
148219820Sjeff							   fd_set * readfds,
149219820Sjeff							   fd_set * writefds,
150219820Sjeff							   fd_set * exceptfds,
151219820Sjeff							   const struct timespec * timeout,
152219820Sjeff							   const sigset_t * sigmask);
153219820Sjeff
154219820Sjefftypedef int (*poll_func_t) (struct pollfd * ufds,
155219820Sjeff							unsigned long int nfds, int timeout);
156219820Sjeff
157219820Sjeff#ifdef __linux__
158219820Sjefftypedef int (*epoll_create_func_t) (int size);
159219820Sjeff
160219820Sjefftypedef int (*epoll_ctl_func_t) (int epfd,
161219820Sjeff								 int op, int fd, struct epoll_event * event);
162219820Sjeff
163219820Sjefftypedef int (*epoll_wait_func_t) (int epfd,
164219820Sjeff								  struct epoll_event * events,
165219820Sjeff								  int maxevents, int timeout);
166219820Sjeff
167219820Sjefftypedef int (*epoll_pwait_func_t) (int epfd,
168219820Sjeff								   struct epoll_event * events,
169219820Sjeff								   int maxevents,
170219820Sjeff								   int timeout, const sigset_t * sigmask);
171219820Sjeff#endif
172219820Sjeff
173219820Sjeff
174219820Sjeffstruct socket_lib_funcs {
175219820Sjeff	ioctl_func_t ioctl;
176219820Sjeff	fcntl_func_t fcntl;
177219820Sjeff	socket_func_t socket;
178219820Sjeff	setsockopt_func_t setsockopt;
179219820Sjeff	connect_func_t connect;
180219820Sjeff	listen_func_t listen;
181219820Sjeff	bind_func_t bind;
182219820Sjeff	close_func_t close;
183219820Sjeff	dup_func_t dup;
184219820Sjeff	dup2_func_t dup2;
185219820Sjeff	getpeername_func_t getpeername;
186219820Sjeff	getsockname_func_t getsockname;
187219820Sjeff	accept_func_t accept;
188219820Sjeff	select_func_t select;
189219820Sjeff	pselect_func_t pselect;
190219820Sjeff	poll_func_t poll;
191219820Sjeff#ifdef __linux__
192219820Sjeff	epoll_create_func_t epoll_create;
193219820Sjeff	epoll_ctl_func_t epoll_ctl;
194219820Sjeff	epoll_wait_func_t epoll_wait;
195219820Sjeff	epoll_pwait_func_t epoll_pwait;
196219820Sjeff#endif
197219820Sjeff};								/* socket_lib_funcs */
198219820Sjeff
199219820Sjeff#ifdef SOLARIS_BUILD
200219820Sjeff/* Solaris has another interface to socket functions prefixed with __xnet_ */
201219820Sjeffstruct socket_lib_xnet_funcs {
202219820Sjeff	socket_func_t socket;
203219820Sjeff	connect_func_t connect;
204219820Sjeff	listen_func_t listen;
205219820Sjeff	bind_func_t bind;
206219820Sjeff};
207219820Sjeff#endif
208219820Sjeff
209219820Sjeffstatic int simple_sdp_library;
210219820Sjeffstatic int max_file_descriptors;
211219820Sjeffstatic int dev_null_fd;
212219820Sjeffvolatile static int init_status = 0;	/* 0: idle, 1:during, 2:ready */
213219820Sjeff
214219820Sjeff/* --------------------------------------------------------------------- */
215219820Sjeff/* library static and global variables                                   */
216219820Sjeff/* --------------------------------------------------------------------- */
217219820Sjeff
218219820Sjeff/* glibc provides these symbols - for Solaris builds we fake them
219219820Sjeff * until _init is called, at which point we quiz libdl.. */
220219820Sjeff#ifdef SOLARIS_BUILD
221219820Sjeffchar *program_invocation_name = "[progname]", *program_invocation_short_name =
222219820Sjeff	"[short_progname]";
223219820Sjeff#else
224219820Sjeffextern char *program_invocation_name, *program_invocation_short_name;
225219820Sjeff#endif
226219820Sjeff
227219820Sjeff#ifdef RTLD_NEXT
228219820Sjeffstatic void *__libc_dl_handle = RTLD_NEXT;
229219820Sjeff#else
230219820Sjeffstatic void *__libc_dl_handle;
231219820Sjeff#endif
232219820Sjeff
233219820Sjeff/* extra fd attributes we need for our algorithms */
234219820Sjeffstruct sdp_extra_fd_attributes {
235219820Sjeff	int shadow_fd;				/* file descriptor of shadow sdp socket    */
236219820Sjeff	short last_accept_was_tcp;	/* used by accept to alternate tcp and sdp */
237219820Sjeff	short is_sdp;				/* 1 if the fd represents an sdp socket    */
238219820Sjeff};								/* sdp_extra_fd_attributes */
239219820Sjeff
240219820Sjeff/* stores the extra attributes struct by fd */
241219820Sjeffstatic struct sdp_extra_fd_attributes *libsdp_fd_attributes;
242219820Sjeff
243219820Sjeffstatic struct socket_lib_funcs _socket_funcs = {
244219820Sjeff	.socket = NULL,
245219820Sjeff	/* Automatically sets all other elements to NULL */
246219820Sjeff};								/* _socket_funcs */
247219820Sjeff
248219820Sjeff#ifdef SOLARIS_BUILD
249219820Sjeffstatic struct socket_lib_xnet_funcs _socket_xnet_funcs = {
250219820Sjeff	.socket = NULL,
251219820Sjeff	/* Automatically sets all other elements to NULL */
252219820Sjeff};
253219820Sjeff#endif
254219820Sjeff
255219820Sjeff/* --------------------------------------------------------------------- */
256219820Sjeff/* Prototypes                                                            */
257219820Sjeff/* --------------------------------------------------------------------- */
258219820Sjeffvoid __sdp_init(void);
259219820Sjeff
260219820Sjeff/* --------------------------------------------------------------------- */
261219820Sjeff/*                                                                       */
262219820Sjeff/* local static functions.                                               */
263219820Sjeff/*                                                                       */
264219820Sjeff/* --------------------------------------------------------------------- */
265219820Sjeff
266219820Sjeff/* ========================================================================= */
267219820Sjeff/*..init_extra_attribute -- initialize the set of extra attributes for a fd */
268219820Sjeffstatic void init_extra_attribute(int fd)
269219820Sjeff{
270219820Sjeff	if ((0 <= fd) && (max_file_descriptors > fd)) {
271219820Sjeff		libsdp_fd_attributes[fd].shadow_fd = -1;
272219820Sjeff		libsdp_fd_attributes[fd].is_sdp = 0;
273219820Sjeff		libsdp_fd_attributes[fd].last_accept_was_tcp = -1;
274219820Sjeff	}
275219820Sjeff}
276219820Sjeff
277219820Sjeffstatic inline int is_valid_fd(int fd)
278219820Sjeff{
279219820Sjeff	return (0 <= fd) && (fd < max_file_descriptors);
280219820Sjeff}
281219820Sjeff
282219820Sjeff/* ========================================================================= */
283219820Sjeff/*..get_shadow_fd_by_fd -- given an fd return its shadow fd if exists        */
284219820Sjeffstatic inline int get_shadow_fd_by_fd(int fd)
285219820Sjeff{
286219820Sjeff	if (is_valid_fd(fd))
287219820Sjeff		return libsdp_fd_attributes[fd].shadow_fd;
288219820Sjeff	else
289219820Sjeff		return -1;
290219820Sjeff}
291219820Sjeff
292219820Sjeff/* ========================================================================= */
293219820Sjeff/*..set_shadow_for_fd --                                                     */
294219820Sjeffstatic inline void set_shadow_for_fd(int fd, int shadow_fd)
295219820Sjeff{
296219820Sjeff	if (is_valid_fd(fd))
297219820Sjeff		libsdp_fd_attributes[fd].shadow_fd = shadow_fd;
298219820Sjeff}
299219820Sjeff
300219820Sjeff/* ========================================================================= */
301219820Sjeff/*..set_is_sdp_socket --                                                     */
302219820Sjeffstatic inline void set_is_sdp_socket(int fd, short is_sdp)
303219820Sjeff{
304219820Sjeff	if (is_valid_fd(fd))
305219820Sjeff		libsdp_fd_attributes[fd].is_sdp = is_sdp;
306219820Sjeff}
307219820Sjeff
308219820Sjeff/* ========================================================================= */
309219820Sjeff/*..get_is_sdp_socket -- given an fd return 1 if it is an SDP socket         */
310219820Sjeffstatic inline int get_is_sdp_socket(int fd)
311219820Sjeff{
312219820Sjeff	if (is_valid_fd(fd))
313219820Sjeff		return libsdp_fd_attributes[fd].is_sdp;
314219820Sjeff	else
315219820Sjeff		return 0;
316219820Sjeff}
317219820Sjeff
318219820Sjeff/* ========================================================================= */
319219820Sjeff/*..last_accept_was_tcp -- given an fd return 1 if last accept was tcp       */
320219820Sjeffstatic inline int last_accept_was_tcp(int fd)
321219820Sjeff{
322219820Sjeff	if (is_valid_fd(fd))
323219820Sjeff		return libsdp_fd_attributes[fd].last_accept_was_tcp;
324219820Sjeff	else
325219820Sjeff		return 0;
326219820Sjeff}
327219820Sjeff
328219820Sjeff/* ========================================================================= */
329219820Sjeff/*..set_last_accept -- given an fd set last accept was tcp                   */
330219820Sjeffstatic inline void set_last_accept(int fd, int was_tcp)
331219820Sjeff{
332219820Sjeff	if (is_valid_fd(fd))
333219820Sjeff		libsdp_fd_attributes[fd].last_accept_was_tcp = was_tcp;
334219820Sjeff}
335219820Sjeff
336219820Sjeff/* ========================================================================= */
337219820Sjeff/*..cleanup_shadow -- an error occured on an SDP socket, cleanup             */
338219820Sjeffstatic int cleanup_shadow(int fd)
339219820Sjeff{
340219820Sjeff	int shadow_fd = get_shadow_fd_by_fd(fd);
341219820Sjeff
342219820Sjeff	if (shadow_fd == -1)
343219820Sjeff		return 0;
344219820Sjeff	libsdp_fd_attributes[fd].shadow_fd = -1;
345219820Sjeff	libsdp_fd_attributes[fd].last_accept_was_tcp = 0;
346219820Sjeff	return (_socket_funcs.close(shadow_fd));
347219820Sjeff}								/* cleanup_shadow */
348219820Sjeff
349219820Sjeff/* ========================================================================= */
350219820Sjeff/*..replace_fd_with_its_shadow -- perform all required for such promotion    */
351219820Sjeffstatic int replace_fd_with_its_shadow(int fd)
352219820Sjeff{
353219820Sjeff	int shadow_fd = libsdp_fd_attributes[fd].shadow_fd;
354219820Sjeff
355219820Sjeff	if (shadow_fd == -1) {
356219820Sjeff		__sdp_log(9, "Error replace_fd_with_its_shadow: no shadow for fd:%d\n",
357219820Sjeff				  fd);
358219820Sjeff		return EINVAL;
359219820Sjeff	}
360219820Sjeff
361219820Sjeff	/* copy the attributes of the shadow before we clean them up */
362219820Sjeff	libsdp_fd_attributes[fd] = libsdp_fd_attributes[shadow_fd];
363219820Sjeff	libsdp_fd_attributes[fd].shadow_fd = -1;
364219820Sjeff	if (_socket_funcs.dup2(shadow_fd, fd) < 0) {
365219820Sjeff		init_extra_attribute(fd);
366219820Sjeff		_socket_funcs.close(shadow_fd);
367219820Sjeff		return EINVAL;
368219820Sjeff	}
369219820Sjeff	_socket_funcs.close(shadow_fd);
370219820Sjeff	return 0;
371219820Sjeff}
372219820Sjeff
373219820Sjeffstatic sa_family_t get_sdp_domain(int domain)
374219820Sjeff{
375219820Sjeff	if (AF_INET_SDP == domain || AF_INET6_SDP == domain)
376219820Sjeff		return domain;
377219820Sjeff
378219820Sjeff	if (AF_INET == domain)
379219820Sjeff		return AF_INET_SDP;
380219820Sjeff	else if (AF_INET6 == domain)
381219820Sjeff		return AF_INET6_SDP;
382219820Sjeff
383219820Sjeff	__sdp_log(9, "Error %s: unknown TCP domain: %d\n", __func__, domain);
384219820Sjeff
385219820Sjeff	return -1;
386219820Sjeff}
387219820Sjeff
388219820Sjeffstatic int get_sock_domain(int sd)
389219820Sjeff{
390219820Sjeff	struct sockaddr_storage tmp_sin;
391219820Sjeff	socklen_t tmp_sinlen = sizeof(tmp_sin);
392219820Sjeff
393219820Sjeff	if (_socket_funcs.getsockname(sd, (struct sockaddr *) &tmp_sin, &tmp_sinlen) < 0) {
394219820Sjeff		__sdp_log(9, "Error %s: getsockname return <%d> for socket\n", __func__, errno);
395219820Sjeff		return -1;
396219820Sjeff	}
397219820Sjeff
398219820Sjeff	return ((struct sockaddr *)&tmp_sin)->sa_family;
399219820Sjeff}
400219820Sjeff
401219820Sjeff/* ========================================================================= */
402219820Sjeff/*..is_filtered_unsuported_sockopt -- return 1 if to filter sockopt failure  */
403219820Sjeffstatic inline int is_filtered_unsuported_sockopt(int level, int optname)
404219820Sjeff{
405219820Sjeff	/*
406219820Sjeff	 * TODO: until we know exactly which unsupported opts are really
407219820Sjeff	 * a don't care we always pass the error
408219820Sjeff	 */
409219820Sjeff	return 0;
410219820Sjeff#if 0
411219820Sjeff	/* these are the SOL_TCP OPTS we should consider filterring */
412219820Sjeff	TCP_NODELAY 1				/* Don't delay send to coalesce packets  */
413219820Sjeff		TCP_MAXSEG 2			/* Set maximum segment size  */
414219820Sjeff		TCP_CORK 3				/* Control sending of partial frames  */
415219820Sjeff		TCP_KEEPIDLE 4			/* Start keeplives after this period */
416219820Sjeff		TCP_KEEPINTVL 5			/* Interval between keepalives */
417219820Sjeff		TCP_KEEPCNT 6			/* Number of keepalives before death */
418219820Sjeff		TCP_SYNCNT 7			/* Number of SYN retransmits */
419219820Sjeff		TCP_LINGER2 8			/* Life time of orphaned FIN-WAIT-2 state */
420219820Sjeff		TCP_DEFER_ACCEPT 9		/* Wake up listener only when data arrive */
421219820Sjeff		TCP_WINDOW_CLAMP 10		/* Bound advertised window */
422219820Sjeff		TCP_INFO 11				/* Information about this connection. */
423219820Sjeff		TCP_QUICKACK 12			/* Bock/reenable quick ACKs.  */
424219820Sjeff#endif
425219820Sjeff}
426219820Sjeff
427219820Sjeff/* ========================================================================= */
428219820Sjeff/*..is_invalid_addr -- return 1 if given pointer is not valid                */
429219820Sjeff/* NOTE: invalidation of the size is going to happen during actual call      */
430219820Sjeffstatic inline int is_invalid_addr(const void *p)
431219820Sjeff{
432219820Sjeff	/* HACK: on some systems we can not write to check for pointer validity */
433219820Sjeff	size_t ret = fcntl(dev_null_fd, F_GETLK, p);
434219820Sjeff
435219820Sjeff	ret = (errno == EFAULT);
436219820Sjeff	errno = 0;
437219820Sjeff	return ret;
438219820Sjeff}
439219820Sjeff
440219820Sjeff/* ========================================================================= */
441219820Sjeff/*..get_addr_str -- fill in the given buffer with addr str or return 1       */
442219820Sjeffstatic int get_addr_str(const struct sockaddr *addr, char *buf, size_t len)
443219820Sjeff{
444219820Sjeff	const struct sockaddr_in *sin = (struct sockaddr_in *) addr;
445219820Sjeff	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) addr;
446219820Sjeff	char const *conv_res;
447219820Sjeff
448219820Sjeff	if (sin->sin_family == AF_INET) {
449219820Sjeff		conv_res = inet_ntop(AF_INET, (void *) &(sin->sin_addr), buf, len);
450219820Sjeff	} else if (sin6->sin6_family == AF_INET6) {
451219820Sjeff		conv_res = inet_ntop(AF_INET6, (void *) &sin6->sin6_addr, buf, len);
452219820Sjeff	} else {
453219820Sjeff		strncpy(buf, "unknown address family", len);
454219820Sjeff		conv_res = (char *) 1;
455219820Sjeff	}
456219820Sjeff	return conv_res == NULL;
457219820Sjeff}
458219820Sjeff
459219820Sjeff/* --------------------------------------------------------------------- */
460219820Sjeff/*                                                                       */
461219820Sjeff/* Socket library function overrides.                                    */
462219820Sjeff/*                                                                       */
463219820Sjeff/* --------------------------------------------------------------------- */
464219820Sjeff
465219820Sjeff/* ========================================================================= */
466219820Sjeff/*..ioctl -- replacement ioctl call. */
467219820Sjeffint
468219820Sjeffioctl(int fd,
469219820Sjeff	  int request,
470219820Sjeff	  void *arg0,
471219820Sjeff	  void *arg1,
472219820Sjeff	  void *arg2, void *arg3, void *arg4, void *arg5, void *arg6, void *arg7)
473219820Sjeff{
474219820Sjeff	int shadow_fd;
475219820Sjeff	int sret = 0;
476219820Sjeff	int ret = 0;
477219820Sjeff
478219820Sjeff	if (init_status == 0)
479219820Sjeff		__sdp_init();
480219820Sjeff
481219820Sjeff	if (NULL == _socket_funcs.ioctl) {
482219820Sjeff		__sdp_log(9, "Error ioctl: no implementation for ioctl found\n");
483219820Sjeff		return -1;
484219820Sjeff	}
485219820Sjeff
486219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
487219820Sjeff
488219820Sjeff	__sdp_log(2, "IOCTL: <%s:%d:%d> request <%d>\n",
489219820Sjeff			  program_invocation_short_name, fd, shadow_fd, request);
490219820Sjeff
491219820Sjeff	ret = _socket_funcs.ioctl(fd, request,
492219820Sjeff							  arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
493219820Sjeff
494219820Sjeff	/* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */
495219820Sjeff	if ((ret < 0) && get_is_sdp_socket(fd) && (request == FIONREAD)) {
496219820Sjeff		__sdp_log(8, "Warning ioctl: "
497219820Sjeff				  "Ignoring FIONREAD error for SDP socket.\n");
498219820Sjeff		ret = 0;
499219820Sjeff	}
500219820Sjeff
501219820Sjeff	/* if shadow and no error on tcp */
502219820Sjeff	if ((ret >= 0) && (-1 != shadow_fd)) {
503219820Sjeff		sret = _socket_funcs.ioctl(shadow_fd, request,
504219820Sjeff								   arg0, arg1, arg2, arg3, arg4, arg5, arg6,
505219820Sjeff								   arg7);
506219820Sjeff		/* HACK: avoid failing on FIONREAD error as SDP does not support it at the moment */
507219820Sjeff		if ((sret < 0) && (request == FIONREAD)) {
508219820Sjeff			__sdp_log(8, "Warning ioctl: "
509219820Sjeff					  "Ignoring FIONREAD error for shadow SDP socket.\n");
510219820Sjeff			sret = 0;
511219820Sjeff		}
512219820Sjeff
513219820Sjeff		if (sret < 0) {
514219820Sjeff			__sdp_log(9, "Error ioctl: "
515219820Sjeff					  "<%d> calling ioctl for SDP socket, closing it.\n",
516219820Sjeff					  errno);
517219820Sjeff			cleanup_shadow(fd);
518219820Sjeff		}
519219820Sjeff	}
520219820Sjeff
521219820Sjeff	__sdp_log(2, "IOCTL: <%s:%d:%d> result <%d:%d>\n",
522219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret, sret);
523219820Sjeff
524219820Sjeff	return ret;
525219820Sjeff}								/* ioctl */
526219820Sjeff
527219820Sjeff/* ========================================================================= */
528219820Sjeff/*..fcntl -- replacement fcntl call.                                         */
529219820Sjeffint fcntl(int fd, int cmd, ...)
530219820Sjeff{
531219820Sjeff	int shadow_fd;
532219820Sjeff	int sret = 0;
533219820Sjeff	int ret = 0;
534219820Sjeff
535219820Sjeff	void *arg;
536219820Sjeff	va_list ap;
537219820Sjeff
538219820Sjeff	va_start(ap, cmd);
539219820Sjeff	arg = va_arg(ap, void *);
540219820Sjeff	va_end(ap);
541219820Sjeff
542219820Sjeff
543219820Sjeff	if (init_status == 0)
544219820Sjeff		__sdp_init();
545219820Sjeff
546219820Sjeff	if (NULL == _socket_funcs.fcntl) {
547219820Sjeff		__sdp_log(9, "Error fcntl: no implementation for fcntl found\n");
548219820Sjeff		return -1;
549219820Sjeff	}
550219820Sjeff
551219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
552219820Sjeff
553219820Sjeff	__sdp_log(2, "FCNTL: <%s:%d:%d> command <%d> argument <%p>\n",
554219820Sjeff			  program_invocation_short_name, fd, shadow_fd, cmd, arg);
555219820Sjeff
556219820Sjeff	ret = _socket_funcs.fcntl(fd, cmd, arg);
557219820Sjeff	if ((ret >= 0) && (-1 != shadow_fd)) {
558219820Sjeff		sret = _socket_funcs.fcntl(shadow_fd, cmd, arg);
559219820Sjeff		if (sret < 0) {
560219820Sjeff			__sdp_log(9, "Error fcntl:"
561219820Sjeff					  " <%d> calling fcntl(%d, %d, %p) for SDP socket. Closing it.\n",
562219820Sjeff					  shadow_fd, cmd, arg, errno);
563219820Sjeff			cleanup_shadow(fd);
564219820Sjeff		}
565219820Sjeff	}
566219820Sjeff
567219820Sjeff	__sdp_log(2, "FCNTL: <%s:%d:%d> result <%d:%d>\n",
568219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret, sret);
569219820Sjeff
570219820Sjeff	return ret;
571219820Sjeff}								/* fcntl */
572219820Sjeff
573219820Sjeff/* ========================================================================= */
574219820Sjeff/*..setsockopt -- replacement setsockopt call.                               */
575219820Sjeffint
576219820Sjeffsetsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
577219820Sjeff{
578219820Sjeff	int shadow_fd;
579219820Sjeff	int sret = 0;
580219820Sjeff	int ret = 0;
581219820Sjeff
582219820Sjeff	if (init_status == 0)
583219820Sjeff		__sdp_init();
584219820Sjeff
585219820Sjeff	if (NULL == _socket_funcs.setsockopt) {
586219820Sjeff		__sdp_log(9, "Error setsockopt:"
587219820Sjeff				  " no implementation for setsockopt found\n");
588219820Sjeff		return -1;
589219820Sjeff	}
590219820Sjeff
591219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
592219820Sjeff
593219820Sjeff	__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> level <%d> name <%d>\n",
594219820Sjeff			  program_invocation_short_name, fd, shadow_fd, level, optname);
595219820Sjeff
596219820Sjeff	if (level == SOL_SOCKET && optname == SO_KEEPALIVE && get_is_sdp_socket(fd)) {
597219820Sjeff		level = AF_INET_SDP;
598219820Sjeff		__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n",
599219820Sjeff				  program_invocation_short_name, fd, shadow_fd, level);
600219820Sjeff	}
601219820Sjeff
602219820Sjeff	ret = _socket_funcs.setsockopt(fd, level, optname, optval, optlen);
603219820Sjeff	if ((ret >= 0) && (shadow_fd != -1)) {
604219820Sjeff		if (level == SOL_SOCKET && optname == SO_KEEPALIVE &&
605219820Sjeff			get_is_sdp_socket(shadow_fd)) {
606219820Sjeff			level = AF_INET_SDP;
607219820Sjeff			__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> substitute level %d\n",
608219820Sjeff					  program_invocation_short_name, fd, shadow_fd, level);
609219820Sjeff		}
610219820Sjeff
611219820Sjeff		sret = _socket_funcs.setsockopt(shadow_fd, level, optname, optval, optlen);
612219820Sjeff		if (sret < 0) {
613219820Sjeff			__sdp_log(8, "Warning sockopts:"
614219820Sjeff					  " ignoring error on shadow SDP socket fd:<%d>\n", fd);
615219820Sjeff			/*
616219820Sjeff			 * HACK: we should allow some errors as some sock opts are unsupported
617219820Sjeff			 * __sdp_log(9, "Error %d calling setsockopt for SDP socket, closing\n", errno);
618219820Sjeff			 * cleanup_shadow(fd);
619219820Sjeff			 */
620219820Sjeff		}
621219820Sjeff	}
622219820Sjeff
623219820Sjeff	/* Due to SDP limited implmentation of sockopts we ignore some errors */
624219820Sjeff	if ((ret < 0) && get_is_sdp_socket(fd) &&
625219820Sjeff		is_filtered_unsuported_sockopt(level, optname)) {
626219820Sjeff		__sdp_log(8, "Warning sockopts: "
627219820Sjeff				  "ignoring error on non implemented sockopt on SDP socket"
628219820Sjeff				  " fd:<%d> level:<%d> opt:<%d>\n", fd, level, optval);
629219820Sjeff		ret = 0;
630219820Sjeff	}
631219820Sjeff
632219820Sjeff	__sdp_log(2, "SETSOCKOPT: <%s:%d:%d> result <%d:%d>\n",
633219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret, sret);
634219820Sjeff
635219820Sjeff	return ret;
636219820Sjeff}								/* setsockopt */
637219820Sjeff
638219820Sjeff/* ========================================================================= */
639219820Sjeff/*..socket -- replacement socket call.                                       */
640219820Sjeff
641219820Sjeffstatic inline int __create_socket_semantic(int domain,
642219820Sjeff										   int type,
643219820Sjeff										   int protocol, int semantics)
644219820Sjeff{
645219820Sjeff	return
646219820Sjeff#ifdef SOLARIS_BUILD
647219820Sjeff		(semantics == SOCKET_SEMANTIC_XNET) ?
648219820Sjeff		_socket_xnet_funcs.socket(domain, type, protocol) :
649219820Sjeff#endif
650219820Sjeff		_socket_funcs.socket(domain, type, protocol);
651219820Sjeff}
652219820Sjeff
653219820Sjeff/* Contains the main logic for creating shadow SDP sockets */
654219820Sjeffstatic int __create_socket(int domain, int type, int protocol, int semantics)
655219820Sjeff{
656219820Sjeff	int s = -1;
657219820Sjeff	int shadow_fd = -1;
658219820Sjeff	use_family_t family_by_prog;
659219820Sjeff	int sdp_domain;
660219820Sjeff
661219820Sjeff	if (init_status == 0)
662219820Sjeff		__sdp_init();
663219820Sjeff
664219820Sjeff	if (NULL == _socket_funcs.socket) {
665219820Sjeff		__sdp_log(9, "Error socket: no implementation for socket found\n");
666219820Sjeff		return -1;
667219820Sjeff	}
668219820Sjeff
669219820Sjeff	__sdp_log(2, "SOCKET: <%s> domain <%d> type <%d> protocol <%d>\n",
670219820Sjeff			  program_invocation_short_name, domain, type, protocol);
671219820Sjeff
672219820Sjeff	sdp_domain = get_sdp_domain(domain);
673219820Sjeff	if (sdp_domain < 0) {
674219820Sjeff		errno = EAFNOSUPPORT;
675219820Sjeff		s = -1;
676219820Sjeff		goto done;
677219820Sjeff	}
678219820Sjeff
679219820Sjeff	/* check to see if we can skip the shadow */
680219820Sjeff	if ((AF_INET == domain || AF_INET6 == domain) && (SOCK_STREAM == type))
681219820Sjeff		if (simple_sdp_library)
682219820Sjeff			family_by_prog = USE_SDP;
683219820Sjeff		else
684219820Sjeff			family_by_prog = __sdp_match_by_program();
685219820Sjeff	else if (AF_INET_SDP == domain || AF_INET6_SDP == domain)
686219820Sjeff		family_by_prog = USE_SDP;
687219820Sjeff	else
688219820Sjeff		family_by_prog = USE_TCP;
689219820Sjeff
690219820Sjeff	if (family_by_prog == USE_TCP) {
691219820Sjeff		__sdp_log(1, "SOCKET: making TCP only socket (no shadow)\n");
692219820Sjeff		s = __create_socket_semantic(domain, type, protocol, semantics);
693219820Sjeff		init_extra_attribute(s);
694219820Sjeff		set_is_sdp_socket(s, 0);
695219820Sjeff		goto done;
696219820Sjeff	}
697219820Sjeff
698219820Sjeff	if (family_by_prog == USE_SDP) {
699219820Sjeff		/* HACK: convert the protocol if IPPROTO_IP */
700219820Sjeff		if (protocol == 0)
701219820Sjeff			protocol = IPPROTO_TCP;
702219820Sjeff
703219820Sjeff		__sdp_log(1, "SOCKET: making SDP socket type:%d proto:%d\n",
704219820Sjeff				  type, protocol);
705219820Sjeff		s = __create_socket_semantic(sdp_domain, type, protocol, semantics);
706219820Sjeff		init_extra_attribute(s);
707219820Sjeff		set_is_sdp_socket(s, 1);
708219820Sjeff		goto done;
709219820Sjeff	}
710219820Sjeff
711219820Sjeff	/* HACK: if we fail creating the TCP socket should we abort ? */
712219820Sjeff	__sdp_log(1, "SOCKET: making TCP socket\n");
713219820Sjeff	s = __create_socket_semantic(domain, type, protocol, semantics);
714219820Sjeff	init_extra_attribute(s);
715219820Sjeff	set_is_sdp_socket(s, 0);
716219820Sjeff	if (is_valid_fd(s)) {
717219820Sjeff		if (((AF_INET == domain) || (AF_INET6 == domain)) &&
718219820Sjeff			(SOCK_STREAM == type)) {
719219820Sjeff
720219820Sjeff			if (protocol == 0)
721219820Sjeff				protocol = IPPROTO_TCP;
722219820Sjeff			__sdp_log(1, "SOCKET: making SDP shadow socket type:%d proto:%d\n",
723219820Sjeff					  type, protocol);
724219820Sjeff			shadow_fd =
725219820Sjeff				__create_socket_semantic(sdp_domain, type, protocol,
726219820Sjeff										 semantics);
727219820Sjeff			if (is_valid_fd(shadow_fd)) {
728219820Sjeff				init_extra_attribute(shadow_fd);
729219820Sjeff				if (libsdp_fd_attributes[s].shadow_fd != -1) {
730219820Sjeff					__sdp_log(8, "Warning socket: "
731219820Sjeff							  "overriding existing shadow fd:%d for fd:%d\n",
732219820Sjeff							  libsdp_fd_attributes[s].shadow_fd, s);
733219820Sjeff				}
734219820Sjeff				set_is_sdp_socket(shadow_fd, 1);
735219820Sjeff				set_shadow_for_fd(s, shadow_fd);
736219820Sjeff			} else {
737219820Sjeff				__sdp_log(9,
738219820Sjeff						  "Error socket: <%d> calling socket for SDP socket\n",
739219820Sjeff						  errno);
740219820Sjeff				/* fail if we did not make the SDP socket */
741219820Sjeff				__sdp_log(1, "SOCKET: closing TCP socket:<%d>\n", s);
742219820Sjeff				_socket_funcs.close(s);
743219820Sjeff				s = -1;
744219820Sjeff			}
745219820Sjeff		}
746219820Sjeff	} else {
747219820Sjeff		__sdp_log(9, "Error socket: "
748219820Sjeff				  "ignoring SDP socket since TCP fd:%d out of range\n", s);
749219820Sjeff	}
750219820Sjeff
751219820Sjeffdone:
752219820Sjeff	__sdp_log(2, "SOCKET: <%s:%d:%d>\n",
753219820Sjeff			  program_invocation_short_name, s, shadow_fd);
754219820Sjeff
755219820Sjeff	return s;
756219820Sjeff}								/* socket */
757219820Sjeff
758219820Sjeffint socket(int domain, int type, int protocol)
759219820Sjeff{
760219820Sjeff	return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_DEFAULT);
761219820Sjeff}
762219820Sjeff
763219820Sjeff#ifdef SOLARIS_BUILD
764219820Sjeffint __xnet_socket(int domain, int type, int protocol)
765219820Sjeff{
766219820Sjeff	return __create_socket(domain, type, protocol, SOCKET_SEMANTIC_XNET);
767219820Sjeff}
768219820Sjeff#endif
769219820Sjeff
770219820Sjeff/* ========================================================================= */
771219820Sjeff/*..get_fd_addr_port_num - obtain the port the fd is attached to             */
772219820Sjeffstatic int get_fd_addr_port_num(int sd)
773219820Sjeff{
774219820Sjeff	struct sockaddr_storage addr;
775219820Sjeff	int ret;
776219820Sjeff	const struct sockaddr_in *sin;
777219820Sjeff	socklen_t addrlen = sizeof(addr);
778219820Sjeff
779219820Sjeff	ret = _socket_funcs.getsockname(sd, (struct sockaddr *) &addr, &addrlen);
780219820Sjeff
781219820Sjeff	if (ret) {
782219820Sjeff		__sdp_log(9, "Error: in get_fd_addr_port_num - Failed to get getsockname\n");
783219820Sjeff		return -1;
784219820Sjeff	}
785219820Sjeff
786219820Sjeff	/* port num is in same location for IPv4 and IPv6 */
787219820Sjeff	sin = (const struct sockaddr_in *) &addr;
788219820Sjeff	return ntohs(sin->sin_port);
789219820Sjeff}
790219820Sjeff
791219820Sjeff/* ========================================================================= */
792219820Sjeff/*..set_addr_port_num - sets the port in the given address                   */
793219820Sjeffstatic int set_addr_port_num(const struct sockaddr *addr, int port)
794219820Sjeff{
795219820Sjeff	struct sockaddr_in *sin = (struct sockaddr_in *) addr;
796219820Sjeff
797219820Sjeff	/* port num is in same location for IPv4 and IPv6 */
798219820Sjeff	sin->sin_port = htons(port);
799219820Sjeff	return 0;
800219820Sjeff}
801219820Sjeff
802219820Sjeff/* ========================================================================= */
803219820Sjeff/*  perform a bind with the given socket semantics                           */
804219820Sjeffstatic inline int
805219820Sjeff__bind_semantics(int fd,
806219820Sjeff				 const struct sockaddr *my_addr,
807219820Sjeff				 socklen_t addrlen, int semantics)
808219820Sjeff{
809219820Sjeff	return
810219820Sjeff#ifdef SOLARIS_BUILD
811219820Sjeff		(semantics == SOCKET_SEMANTIC_XNET) ?
812219820Sjeff		_socket_xnet_funcs.bind(fd, my_addr, addrlen) :
813219820Sjeff#endif
814219820Sjeff		_socket_funcs.bind(fd, my_addr, addrlen);
815219820Sjeff}
816219820Sjeff
817219820Sjeff/* ========================================================================= */
818219820Sjeff/*..find_free_port - find same free port on both TCP and SDP                 */
819219820Sjeff#define MAX_BIND_ANY_PORT_TRIES 20000
820219820Sjeffstatic int
821219820Sjefffind_free_port(const struct sockaddr *sin_addr,
822219820Sjeff			   const socklen_t addrlen,
823219820Sjeff			   int orig_sd,
824219820Sjeff			   int *sdp_sd, int *tcp_sd, int semantics)
825219820Sjeff{
826219820Sjeff	static int tcp_turn = 1;
827219820Sjeff	int tmp_turn = tcp_turn;
828219820Sjeff	int num_of_loops = 0;
829219820Sjeff	int port = -1;
830219820Sjeff	int tmp_sd[2];
831219820Sjeff	unsigned int yes = 1;
832219820Sjeff	int ret;
833219820Sjeff	int domain, sdp_domain;
834219820Sjeff
835219820Sjeff	__sdp_log(2, "find_free_port: starting search for common free port\n");
836219820Sjeff
837219820Sjeff	/* need to obtain the address family from the fd */
838219820Sjeff	domain = get_sock_domain(orig_sd);
839219820Sjeff	if (domain == -1) {
840219820Sjeff		errno = EFAULT;
841219820Sjeff		goto done;
842219820Sjeff	}
843219820Sjeff
844219820Sjeff	sdp_domain = get_sdp_domain(domain);
845219820Sjeff	if (sdp_domain < 0) {
846219820Sjeff		errno = EFAULT;
847219820Sjeff		goto done;
848219820Sjeff	}
849219820Sjeff
850219820Sjeff	do {
851219820Sjeff		__sdp_log(1, "find_free_port: taking loop (%d)\n", ++num_of_loops);
852219820Sjeff
853219820Sjeff		__sdp_log(1, "find_free_port: creating the two sockets\n");
854219820Sjeff		tmp_sd[0] = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP);
855219820Sjeff		if (tmp_sd[0] < 0) {
856219820Sjeff			__sdp_log(8, "Warning find_free_port: creating first socket failed\n");
857219820Sjeff			goto done;
858219820Sjeff		}
859219820Sjeff
860219820Sjeff		_socket_funcs.setsockopt(tmp_sd[0], SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
861219820Sjeff
862219820Sjeff		tmp_sd[1] = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP);
863219820Sjeff		if (tmp_sd[1] < 0) {
864219820Sjeff			__sdp_log(8, "Warning find_free_port: creating second socket failed\n");
865219820Sjeff			_socket_funcs.close(tmp_sd[0]);
866219820Sjeff			goto done;
867219820Sjeff		}
868219820Sjeff
869219820Sjeff		_socket_funcs.setsockopt(tmp_sd[1], SOL_SOCKET, SO_REUSEADDR, &yes,
870219820Sjeff								 sizeof(yes));
871219820Sjeff
872219820Sjeff		__sdp_log(1, "find_free_port: binding first %s socket\n",
873219820Sjeff				  tmp_turn ? "tcp" : "sdp");
874219820Sjeff		ret = __bind_semantics(tmp_sd[tmp_turn], sin_addr, addrlen, semantics);
875219820Sjeff		if (ret < 0) {
876219820Sjeff			__sdp_log(8,
877219820Sjeff					  "Warning find_free_port: binding first socket failed:%s\n",
878219820Sjeff					  strerror(errno));
879219820Sjeff			_socket_funcs.close(tmp_sd[0]);
880219820Sjeff			_socket_funcs.close(tmp_sd[1]);
881219820Sjeff			goto done;
882219820Sjeff		}
883219820Sjeff
884219820Sjeff		__sdp_log(1, "find_free_port: listening on first socket\n");
885219820Sjeff		ret = _socket_funcs.listen(tmp_sd[tmp_turn], 5);
886219820Sjeff		if (ret < 0) {
887219820Sjeff			__sdp_log(8, "Warning find_free_port: listening on first socket failed:%s\n",
888219820Sjeff					strerror(errno));
889219820Sjeff			_socket_funcs.close(tmp_sd[0]);
890219820Sjeff			_socket_funcs.close(tmp_sd[1]);
891219820Sjeff			goto done;
892219820Sjeff		}
893219820Sjeff
894219820Sjeff		port = get_fd_addr_port_num(tmp_sd[tmp_turn]);
895219820Sjeff		if (port < 0) {
896219820Sjeff			__sdp_log(8, "Warning find_free_port: first socket port:%d < 0\n",
897219820Sjeff					port);
898219820Sjeff			_socket_funcs.close(tmp_sd[0]);
899219820Sjeff			_socket_funcs.close(tmp_sd[1]);
900219820Sjeff			goto done;
901219820Sjeff		}
902219820Sjeff		__sdp_log(1, "find_free_port: first socket port:%u\n", port);
903219820Sjeff
904219820Sjeff		set_addr_port_num(sin_addr, port);
905219820Sjeff
906219820Sjeff		__sdp_log(1, "find_free_port: binding second socket\n");
907219820Sjeff		ret = __bind_semantics(tmp_sd[1 - tmp_turn], sin_addr, addrlen, semantics);
908219820Sjeff		if (ret < 0) {
909219820Sjeff			/* bind() for sdp socket failed. It is acceptable only
910219820Sjeff			 * if the IP is not part of IB network. */
911219820Sjeff
912219820Sjeff			if (errno != EADDRINUSE) {
913219820Sjeff				__sdp_log(8, "Warning find_free_port: "
914219820Sjeff						  "binding second socket failed with %s\n",
915219820Sjeff						  strerror(errno));
916219820Sjeff				goto close_and_mark;
917219820Sjeff			} else {
918219820Sjeff				int err;
919219820Sjeff#ifdef __linux__
920219820Sjeff				socklen_t len = sizeof(int);
921219820Sjeff
922219820Sjeff				ret = getsockopt(tmp_sd[1 - tmp_turn], SOL_TCP,
923219820Sjeff								 SDP_LAST_BIND_ERR, &err, &len);
924219820Sjeff				if (-1 == ret) {
925219820Sjeff					__sdp_log(9, "Error %s:getsockopt: %s\n",
926219820Sjeff							  __func__, strerror(errno));
927219820Sjeff					goto close_and_mark;
928219820Sjeff				}
929219820Sjeff#else
930219820Sjeff				err = -errno;
931219820Sjeff#endif
932219820Sjeff				if (-ENOENT == err || -EADDRINUSE != err) {
933219820Sjeff					/* bind() failed due to either:
934219820Sjeff					 * 1. IP is ETH, not IB, so can't bind() to sdp socket.
935219820Sjeff					 * 2. real error.
936219820Sjeff					 * Continue only with TCP */
937219820Sjeff					goto close_and_mark;
938219820Sjeff				}
939219820Sjeff				__sdp_log(1, "find_free_port: %s port %u was busy\n",
940219820Sjeff					  1 - tmp_turn ? "tcp" : "sdp",
941219820Sjeff					  ntohs(((const struct sockaddr_in *)sin_addr)->sin_port));
942219820Sjeff			}
943219820Sjeff
944219820Sjeff			/* close the sockets - we will need new ones ... */
945219820Sjeff			__sdp_log(1,
946219820Sjeff					  "find_free_port: closing the two sockets before next loop\n");
947219820Sjeff			_socket_funcs.close(tmp_sd[0]);
948219820Sjeff			_socket_funcs.close(tmp_sd[1]);
949219820Sjeff
950219820Sjeff			port = -1;
951219820Sjeff			/* we always start with tcp so we keep the original setting for now */
952219820Sjeff			/* tmp_turn = 1 - tmp_turn; */
953219820Sjeff		}
954219820Sjeff
955219820Sjeff	} while ((port < 0) && (num_of_loops < MAX_BIND_ANY_PORT_TRIES));
956219820Sjeff
957219820Sjeffsetfds:
958219820Sjeff	tcp_turn = tmp_turn;
959219820Sjeff	*sdp_sd = tmp_sd[0];
960219820Sjeff	*tcp_sd = tmp_sd[1];
961219820Sjeff
962219820Sjeffdone:
963219820Sjeff	__sdp_log(2, "find_free_port: return port:<%d>\n", port);
964219820Sjeff	return port;
965219820Sjeff
966219820Sjeffclose_and_mark:
967219820Sjeff	_socket_funcs.close(tmp_sd[0]);
968219820Sjeff	tmp_sd[0] = -1;				/* mark with error */
969219820Sjeff	goto setfds;
970219820Sjeff
971219820Sjeff}
972219820Sjeff
973219820Sjeff/* ========================================================================= */
974219820Sjeff/*..check_legal_bind - check if given address is okay for both TCP and SDP   */
975219820Sjeffstatic int
976219820Sjeffcheck_legal_bind(const struct sockaddr *sin_addr,
977219820Sjeff				 const socklen_t addrlen,
978219820Sjeff				 int orig_sd,
979219820Sjeff				 int *sdp_sd, int *tcp_sd, int semantics)
980219820Sjeff{
981219820Sjeff	unsigned int yes = 1;
982219820Sjeff	int ret = -1;
983219820Sjeff	int sret = -1;
984219820Sjeff	int domain, sdp_domain;
985219820Sjeff
986219820Sjeff	/* need to obtain the address family from the fd */
987219820Sjeff	domain = get_sock_domain(orig_sd);
988219820Sjeff	if (domain == -1) {
989219820Sjeff		errno = EFAULT;
990219820Sjeff		ret = -1;
991219820Sjeff		goto done;
992219820Sjeff	}
993219820Sjeff
994219820Sjeff	sdp_domain = get_sdp_domain(domain);
995219820Sjeff	if (sdp_domain < 0) {
996219820Sjeff		errno = EFAULT;
997219820Sjeff		goto done;
998219820Sjeff	}
999219820Sjeff
1000219820Sjeff	__sdp_log(2, "check_legal_bind: binding two temporary sockets\n");
1001219820Sjeff	*sdp_sd = _socket_funcs.socket(sdp_domain, SOCK_STREAM, IPPROTO_TCP);
1002219820Sjeff	if (*sdp_sd < 0) {
1003219820Sjeff		__sdp_log(9, "Error check_legal_bind: " "creating SDP socket failed\n");
1004219820Sjeff		goto done;
1005219820Sjeff	}
1006219820Sjeff
1007219820Sjeff	__sdp_log(2, "check_legal_bind: reusing <%d> \n", *sdp_sd);
1008219820Sjeff	sret =
1009219820Sjeff		_socket_funcs.setsockopt(*sdp_sd, SOL_SOCKET, SO_REUSEADDR, &yes,
1010219820Sjeff								 sizeof(yes));
1011219820Sjeff	if (sret < 0) {
1012219820Sjeff		__sdp_log(9, "Error bind: Could not setsockopt sdp_sd\n");
1013219820Sjeff	}
1014219820Sjeff
1015219820Sjeff	*tcp_sd = _socket_funcs.socket(domain, SOCK_STREAM, IPPROTO_TCP);
1016219820Sjeff	if (*tcp_sd < 0) {
1017219820Sjeff		__sdp_log(9, "Error check_legal_bind: "
1018219820Sjeff				  "creating second socket failed:%s\n", strerror(errno));
1019219820Sjeff		_socket_funcs.close(*sdp_sd);
1020219820Sjeff		goto done;
1021219820Sjeff	}
1022219820Sjeff
1023219820Sjeff	__sdp_log(2, "check_legal_bind: reusing <%d> \n", *tcp_sd);
1024219820Sjeff	sret =
1025219820Sjeff		_socket_funcs.setsockopt(*tcp_sd, SOL_SOCKET, SO_REUSEADDR, &yes,
1026219820Sjeff								 sizeof(yes));
1027219820Sjeff	if (sret < 0) {
1028219820Sjeff		__sdp_log(9, "Error bind: Could not setsockopt tcp_sd\n");
1029219820Sjeff	}
1030219820Sjeff
1031219820Sjeff	__sdp_log(1, "check_legal_bind: binding SDP socket\n");
1032219820Sjeff	ret = __bind_semantics(*sdp_sd, sin_addr, addrlen, semantics);
1033219820Sjeff	if (ret < 0) {
1034219820Sjeff		/* bind() for sdp socket failed. It is acceptable only if
1035219820Sjeff		 * the IP is not part of IB network. */
1036219820Sjeff		int err;
1037219820Sjeff		socklen_t len = sizeof(int);
1038219820Sjeff
1039219820Sjeff		if (EADDRINUSE != errno)
1040219820Sjeff			goto done;
1041219820Sjeff#ifdef __linux__
1042219820Sjeff		if (-1 == getsockopt(*sdp_sd, SOL_TCP, SDP_LAST_BIND_ERR, &err, &len)) {
1043219820Sjeff			__sdp_log(9, "Error check_legal_bind:getsockopt: %s\n",
1044219820Sjeff					  strerror(errno));
1045219820Sjeff			goto done;
1046219820Sjeff		}
1047219820Sjeff#else
1048219820Sjeff		err = -errno;
1049219820Sjeff#endif
1050219820Sjeff		if (-ENOENT != err) {
1051219820Sjeff			/* bind() failed due to real error. Can't continue */
1052219820Sjeff			__sdp_log(9, "Error check_legal_bind: "
1053219820Sjeff					  "binding SDP socket failed:%s\n", strerror(errno));
1054219820Sjeff			_socket_funcs.close(*sdp_sd);
1055219820Sjeff			_socket_funcs.close(*tcp_sd);
1056219820Sjeff
1057219820Sjeff			/* TCP and SDP without library return EINVAL */
1058219820Sjeff			if (errno == EADDRINUSE)
1059219820Sjeff				errno = EINVAL;
1060219820Sjeff
1061219820Sjeff			goto done;
1062219820Sjeff		}
1063219820Sjeff		/* IP is ETH, not IB, so can't bind() to sdp socket */
1064219820Sjeff		/* Continue only with TCP */
1065219820Sjeff		_socket_funcs.close(*sdp_sd);
1066219820Sjeff		*sdp_sd = -1;
1067219820Sjeff	}
1068219820Sjeff
1069219820Sjeff	__sdp_log(1, "check_legal_bind: binding TCP socket\n");
1070219820Sjeff	ret = __bind_semantics(*tcp_sd, sin_addr, addrlen, semantics);
1071219820Sjeff	if (ret < 0) {
1072219820Sjeff		__sdp_log(9, "Error check_legal_bind: "
1073219820Sjeff				  "binding TCP socket failed:%s\n", strerror(errno));
1074219820Sjeff		if (-1 != *sdp_sd)
1075219820Sjeff			_socket_funcs.close(*sdp_sd);
1076219820Sjeff		_socket_funcs.close(*tcp_sd);
1077219820Sjeff		goto done;
1078219820Sjeff	}
1079219820Sjeff	ret = 0;
1080219820Sjeff	__sdp_log(2, "check_legal_bind: result:<%d>\n", ret);
1081219820Sjeffdone:
1082219820Sjeff	return ret;
1083219820Sjeff}
1084219820Sjeff
1085219820Sjeff/* ========================================================================= */
1086219820Sjeff/*..close_and_bind - close an open fd and bind another one immediately       */
1087219820Sjeffstatic int
1088219820Sjeffclose_and_bind(int old_sd,
1089219820Sjeff			   int new_sd,
1090219820Sjeff			   const struct sockaddr *addr, socklen_t addrlen, int semantics)
1091219820Sjeff{
1092219820Sjeff	int ret;
1093219820Sjeff
1094219820Sjeff	__sdp_log(2, "close_and_bind: closing <%d> binding <%d>\n", old_sd, new_sd);
1095219820Sjeff	ret = _socket_funcs.close(old_sd);
1096219820Sjeff	if (ret < 0) {
1097219820Sjeff		__sdp_log(9, "Error bind: Could not close old_sd\n");
1098219820Sjeff		goto done;
1099219820Sjeff	}
1100219820Sjeff
1101219820Sjeff	ret = __bind_semantics(new_sd, addr, addrlen, semantics);
1102219820Sjeff	if (ret < 0)
1103219820Sjeff		__sdp_log(9, "Error bind: Could not bind new_sd\n");
1104219820Sjeff
1105219820Sjeffdone:
1106219820Sjeff	__sdp_log(2, "close_and_bind: returning <%d>\n", ret);
1107219820Sjeff	return ret;
1108219820Sjeff}
1109219820Sjeff
1110219820Sjeff/* ========================================================================= */
1111219820Sjeff/*..bind -- replacement bind call.                                           */
1112219820Sjeff/*
1113219820Sjeff   As we do not know the role of this socket yet so we cannot choose AF.
1114219820Sjeff   We need to be able to handle shadow too.
1115219820Sjeff   SDP sockets (may be shadow or not) must be using converted address
1116219820Sjeff
1117219820Sjeff	Since there is no way to "rebind" a socket we have to avoid "false" bind:
1118219820Sjeff	1. When the given address for the bind includes a port we need to
1119219820Sjeff	   guarantee the port is free on both address families. We do that
1120219820Sjeff      by creating temporary sockets and biding them first. Then we close and
1121219820Sjeff		re-use the address on the real sockets.
1122219820Sjeff	2. When ANY_PORT is requested we need to make sure the port we obtain from
1123219820Sjeff	   the first address family is also free on the second one. We use temporary
1124219820Sjeff		sockets for that task too. We loop several times to find such common
1125219820Sjeff		available socket
1126219820Sjeff*/
1127219820Sjeffstatic int
1128219820Sjeff__perform_bind(int fd,
1129219820Sjeff			   const struct sockaddr *addr, socklen_t addrlen, int semantics)
1130219820Sjeff{
1131219820Sjeff	int shadow_fd;
1132219820Sjeff	struct sockaddr_in *sin_addr = (struct sockaddr_in *) addr;
1133219820Sjeff	int ret, sret = -1;
1134219820Sjeff	char buf[MAX_ADDR_STR_LEN];
1135219820Sjeff
1136219820Sjeff	if (init_status == 0)
1137219820Sjeff		__sdp_init();
1138219820Sjeff
1139219820Sjeff	if (NULL == _socket_funcs.bind) {
1140219820Sjeff		__sdp_log(9, "Error bind: no implementation for bind found\n");
1141219820Sjeff		return -1;
1142219820Sjeff	}
1143219820Sjeff
1144219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1145219820Sjeff
1146219820Sjeff	if ((addr == NULL) || is_invalid_addr(addr)) {
1147219820Sjeff		errno = EFAULT;
1148219820Sjeff		__sdp_log(9, "Error bind: illegal address provided\n");
1149219820Sjeff		return -1;
1150219820Sjeff	}
1151219820Sjeff
1152219820Sjeff	if (get_addr_str(addr, buf, MAX_ADDR_STR_LEN)) {
1153219820Sjeff		__sdp_log(9, "Error bind: provided illegal address: %s\n",
1154219820Sjeff				  strerror(errno));
1155219820Sjeff		return -1;
1156219820Sjeff	}
1157219820Sjeff
1158219820Sjeff	__sdp_log(2, "BIND: <%s:%d:%d> type <%d> IP <%s> port <%d>\n",
1159219820Sjeff			  program_invocation_short_name, fd, shadow_fd,
1160219820Sjeff			  sin_addr->sin_family, buf, ntohs(sin_addr->sin_port));
1161219820Sjeff
1162219820Sjeff	if (get_is_sdp_socket(fd)) {
1163219820Sjeff		__sdp_log(1, "BIND: binding SDP socket:<%d>\n", fd);
1164219820Sjeff		ret = __bind_semantics(fd, addr, addrlen, semantics);
1165219820Sjeff		goto done;
1166219820Sjeff	} else if (shadow_fd != -1) {
1167219820Sjeff		/* has shadow */
1168219820Sjeff		/* we need to validate the given address or find a common port
1169219820Sjeff		 * so we use the following tmp address and sockets */
1170219820Sjeff		struct sockaddr_storage tmp_addr;
1171219820Sjeff		int sdp_sd = -1, tcp_sd = -1, port;
1172219820Sjeff
1173219820Sjeff		memcpy(&tmp_addr, addr, addrlen);
1174219820Sjeff		ret = 0;
1175219820Sjeff		if (ntohs(sin_addr->sin_port) == 0) {
1176219820Sjeff			/* When we get ANY_PORT we need to make sure that both TCP
1177219820Sjeff			 * and SDP sockets will use the same port */
1178219820Sjeff
1179219820Sjeff			port = find_free_port(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics);
1180219820Sjeff			if (port < 0) {
1181219820Sjeff				ret = -1;
1182219820Sjeff				__sdp_log(9, "BIND: Failed to find common free port\n");
1183219820Sjeff				/* We cannot bind both tcp and sdp on the same port, we will close
1184219820Sjeff				 * the sdp and continue with tcp only */
1185219820Sjeff				goto done;
1186219820Sjeff			} else {
1187219820Sjeff				/* copy the port to the tmp address */
1188219820Sjeff				set_addr_port_num((struct sockaddr *) &tmp_addr, port);
1189219820Sjeff			}
1190219820Sjeff		} else {
1191219820Sjeff			/* have a shadow but requested specific port - check that we
1192219820Sjeff			 * can actually bind the two addresses and then reuse */
1193219820Sjeff			ret = check_legal_bind(addr, addrlen, fd, &sdp_sd, &tcp_sd, semantics);
1194219820Sjeff			if (ret < 0) {
1195219820Sjeff				__sdp_log(9, "Error bind: "
1196219820Sjeff						  "Provided address can not bind on the two sockets\n");
1197219820Sjeff			}
1198219820Sjeff		}
1199219820Sjeff
1200219820Sjeff		/* if we fail to find a common port or given address can not be used
1201219820Sjeff		 * we return error */
1202219820Sjeff		if (ret < 0) {
1203219820Sjeff			/* Temporary sockets already closed by check_legal_bind or
1204219820Sjeff			 * find_free_port */
1205219820Sjeff			errno = EADDRINUSE;
1206219820Sjeff			goto done;
1207219820Sjeff		}
1208219820Sjeff
1209219820Sjeff		/* close temporary sockets and reuse their address */
1210219820Sjeff		/* HACK: close_and_bind might race with other applications. */
1211219820Sjeff		/* When the race occur we return EADDRINUSE */
1212219820Sjeff		ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) &tmp_addr,
1213219820Sjeff						   addrlen, semantics);
1214219820Sjeff		if (ret < 0) {
1215219820Sjeff			__sdp_log(9, "Error bind: " "Could not close_and_bind TCP side\n");
1216219820Sjeff			if (-1 != sdp_sd)
1217219820Sjeff				_socket_funcs.close(sdp_sd);
1218219820Sjeff			goto done;
1219219820Sjeff		}
1220219820Sjeff
1221219820Sjeff		if (-1 != sdp_sd) {
1222219820Sjeff			ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) &tmp_addr,
1223219820Sjeff							   addrlen, semantics);
1224219820Sjeff
1225219820Sjeff			if (ret < 0) {
1226219820Sjeff				__sdp_log(9,
1227219820Sjeff						  "Error bind: " "Could not close_and_bind sdp side\n");
1228219820Sjeff				goto done;
1229219820Sjeff			}
1230219820Sjeff		}
1231219820Sjeff		goto done;
1232219820Sjeff	}
1233219820Sjeff
1234219820Sjeff	/* we can only get here on single TCP socket */
1235219820Sjeff	__sdp_log(1, "BIND: binding TCP socket:<%d>\n", fd);
1236219820Sjeff	ret = __bind_semantics(fd, addr, addrlen, semantics);
1237219820Sjeff
1238219820Sjeffdone:
1239219820Sjeff	__sdp_log(2, "BIND: <%s:%d:%d> result <%d:%d>\n",
1240219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret, sret);
1241219820Sjeff
1242219820Sjeff	return ret;
1243219820Sjeff}								/* bind */
1244219820Sjeff
1245219820Sjeff
1246219820Sjeffint bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
1247219820Sjeff{
1248219820Sjeff	return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_DEFAULT);
1249219820Sjeff}
1250219820Sjeff
1251219820Sjeff#ifdef SOLARIS_BUILD
1252219820Sjeffint __xnet_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
1253219820Sjeff{
1254219820Sjeff	return __perform_bind(fd, my_addr, addrlen, SOCKET_SEMANTIC_XNET);
1255219820Sjeff}
1256219820Sjeff#endif
1257219820Sjeff
1258219820Sjeff
1259219820Sjeff/* ========================================================================= */
1260219820Sjeff/*..connect -- replacement connect call.                                     */
1261219820Sjeff/*
1262219820Sjeff  Given the connect address we can take out AF decision
1263219820Sjeff  if target AF == both it means SDP and fall back to TCP
1264219820Sjeff  if any connect worked we are fine
1265219820Sjeff*/
1266219820Sjeffstatic inline int
1267219820Sjeff__connect_semantics(int fd,
1268219820Sjeff					const struct sockaddr *serv_addr,
1269219820Sjeff					socklen_t addrlen, int semantics)
1270219820Sjeff{
1271219820Sjeff	return
1272219820Sjeff#ifdef SOLARIS_BUILD
1273219820Sjeff		(semantics == SOCKET_SEMANTIC_XNET) ?
1274219820Sjeff		_socket_xnet_funcs.connect(fd, serv_addr, addrlen) :
1275219820Sjeff#endif
1276219820Sjeff		_socket_funcs.connect(fd, serv_addr, addrlen);
1277219820Sjeff}
1278219820Sjeff
1279219820Sjeffstatic int
1280219820Sjeff__perform_connect(int fd, const struct sockaddr *serv_addr,
1281219820Sjeff		socklen_t addrlen, int semantics)
1282219820Sjeff{
1283219820Sjeff	struct sockaddr_in *serv_sin = (struct sockaddr_in *) serv_addr;
1284219820Sjeff	char buf[MAX_ADDR_STR_LEN];
1285219820Sjeff	int shadow_fd;
1286219820Sjeff	int ret = -1, dup_ret;
1287219820Sjeff	use_family_t target_family;
1288219820Sjeff	int fopts;
1289219820Sjeff
1290219820Sjeff	if (init_status == 0)
1291219820Sjeff		__sdp_init();
1292219820Sjeff
1293219820Sjeff	if (NULL == _socket_funcs.connect) {
1294219820Sjeff		__sdp_log(9, "Error connect: no implementation for connect found\n");
1295219820Sjeff		return -1;
1296219820Sjeff	}
1297219820Sjeff
1298219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1299219820Sjeff
1300219820Sjeff	if ((serv_addr == NULL) || is_invalid_addr(serv_addr)) {
1301219820Sjeff		errno = EFAULT;
1302219820Sjeff		__sdp_log(9, "Error connect: illegal address provided\n");
1303219820Sjeff		return -1;
1304219820Sjeff	}
1305219820Sjeff
1306219820Sjeff	if (get_addr_str(serv_addr, buf, MAX_ADDR_STR_LEN)) {
1307219820Sjeff		__sdp_log(9, "Error connect: provided illegal address: %s\n",
1308219820Sjeff				  strerror(errno));
1309219820Sjeff		return EADDRNOTAVAIL;
1310219820Sjeff	}
1311219820Sjeff
1312219820Sjeff	__sdp_log(2, "CONNECT: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n",
1313219820Sjeff			  program_invocation_short_name, fd, shadow_fd,
1314219820Sjeff			  serv_sin->sin_family, buf, ntohs(serv_sin->sin_port));
1315219820Sjeff
1316219820Sjeff
1317219820Sjeff	/* obtain the target address family */
1318219820Sjeff	target_family = __sdp_match_connect(serv_addr, addrlen);
1319219820Sjeff
1320219820Sjeff	/* if we do not have a shadow - just do the work */
1321219820Sjeff	if (shadow_fd == -1) {
1322219820Sjeff		__sdp_log(1, "CONNECT: connectingthrough %s\n",
1323219820Sjeff				get_is_sdp_socket(fd) ? "SDP" : "TCP");
1324219820Sjeff		ret = __connect_semantics(fd, serv_addr, addrlen, semantics);
1325219820Sjeff		if ((ret == 0) || (errno == EINPROGRESS)) {
1326219820Sjeff			__sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n",
1327219820Sjeff					fd, buf, ntohs(serv_sin->sin_port));
1328219820Sjeff		}
1329219820Sjeff		goto done;
1330219820Sjeff	}
1331219820Sjeff
1332219820Sjeff	if ((target_family == USE_SDP) || (target_family == USE_BOTH)) {
1333219820Sjeff		/* NOTE: the entire if sequence is negative logic */
1334219820Sjeff		__sdp_log(1, "CONNECT: connecting SDP fd:%d\n", shadow_fd);
1335219820Sjeff
1336219820Sjeff		/* make the socket blocking on shadow SDP */
1337219820Sjeff		fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL);
1338219820Sjeff		if ((target_family == USE_BOTH) && (fopts & O_NONBLOCK)) {
1339219820Sjeff			__sdp_log(1,
1340219820Sjeff					  "CONNECT: shadow_fd <%d> will be blocking during connect\n",
1341219820Sjeff					  shadow_fd);
1342219820Sjeff			_socket_funcs.fcntl(shadow_fd, F_SETFL, fopts & (~O_NONBLOCK));
1343219820Sjeff		}
1344219820Sjeff
1345219820Sjeff		ret = __connect_semantics(shadow_fd, serv_addr, addrlen, semantics);
1346219820Sjeff		if ((ret < 0) && (errno != EINPROGRESS)) {
1347219820Sjeff			__sdp_log(9, "Error connect: "
1348219820Sjeff					  "failed for SDP fd:%d with error:%m\n", shadow_fd);
1349219820Sjeff		} else {
1350219820Sjeff			__sdp_log(7, "CONNECT: connected SDP fd:%d to:%s port %d\n",
1351219820Sjeff					  fd, buf, ntohs(serv_sin->sin_port));
1352219820Sjeff		}
1353219820Sjeff
1354219820Sjeff		/* restore socket options */
1355219820Sjeff		_socket_funcs.fcntl(shadow_fd, F_SETFL, fopts);
1356219820Sjeff
1357219820Sjeff		/* if target is SDP or we succeeded we need to dup SDP fd into TCP fd */
1358219820Sjeff		if ((target_family == USE_SDP) || (ret >= 0)) {
1359219820Sjeff			dup_ret = replace_fd_with_its_shadow(fd);
1360219820Sjeff			if (dup_ret < 0) {
1361219820Sjeff				__sdp_log(9, "Error connect: "
1362219820Sjeff						  "failed to dup2 shadow into orig fd:%d\n", fd);
1363219820Sjeff				ret = dup_ret;
1364219820Sjeff			} else {
1365219820Sjeff				/* we can skip the TCP option if we are done */
1366219820Sjeff				__sdp_log(1, "CONNECT: "
1367219820Sjeff						  "matched SDP fd:%d so shadow dup into TCP\n", fd);
1368219820Sjeff				goto done;
1369219820Sjeff			}
1370219820Sjeff		}
1371219820Sjeff	}
1372219820Sjeff
1373219820Sjeff	if ((target_family == USE_TCP) || (target_family == USE_BOTH)) {
1374219820Sjeff		__sdp_log(1, "CONNECT: connecting TCP fd:%d\n", fd);
1375219820Sjeff		ret = __connect_semantics(fd, serv_addr, addrlen, semantics);
1376219820Sjeff		if ((ret < 0) && (errno != EINPROGRESS))
1377219820Sjeff			__sdp_log(9, "Error connect: for TCP fd:%d failed with error:%m\n",
1378219820Sjeff					  fd);
1379219820Sjeff		else
1380219820Sjeff			__sdp_log(7, "CONNECT: connected TCP fd:%d to:%s port %d\n",
1381219820Sjeff					  fd, buf, ntohs(serv_sin->sin_port));
1382219820Sjeff
1383219820Sjeff		if ((target_family == USE_TCP) || (ret >= 0) || (errno == EINPROGRESS)) {
1384219820Sjeff			if (cleanup_shadow(fd) < 0)
1385219820Sjeff				__sdp_log(9,
1386219820Sjeff						  "Error connect: failed to cleanup shadow for fd:%d\n",
1387219820Sjeff						  fd);
1388219820Sjeff		}
1389219820Sjeff	}
1390219820Sjeff
1391219820Sjeffdone:
1392219820Sjeff	__sdp_log(2, "CONNECT: <%s:%d:%d> result <%d>\n",
1393219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret);
1394219820Sjeff
1395219820Sjeff	return ret;
1396219820Sjeff}								/* connect */
1397219820Sjeff
1398219820Sjeffint connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
1399219820Sjeff{
1400219820Sjeff	return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_DEFAULT);
1401219820Sjeff}
1402219820Sjeff
1403219820Sjeff#if defined( SOLARIS_BUILD )
1404219820Sjeffint __xnet_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
1405219820Sjeff{
1406219820Sjeff	return __perform_connect(fd, serv_addr, addrlen, SOCKET_SEMANTIC_XNET);
1407219820Sjeff}
1408219820Sjeff#endif
1409219820Sjeff
1410219820Sjeff/* ========================================================================= */
1411219820Sjeff/*..listen -- replacement listen call.                                       */
1412219820Sjeff/*
1413219820Sjeff   Now we know our role (passive/server) and our address so we can get AF.
1414219820Sjeff   If both we should try listening on both
1415219820Sjeff*/
1416219820Sjeff
1417219820Sjeffstatic inline int __listen_semantics(int fd, int backlog, int semantics)
1418219820Sjeff{
1419219820Sjeff	return
1420219820Sjeff#ifdef SOLARIS_BUILD
1421219820Sjeff		(semantics == SOCKET_SEMANTIC_XNET) ?
1422219820Sjeff		_socket_xnet_funcs.listen(fd, backlog) :
1423219820Sjeff#endif
1424219820Sjeff		_socket_funcs.listen(fd, backlog);
1425219820Sjeff}
1426219820Sjeff
1427219820Sjeffstatic int __perform_listen(int fd, int backlog, int semantics)
1428219820Sjeff{
1429219820Sjeff	use_family_t target_family;
1430219820Sjeff	int shadow_fd;
1431219820Sjeff	int ret = 0, sret = 0;
1432219820Sjeff	struct sockaddr_storage tmp_sin;
1433219820Sjeff	socklen_t tmp_sinlen = sizeof(tmp_sin);
1434219820Sjeff	struct sockaddr_in *sin4 = (struct sockaddr_in *) &tmp_sin;
1435219820Sjeff	char buf[MAX_ADDR_STR_LEN];
1436219820Sjeff	int actual_port;
1437219820Sjeff
1438219820Sjeff	if (init_status == 0)
1439219820Sjeff		__sdp_init();
1440219820Sjeff
1441219820Sjeff	if (NULL == _socket_funcs.listen) {
1442219820Sjeff		__sdp_log(9, "Error listen: no implementation for listen found\n");
1443219820Sjeff		return -1;
1444219820Sjeff	}
1445219820Sjeff
1446219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1447219820Sjeff	__sdp_log(2, "LISTEN: <%s:%d:%d>\n",
1448219820Sjeff			  program_invocation_short_name, fd, shadow_fd);
1449219820Sjeff
1450219820Sjeff	/* if there is no shadow - simply call listen */
1451219820Sjeff	if (shadow_fd == -1) {
1452219820Sjeff		__sdp_log(1, "LISTEN: calling listen on fd:%d\n", fd);
1453219820Sjeff		ret = __listen_semantics(fd, backlog, semantics);
1454219820Sjeff		goto done;
1455219820Sjeff	}
1456219820Sjeff
1457219820Sjeff	/* we need to obtain the address from the fd */
1458219820Sjeff	if (_socket_funcs.getsockname(fd, (struct sockaddr *) &tmp_sin, &tmp_sinlen)
1459219820Sjeff		< 0) {
1460219820Sjeff		__sdp_log(9, "Error listen: getsockname return <%d> for TCP socket\n",
1461219820Sjeff				  errno);
1462219820Sjeff		errno = EADDRNOTAVAIL;
1463219820Sjeff		sret = -1;
1464219820Sjeff		goto done;
1465219820Sjeff	}
1466219820Sjeff
1467219820Sjeff	if (get_addr_str((struct sockaddr *) &tmp_sin, buf, MAX_ADDR_STR_LEN)) {
1468219820Sjeff		__sdp_log(9, "Error listen: provided illegal address: %s\n",
1469219820Sjeff				  strerror(errno));
1470219820Sjeff	}
1471219820Sjeff
1472219820Sjeff	__sdp_log(2, "LISTEN: <%s:%d:%d> domain <%d> IP <%s> port <%d>\n",
1473219820Sjeff			  program_invocation_short_name, fd, shadow_fd,
1474219820Sjeff			  sin4->sin_family, buf, ntohs(sin4->sin_port));
1475219820Sjeff
1476219820Sjeff	target_family =
1477219820Sjeff		__sdp_match_listen((struct sockaddr *) &tmp_sin, sizeof(tmp_sin));
1478219820Sjeff
1479219820Sjeff	/*
1480219820Sjeff	 * in case of an implicit bind and "USE_BOTH" rule we need to first bind the
1481219820Sjeff	 * two sockets to the same port number
1482219820Sjeff	 */
1483219820Sjeff	actual_port = ntohs(sin4->sin_port);
1484219820Sjeff
1485219820Sjeff	/* do we need to implicit bind both */
1486219820Sjeff	if ((actual_port == 0) && (target_family == USE_BOTH)) {
1487219820Sjeff		int sdp_sd = -1, tcp_sd = -1;
1488219820Sjeff
1489219820Sjeff		actual_port = find_free_port((struct sockaddr *) &tmp_sin, tmp_sinlen,
1490219820Sjeff				fd, &sdp_sd, &tcp_sd, semantics);
1491219820Sjeff		if (actual_port < 0) {
1492219820Sjeff			ret = -1;
1493219820Sjeff			__sdp_log(8, "LISTEN: Failed to find common free port. Only TCP will be used.\n");
1494219820Sjeff			target_family = USE_TCP;
1495219820Sjeff		} else {
1496219820Sjeff			/* copy the port to the tmp address */
1497219820Sjeff			set_addr_port_num((struct sockaddr *) sin4, actual_port);
1498219820Sjeff
1499219820Sjeff			__sdp_log(2, "LISTEN: BOTH on IP <%s> port <%d>\n",
1500219820Sjeff					  buf, actual_port);
1501219820Sjeff			/* perform the bind */
1502219820Sjeff			ret = close_and_bind(tcp_sd, fd, (struct sockaddr *) sin4,
1503219820Sjeff					tmp_sinlen, semantics);
1504219820Sjeff			if (ret < 0) {
1505219820Sjeff				__sdp_log(9, "Error listen: "
1506219820Sjeff						  "Could not close_and_bind TCP side\n");
1507219820Sjeff			}
1508219820Sjeff
1509219820Sjeff			ret = close_and_bind(sdp_sd, shadow_fd, (struct sockaddr *) sin4,
1510219820Sjeff					tmp_sinlen, semantics);
1511219820Sjeff			if (ret < 0) {
1512219820Sjeff				__sdp_log(9, "Error listen: "
1513219820Sjeff						  "Could not close_and_bind SDP side\n");
1514219820Sjeff			}
1515219820Sjeff		}
1516219820Sjeff	}
1517219820Sjeff
1518219820Sjeff	if ((target_family == USE_TCP) || (target_family == USE_BOTH)) {
1519219820Sjeff		__sdp_log(1, "LISTEN: calling listen on TCP fd:%d\n", fd);
1520219820Sjeff		ret = __listen_semantics(fd, backlog, semantics);
1521219820Sjeff		if (ret < 0) {
1522219820Sjeff			__sdp_log(9, "Error listen: failed with code <%d> on TCP fd:<%d>\n",
1523219820Sjeff					  errno, fd);
1524219820Sjeff		} else {
1525219820Sjeff			__sdp_log(7, "LISTEN: fd:%d listening on TCP bound to:%s port:%d\n",
1526219820Sjeff					  fd, buf, actual_port);
1527219820Sjeff		}
1528219820Sjeff	}
1529219820Sjeff
1530219820Sjeff	if ((target_family == USE_SDP) || (target_family == USE_BOTH)) {
1531219820Sjeff		__sdp_log(1, "LISTEN: calling listen on SDP fd:<%d>\n", shadow_fd);
1532219820Sjeff		sret = __listen_semantics(shadow_fd, backlog, semantics);
1533219820Sjeff		if (sret < 0) {
1534219820Sjeff			__sdp_log(9, "Error listen: failed with code <%d> SDP fd:<%d>\n",
1535219820Sjeff					  errno, shadow_fd);
1536219820Sjeff		} else {
1537219820Sjeff			__sdp_log(7, "LISTEN: fd:%d listening on SDP bound to:%s port:%d\n",
1538219820Sjeff					  fd, buf, actual_port);
1539219820Sjeff		}
1540219820Sjeff	}
1541219820Sjeff
1542219820Sjeff	/* cleanup the un-needed shadow if TCP and did not fail */
1543219820Sjeff	if ((target_family == USE_TCP) && (ret >= 0)) {
1544219820Sjeff		__sdp_log(1, "LISTEN: cleaning up shadow SDP\n");
1545219820Sjeff		if (cleanup_shadow(fd) < 0)
1546219820Sjeff			__sdp_log(9, "Error listen: failed to cleanup shadow for fd:%d\n",
1547219820Sjeff					  fd);
1548219820Sjeff	}
1549219820Sjeff
1550219820Sjeff	/* cleanup the TCP socket and replace with SDP */
1551219820Sjeff	if ((target_family == USE_SDP) && (sret >= 0)) {
1552219820Sjeff		__sdp_log(1, "LISTEN: cleaning TCP socket and dup2 SDP into it\n");
1553219820Sjeff		if (0 > (sret = replace_fd_with_its_shadow(fd)))
1554219820Sjeff			__sdp_log(9, "Error listen: "
1555219820Sjeff					  "failed to dup2 shadow into orig fd:%d\n", fd);
1556219820Sjeff	}
1557219820Sjeff
1558219820Sjeffdone:
1559219820Sjeff	__sdp_log(2, "LISTEN: <%s:%d:%d> result <%d>\n",
1560219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret);
1561219820Sjeff	/* its a success only if both are ok */
1562219820Sjeff	if (ret < 0)
1563219820Sjeff		return (ret);
1564219820Sjeff	if (sret < 0)
1565219820Sjeff		return (sret);
1566219820Sjeff	return 0;
1567219820Sjeff}								/* listen */
1568219820Sjeff
1569219820Sjeffint listen(int fd, int backlog)
1570219820Sjeff{
1571219820Sjeff	return __perform_listen(fd, backlog, SOCKET_SEMANTIC_DEFAULT);
1572219820Sjeff}
1573219820Sjeff
1574219820Sjeff#ifdef SOLARIS_BUILD
1575219820Sjeffint __xnet_listen(int fd, int backlog)
1576219820Sjeff{
1577219820Sjeff	return __perform_listen(fd, backlog, SOCKET_SEMANTIC_XNET);
1578219820Sjeff}
1579219820Sjeff#endif
1580219820Sjeff
1581219820Sjeff/* ========================================================================= */
1582219820Sjeff/*..close -- replacement close call. */
1583219820Sjeffint close(int fd)
1584219820Sjeff{
1585219820Sjeff	int shadow_fd;
1586219820Sjeff	int ret;
1587219820Sjeff
1588219820Sjeff	if (init_status == 0)
1589219820Sjeff		__sdp_init();
1590219820Sjeff
1591219820Sjeff	if (NULL == _socket_funcs.close) {
1592219820Sjeff		__sdp_log(9, "Error close: no implementation for close found\n");
1593219820Sjeff		return -1;
1594219820Sjeff	}
1595219820Sjeff
1596219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1597219820Sjeff
1598219820Sjeff	__sdp_log(2, "CLOSE: <%s:%d:%d>\n",
1599219820Sjeff			  program_invocation_short_name, fd, shadow_fd);
1600219820Sjeff
1601219820Sjeff	if (shadow_fd != -1) {
1602219820Sjeff		__sdp_log(1, "CLOSE: closing shadow fd:<%d>\n", shadow_fd);
1603219820Sjeff		if (cleanup_shadow(fd) < 0)
1604219820Sjeff			__sdp_log(9, "Error close: failed to cleanup shadow for fd:%d\n",
1605219820Sjeff					  fd);
1606219820Sjeff	}
1607219820Sjeff
1608219820Sjeff	init_extra_attribute(fd);
1609219820Sjeff	ret = _socket_funcs.close(fd);
1610219820Sjeff	__sdp_log(2, "CLOSE: <%s:%d:%d> result <%d>\n",
1611219820Sjeff			  program_invocation_short_name, fd, shadow_fd, ret);
1612219820Sjeff	return ret;
1613219820Sjeff}								/* close */
1614219820Sjeff
1615219820Sjeff/* ========================================================================= */
1616219820Sjeff/*..dup -- replacement dup call.                                             */
1617219820Sjeff/* we duplicate the fd and its shadow if exists - ok if the main worked      */
1618219820Sjeffint dup(int fd)
1619219820Sjeff{
1620219820Sjeff	int newfd, new_shadow_fd = -1;
1621219820Sjeff	int shadow_fd;
1622219820Sjeff
1623219820Sjeff	if (init_status == 0)
1624219820Sjeff		__sdp_init();
1625219820Sjeff
1626219820Sjeff	if (NULL == _socket_funcs.dup) {
1627219820Sjeff		__sdp_log(9, "Error dup: no implementation for dup found\n");
1628219820Sjeff		return -1;
1629219820Sjeff	}
1630219820Sjeff
1631219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1632219820Sjeff
1633219820Sjeff	__sdp_log(2, "DUP: <%s:%d:%d>\n",
1634219820Sjeff			  program_invocation_short_name, fd, shadow_fd);
1635219820Sjeff
1636219820Sjeff	__sdp_log(1, "DUP: duplication fd:<%d>\n", fd);
1637219820Sjeff	newfd = _socket_funcs.dup(fd);
1638219820Sjeff
1639219820Sjeff	if (newfd == fd)
1640219820Sjeff		return (fd);
1641219820Sjeff
1642219820Sjeff	if (!is_valid_fd(newfd)) {
1643219820Sjeff		__sdp_log(9, "Error dup: new fd <%d> out of range.\n", newfd);
1644219820Sjeff	} else {
1645219820Sjeff		/* copy attributes from old fd */
1646219820Sjeff		libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd];
1647219820Sjeff		libsdp_fd_attributes[newfd].shadow_fd = -1;
1648219820Sjeff
1649219820Sjeff		if (shadow_fd != -1) {
1650219820Sjeff			__sdp_log(1, "DUP: duplication shadow fd:<%d>\n", shadow_fd);
1651219820Sjeff			new_shadow_fd = _socket_funcs.dup(shadow_fd);
1652219820Sjeff			if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) {
1653219820Sjeff				__sdp_log(9, "Error dup: new shadow fd <%d> out of range.\n",
1654219820Sjeff						  new_shadow_fd);
1655219820Sjeff			} else {
1656219820Sjeff				libsdp_fd_attributes[new_shadow_fd] =
1657219820Sjeff					libsdp_fd_attributes[shadow_fd];
1658219820Sjeff				libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd;
1659219820Sjeff			}
1660219820Sjeff		}						/* shadow exists */
1661219820Sjeff	}
1662219820Sjeff
1663219820Sjeff	__sdp_log(2, "DUP: <%s:%d:%d> return <%d:%d>\n",
1664219820Sjeff			  program_invocation_short_name, fd, shadow_fd, newfd,
1665219820Sjeff			  new_shadow_fd);
1666219820Sjeff
1667219820Sjeff	return newfd;
1668219820Sjeff}								/* dup */
1669219820Sjeff
1670219820Sjeff/* ========================================================================= */
1671219820Sjeff/*..dup2 -- replacement dup2 call.                                           */
1672219820Sjeff/* since only the main new fd is given we only move the shadow if exists     */
1673219820Sjeffint dup2(int fd, int newfd)
1674219820Sjeff{
1675219820Sjeff	int shadow_fd;
1676219820Sjeff	int shadow_newfd;
1677219820Sjeff	int new_shadow_fd = -1;
1678219820Sjeff	int ret = 0;
1679219820Sjeff
1680219820Sjeff	if (init_status == 0)
1681219820Sjeff		__sdp_init();
1682219820Sjeff
1683219820Sjeff	if (NULL == _socket_funcs.dup2) {
1684219820Sjeff		__sdp_log(9, "Error dup2: no implementation for dup2 found\n");
1685219820Sjeff		return -1;
1686219820Sjeff	}
1687219820Sjeff
1688219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1689219820Sjeff	shadow_newfd = get_shadow_fd_by_fd(newfd);
1690219820Sjeff
1691219820Sjeff	__sdp_log(2, "DUP2: <%s:%d:%d>\n",
1692219820Sjeff			  program_invocation_short_name, fd, shadow_fd);
1693219820Sjeff
1694219820Sjeff	if (newfd == fd) {
1695219820Sjeff		__sdp_log(1, "DUP2: skip duplicating fd:<%d> into:<%d>\n", fd, newfd);
1696219820Sjeff		goto done;
1697219820Sjeff	}
1698219820Sjeff
1699219820Sjeff	/* dup2 closes the target file desc if it is a valid fd */
1700219820Sjeff	if (shadow_newfd != -1) {
1701219820Sjeff		__sdp_log(1, "DUP2: closing newfd:<%d> shadow:<%d>\n", newfd,
1702219820Sjeff				  shadow_newfd);
1703219820Sjeff		ret = _socket_funcs.close(shadow_newfd);
1704219820Sjeff		if (ret != 0) {
1705219820Sjeff			__sdp_log(9,
1706219820Sjeff					  "DUP2: fail to close newfd:<%d> shadow:<%d> with: %d %s\n",
1707219820Sjeff					  newfd, shadow_newfd, ret, strerror(errno));
1708219820Sjeff		}
1709219820Sjeff	}
1710219820Sjeff
1711219820Sjeff	__sdp_log(1, "DUP2: duplicating fd:<%d> into:<%d>\n", fd, newfd);
1712219820Sjeff	newfd = _socket_funcs.dup2(fd, newfd);
1713219820Sjeff	if ((newfd > max_file_descriptors) || (newfd < 0)) {
1714219820Sjeff		__sdp_log(9, "Error dup2: new fd <%d> out of range.\n", newfd);
1715219820Sjeff	} else {
1716219820Sjeff		/* copy attributes from old fd */
1717219820Sjeff		libsdp_fd_attributes[fd].shadow_fd = -1;
1718219820Sjeff		libsdp_fd_attributes[newfd] = libsdp_fd_attributes[fd];
1719219820Sjeff
1720219820Sjeff		/* if it had a shadow create a new shadow */
1721219820Sjeff		if (shadow_fd != -1) {
1722219820Sjeff			__sdp_log(1, "DUP2: duplication shadow fd:<%d>\n", shadow_fd);
1723219820Sjeff			new_shadow_fd = _socket_funcs.dup(shadow_fd);
1724219820Sjeff			if ((new_shadow_fd > max_file_descriptors) || (new_shadow_fd < 0)) {
1725219820Sjeff				__sdp_log(9, "Error dup2: new shadow fd <%d> out of range.\n",
1726219820Sjeff						  new_shadow_fd);
1727219820Sjeff			} else {
1728219820Sjeff				libsdp_fd_attributes[new_shadow_fd] =
1729219820Sjeff					libsdp_fd_attributes[shadow_fd];
1730219820Sjeff				libsdp_fd_attributes[newfd].shadow_fd = new_shadow_fd;
1731219820Sjeff			}
1732219820Sjeff		}						/* newfd is ok */
1733219820Sjeff	}
1734219820Sjeff
1735219820Sjeffdone:
1736219820Sjeff	__sdp_log(2, "DUP2: <%s:%d:%d> return <%d:%d>\n",
1737219820Sjeff			  program_invocation_short_name, fd, shadow_fd, newfd,
1738219820Sjeff			  new_shadow_fd);
1739219820Sjeff
1740219820Sjeff	return newfd;
1741219820Sjeff}								/* dup */
1742219820Sjeff
1743219820Sjeff/* ========================================================================= */
1744219820Sjeff/*..getsockname -- replacement getsocknanme call.                            */
1745219820Sjeffint getsockname(int fd, struct sockaddr *name, socklen_t * namelen)
1746219820Sjeff{
1747219820Sjeff	int ret = 0;
1748219820Sjeff	char buf[MAX_ADDR_STR_LEN];
1749219820Sjeff
1750219820Sjeff	if (init_status == 0)
1751219820Sjeff		__sdp_init();
1752219820Sjeff
1753219820Sjeff	/*
1754219820Sjeff	 * ensure the SDP protocol family is not exposed to the user, since
1755219820Sjeff	 * this is meant to be a transparency layer.
1756219820Sjeff	 */
1757219820Sjeff	if (NULL == _socket_funcs.getsockname) {
1758219820Sjeff		__sdp_log(9,
1759219820Sjeff				  "Error getsockname: no implementation for getsockname found\n");
1760219820Sjeff		return -1;
1761219820Sjeff	}
1762219820Sjeff
1763219820Sjeff	/* double check provided pointers */
1764219820Sjeff	if ((name == NULL) || is_invalid_addr(name)) {
1765219820Sjeff		errno = EFAULT;
1766219820Sjeff		__sdp_log(9, "Error getsockname: illegal address provided\n");
1767219820Sjeff		return -1;
1768219820Sjeff	}
1769219820Sjeff
1770219820Sjeff	if ((namelen != NULL) && is_invalid_addr(namelen)) {
1771219820Sjeff		errno = EFAULT;
1772219820Sjeff		__sdp_log(9, "Error getsockname: illegal address length pointer provided\n");
1773219820Sjeff		return -1;
1774219820Sjeff	}
1775219820Sjeff
1776219820Sjeff	__sdp_log(2, "GETSOCKNAME <%s:%d>\n", program_invocation_short_name, fd);
1777219820Sjeff
1778219820Sjeff	ret = _socket_funcs.getsockname(fd, name, namelen);
1779219820Sjeff
1780219820Sjeff	if (__sdp_log_get_level() <= 1) {
1781219820Sjeff		if (get_addr_str(name, buf, MAX_ADDR_STR_LEN)) {
1782219820Sjeff			__sdp_log(1, "GETSOCKNAME: " "address is illegal\n");
1783219820Sjeff		} else {
1784219820Sjeff			__sdp_log(1, "GETSOCKNAME: address is:%s port:%d\n", buf,
1785219820Sjeff					  ntohs(((struct sockaddr_in *) name)->sin_port));
1786219820Sjeff		}
1787219820Sjeff	}
1788219820Sjeff	__sdp_log(2, "GETSOCKNAME <%s:%d> result <%d>\n",
1789219820Sjeff			  program_invocation_short_name, fd, ret);
1790219820Sjeff
1791219820Sjeff	return ret;
1792219820Sjeff}								/* getsockname */
1793219820Sjeff
1794219820Sjeff/* ========================================================================= */
1795219820Sjeff/*..getpeername -- replacement getpeername call. */
1796219820Sjeffint getpeername(int fd, struct sockaddr *name, socklen_t * namelen)
1797219820Sjeff{
1798219820Sjeff	int ret = 0;
1799219820Sjeff
1800219820Sjeff	if (init_status == 0)
1801219820Sjeff		__sdp_init();
1802219820Sjeff
1803219820Sjeff	if (NULL == _socket_funcs.getpeername) {
1804219820Sjeff		__sdp_log(9, "Error getpeername: "
1805219820Sjeff				  "no implementation for getpeername found\n");
1806219820Sjeff		return -1;
1807219820Sjeff	}
1808219820Sjeff
1809219820Sjeff	/* double check provided pointers */
1810219820Sjeff	if ((name == NULL) || is_invalid_addr(name)) {
1811219820Sjeff		errno = EFAULT;
1812219820Sjeff		__sdp_log(9, "Error getsockname: illegal address provided\n");
1813219820Sjeff		return -1;
1814219820Sjeff	}
1815219820Sjeff
1816219820Sjeff	if ((namelen != NULL) && is_invalid_addr(namelen)) {
1817219820Sjeff		errno = EFAULT;
1818219820Sjeff		__sdp_log(9,
1819219820Sjeff				  "Error getsockname: illegal address length pointer provided\n");
1820219820Sjeff		return -1;
1821219820Sjeff	}
1822219820Sjeff
1823219820Sjeff	__sdp_log(2, "GETPEERNAME <%s:%d>\n", program_invocation_short_name, fd);
1824219820Sjeff
1825219820Sjeff	ret = _socket_funcs.getpeername(fd, name, namelen);
1826219820Sjeff
1827219820Sjeff	__sdp_log(2, "GETPEERNAME <%s:%d> result <%d:%d> family=%d s_addr=%d\n",
1828219820Sjeff			  program_invocation_short_name, fd, ret,
1829219820Sjeff			  (!(0 > ret) ? 0 : -1), name->sa_family,
1830219820Sjeff			  ((struct sockaddr_in *) name)->sin_addr.s_addr);
1831219820Sjeff
1832219820Sjeff	return ret;
1833219820Sjeff}								/* getpeername */
1834219820Sjeff
1835219820Sjeff
1836219820Sjeff
1837219820Sjeff/* ========================================================================= */
1838219820Sjeff/*..accept -- replacement accept call.                                       */
1839219820Sjeff/*
1840219820Sjeff  If we have a shadow we need to decide which socket we want to accept on
1841219820Sjeff  so we select first and then give priority based on previous selection
1842219820Sjeff*/
1843219820Sjeffint accept(int fd, struct sockaddr *addr, socklen_t * addrlen)
1844219820Sjeff{
1845219820Sjeff	int shadow_fd;
1846219820Sjeff	int ret = 0;
1847219820Sjeff	fd_set fds;
1848219820Sjeff	socklen_t saved_addrlen = 0;
1849219820Sjeff	int fopts;
1850219820Sjeff	char buf[MAX_ADDR_STR_LEN];
1851219820Sjeff
1852219820Sjeff	if (init_status == 0)
1853219820Sjeff		__sdp_init();
1854219820Sjeff
1855219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
1856219820Sjeff
1857219820Sjeff	/*
1858219820Sjeff	 * ensure the SDP protocol family is not exposed to the user, since
1859219820Sjeff	 * this is meant to be a transparency layer.
1860219820Sjeff	 */
1861219820Sjeff	if (NULL == _socket_funcs.accept) {
1862219820Sjeff		__sdp_log(9, "Error accept: no implementation for accept found\n");
1863219820Sjeff		return -1;
1864219820Sjeff	}
1865219820Sjeff
1866219820Sjeff	/* double check provided pointers */
1867219820Sjeff	if ((addr != NULL) && is_invalid_addr(addr)) {
1868219820Sjeff		errno = EINVAL;
1869219820Sjeff		__sdp_log(9, "Error accept: illegal address provided\n");
1870219820Sjeff		return -1;
1871219820Sjeff	}
1872219820Sjeff
1873219820Sjeff	if ((addrlen != NULL) && is_invalid_addr(addrlen)) {
1874219820Sjeff		errno = EINVAL;
1875219820Sjeff		__sdp_log(9, "Error accept: illegal address length pointer provided\n");
1876219820Sjeff		return -1;
1877219820Sjeff	}
1878219820Sjeff
1879219820Sjeff	if (addr && addrlen)
1880219820Sjeff		saved_addrlen = *addrlen;
1881219820Sjeff
1882219820Sjeff	__sdp_log(2, "ACCEPT: <%s:%d>\n", program_invocation_short_name, fd);
1883219820Sjeff
1884219820Sjeff	if (shadow_fd == -1) {
1885219820Sjeff		fopts = _socket_funcs.fcntl(fd, F_GETFL);
1886219820Sjeff		__sdp_log(1, "ACCEPT: fd <%d> opts are <0x%x>\n", fd, fopts);
1887219820Sjeff
1888219820Sjeff		__sdp_log(7, "ACCEPT: accepting on single fd:<%d>\n", fd);
1889219820Sjeff		ret = _socket_funcs.accept(fd, addr, addrlen);
1890219820Sjeff		if (ret < 0) {
1891219820Sjeff			if (!(fopts & O_NONBLOCK && errno == EWOULDBLOCK))
1892219820Sjeff				__sdp_log(9, "Error accept: accept returned :<%d> %s\n",
1893219820Sjeff						  ret, strerror(errno));
1894219820Sjeff		} else {
1895219820Sjeff			set_is_sdp_socket(ret, get_is_sdp_socket(fd));
1896219820Sjeff		}
1897219820Sjeff	} else {
1898219820Sjeff
1899219820Sjeff		fopts = _socket_funcs.fcntl(shadow_fd, F_GETFL);
1900219820Sjeff		__sdp_log(1, "ACCEPT: shadow_fd <%d> opts are <0x%x>\n",
1901219820Sjeff				  shadow_fd, fopts);
1902219820Sjeff
1903219820Sjeff		/* we need different behavior for NONBLOCK or signal IO and BLOCK */
1904219820Sjeff		if ((fopts > 0) && (fopts & (O_NONBLOCK | FASYNC))) {
1905219820Sjeff			__sdp_log(1, "ACCEPT: accepting (nonblock) on SDP fd:<%d>\n", shadow_fd);
1906219820Sjeff
1907219820Sjeff			ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1908219820Sjeff			if (ret >= 0) {
1909219820Sjeff				set_is_sdp_socket(ret, 1);
1910219820Sjeff
1911219820Sjeff				__sdp_log(7, "ACCEPT: accepted (nonblock) SDP fd:<%d>\n",
1912219820Sjeff						  shadow_fd);
1913219820Sjeff			} else {
1914219820Sjeff				__sdp_log(1, "ACCEPT: accept on SDP fd:<%d> return:%d errno:%d\n",
1915219820Sjeff						  shadow_fd, ret, errno);
1916219820Sjeff
1917219820Sjeff				__sdp_log(1, "ACCEPT: accepting (nonblock) on TCP fd:<%d>\n", fd);
1918219820Sjeff				ret = _socket_funcs.accept(fd, addr, addrlen);
1919219820Sjeff				if (ret >= 0) {
1920219820Sjeff					__sdp_log(7, "ACCEPT: accepted (nonblock) TCP fd:<%d>\n",
1921219820Sjeff							  shadow_fd);
1922219820Sjeff				} else {
1923219820Sjeff					__sdp_log(1, "ACCEPT: accept on TCP fd:<%d> "
1924219820Sjeff							  "return:%d errno:%d\n", fd, ret, errno);
1925219820Sjeff				}
1926219820Sjeff			}
1927219820Sjeff		} else {
1928219820Sjeff			__sdp_log(1, "ACCEPT: selecting both fd:<%d> and shadow:<%d>\n",
1929219820Sjeff					  fd, shadow_fd);
1930219820Sjeff			FD_ZERO(&fds);
1931219820Sjeff			FD_SET(fd, &fds);
1932219820Sjeff			FD_SET(shadow_fd, &fds);
1933219820Sjeff			ret =
1934219820Sjeff				_socket_funcs.select(1 + ((fd > shadow_fd) ? fd : shadow_fd),
1935219820Sjeff									 &fds, NULL, NULL, NULL);
1936219820Sjeff			if (ret >= 0) {
1937219820Sjeff				if (last_accept_was_tcp(fd) == 0) {
1938219820Sjeff					if (FD_ISSET(fd, &fds)) {
1939219820Sjeff						set_last_accept(fd, 1);
1940219820Sjeff						__sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd);
1941219820Sjeff						ret = _socket_funcs.accept(fd, addr, addrlen);
1942219820Sjeff					} else {
1943219820Sjeff						__sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n",
1944219820Sjeff								  shadow_fd);
1945219820Sjeff						ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1946219820Sjeff						if (ret >= 0)
1947219820Sjeff							set_is_sdp_socket(ret, 1);
1948219820Sjeff					}
1949219820Sjeff				} else {
1950219820Sjeff					if (FD_ISSET(shadow_fd, &fds)) {
1951219820Sjeff						set_last_accept(fd, 1);
1952219820Sjeff						__sdp_log(7, "ACCEPT: accepting on SDP fd:<%d>\n",
1953219820Sjeff								  shadow_fd);
1954219820Sjeff						ret = _socket_funcs.accept(shadow_fd, addr, addrlen);
1955219820Sjeff						if (ret >= 0)
1956219820Sjeff							set_is_sdp_socket(ret, 1);
1957219820Sjeff					} else {
1958219820Sjeff						__sdp_log(7, "ACCEPT: accepting on TCP fd:<%d>\n", fd);
1959219820Sjeff						ret = _socket_funcs.accept(fd, addr, addrlen);
1960219820Sjeff					}
1961219820Sjeff				}
1962219820Sjeff			} else {
1963219820Sjeff				if (errno != EINTR) {
1964219820Sjeff					__sdp_log(9,
1965219820Sjeff							  "Error accept: select returned :<%d> (%d) %s\n",
1966219820Sjeff							  ret, errno, strerror(errno));
1967219820Sjeff				} else {
1968219820Sjeff					__sdp_log(1, "ACCEPT: select returned :<%d> (%d) %s\n",
1969219820Sjeff							  ret, errno, strerror(errno));
1970219820Sjeff				}
1971219820Sjeff			}
1972219820Sjeff		}						/* blocking mode */
1973219820Sjeff	}							/* shadow fd */
1974219820Sjeff
1975219820Sjeff	if ((__sdp_log_get_level() <= 1) && (ret >= 0) && addr && addrlen) {
1976219820Sjeff		get_addr_str(addr, buf, *addrlen);
1977219820Sjeff		__sdp_log(1, "ACCEPT: accepted from:%s port:%d into fd:%d\n",
1978219820Sjeff				  buf, ntohs(((struct sockaddr_in *) addr)->sin_port), ret);
1979219820Sjeff	}
1980219820Sjeff	__sdp_log(2, "ACCEPT: <%s:%d> return <%d>\n",
1981219820Sjeff			  program_invocation_short_name, fd, ret);
1982219820Sjeff
1983219820Sjeff	return ret;
1984219820Sjeff}								/* accept */
1985219820Sjeff
1986219820Sjeff/* ========================================================================= */
1987219820Sjeff/*..select -- replacement socket call.                                       */
1988219820Sjeff/*
1989219820Sjeff   if we have shadow we must select on it too - which requires a hack back
1990219820Sjeff   and forth
1991219820Sjeff*/
1992219820Sjeffint
1993219820Sjeffselect(int n,
1994219820Sjeff	   fd_set * readfds,
1995219820Sjeff	   fd_set * writefds, fd_set * exceptfds, struct timeval *timeout)
1996219820Sjeff{
1997219820Sjeff	int shadow_fd;
1998219820Sjeff	int ret;
1999219820Sjeff	int current;
2000219820Sjeff	int maxi = 0;
2001219820Sjeff	fd_set new_fds;
2002219820Sjeff
2003219820Sjeff	if (init_status == 0)
2004219820Sjeff		__sdp_init();
2005219820Sjeff
2006219820Sjeff	if (NULL == _socket_funcs.select) {
2007219820Sjeff		__sdp_log(9, "Error select: no implementation for select found\n");
2008219820Sjeff		return -1;
2009219820Sjeff	}
2010219820Sjeff
2011219820Sjeff	__sdp_log(2, "SELECT: <%s:%d>\n", program_invocation_short_name, n);
2012219820Sjeff
2013219820Sjeff	/* if we do not read - nothing to do */
2014219820Sjeff	if (readfds == NULL) {
2015219820Sjeff		ret = _socket_funcs.select(n, readfds, writefds, exceptfds, timeout);
2016219820Sjeff		goto done;
2017219820Sjeff	}
2018219820Sjeff
2019219820Sjeff	FD_ZERO(&new_fds);
2020219820Sjeff	if (n > 0) {
2021219820Sjeff		maxi = n - 1;
2022219820Sjeff	}
2023219820Sjeff
2024219820Sjeff	/* add shadow bits */
2025219820Sjeff	for (current = 0; current < n; current++) {
2026219820Sjeff		if (FD_ISSET(current, readfds)) {
2027219820Sjeff			FD_SET(current, &new_fds);
2028219820Sjeff			if (current > maxi) {
2029219820Sjeff				maxi = current;
2030219820Sjeff			}
2031219820Sjeff			shadow_fd = get_shadow_fd_by_fd(current);
2032219820Sjeff			if (shadow_fd != -1) {
2033219820Sjeff				__sdp_log(1,
2034219820Sjeff						  "SELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2035219820Sjeff						  current, shadow_fd);
2036219820Sjeff				FD_SET(shadow_fd, &new_fds);
2037219820Sjeff				if (shadow_fd > maxi) {
2038219820Sjeff					maxi = shadow_fd;
2039219820Sjeff				}
2040219820Sjeff			}
2041219820Sjeff		}
2042219820Sjeff	}
2043219820Sjeff
2044219820Sjeff	__sdp_log(1, "SELECT: invoking select n=<%d>\n", 1 + maxi);
2045219820Sjeff	ret = _socket_funcs.select(1 + maxi,
2046219820Sjeff							   &new_fds, writefds, exceptfds, timeout);
2047219820Sjeff
2048219820Sjeff	/* remove the count and bits of the shadows */
2049219820Sjeff	if (ret >= 0) {
2050219820Sjeff		for (current = 0; current < n; current++) {
2051219820Sjeff			shadow_fd = get_shadow_fd_by_fd(current);
2052219820Sjeff			if (shadow_fd == -1) {
2053219820Sjeff				if (FD_ISSET(current, readfds) &&
2054219820Sjeff					FD_ISSET(current, &new_fds) == 0) {
2055219820Sjeff					FD_CLR(current, readfds);
2056219820Sjeff				}
2057219820Sjeff			} else {
2058219820Sjeff				if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds)
2059219820Sjeff					&& FD_ISSET(shadow_fd, &new_fds)) {
2060219820Sjeff					ret -= 1;
2061219820Sjeff				}
2062219820Sjeff				if (FD_ISSET(current, readfds) &&
2063219820Sjeff					FD_ISSET(current, &new_fds) == 0 &&
2064219820Sjeff					FD_ISSET(shadow_fd, &new_fds) == 0) {
2065219820Sjeff					FD_CLR(current, readfds);
2066219820Sjeff				}
2067219820Sjeff			}
2068219820Sjeff		}
2069219820Sjeff	}
2070219820Sjeff
2071219820Sjeffdone:
2072219820Sjeff
2073219820Sjeff	__sdp_log(2, "SELECT: <%s:%d> return <%d>\n",
2074219820Sjeff			  program_invocation_short_name, n, ret);
2075219820Sjeff	return ret;
2076219820Sjeff}								/* select */
2077219820Sjeff
2078219820Sjeff/* ========================================================================= */
2079219820Sjeff/*..pselect -- replacement socket call.                                      */
2080219820Sjeff/*
2081219820Sjeff   if we have shadow we must pselect on it too - which requires a hack back
2082219820Sjeff   and forth
2083219820Sjeff*/
2084219820Sjeffint
2085219820Sjeffpselect(int n,
2086219820Sjeff		fd_set * readfds,
2087219820Sjeff		fd_set * writefds,
2088219820Sjeff		fd_set * exceptfds,
2089219820Sjeff		const struct timespec *timeout, const sigset_t * sigmask)
2090219820Sjeff{
2091219820Sjeff	int shadow_fd;
2092219820Sjeff	int ret;
2093219820Sjeff	int current;
2094219820Sjeff	int maxi = 0;
2095219820Sjeff	fd_set new_fds;
2096219820Sjeff
2097219820Sjeff	if (init_status == 0)
2098219820Sjeff		__sdp_init();
2099219820Sjeff
2100219820Sjeff	if (NULL == _socket_funcs.pselect) {
2101219820Sjeff		__sdp_log(9, "Error pselect: no implementation for pselect found\n");
2102219820Sjeff		return -1;
2103219820Sjeff	}
2104219820Sjeff
2105219820Sjeff	__sdp_log(2, "PSELECT: <%s:%d>\n", program_invocation_short_name, n);
2106219820Sjeff
2107219820Sjeff	/* if we do not read - nothing to do */
2108219820Sjeff	if (readfds == NULL) {
2109219820Sjeff		ret =
2110219820Sjeff			_socket_funcs.pselect(n, readfds, writefds, exceptfds, timeout,
2111219820Sjeff								  sigmask);
2112219820Sjeff		goto done;
2113219820Sjeff	}
2114219820Sjeff
2115219820Sjeff	FD_ZERO(&new_fds);
2116219820Sjeff	if (n > 0) {
2117219820Sjeff		maxi = n - 1;
2118219820Sjeff	}
2119219820Sjeff
2120219820Sjeff	/* add shadow bits */
2121219820Sjeff	for (current = 0; current < n; current++) {
2122219820Sjeff		if (FD_ISSET(current, readfds)) {
2123219820Sjeff			FD_SET(current, &new_fds);
2124219820Sjeff			if (current > maxi) {
2125219820Sjeff				maxi = current;
2126219820Sjeff			}
2127219820Sjeff			shadow_fd = get_shadow_fd_by_fd(current);
2128219820Sjeff			if (shadow_fd != -1) {
2129219820Sjeff				__sdp_log(1,
2130219820Sjeff						  "PSELECT: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2131219820Sjeff						  current, shadow_fd);
2132219820Sjeff				FD_SET(shadow_fd, &new_fds);
2133219820Sjeff				if (shadow_fd > maxi) {
2134219820Sjeff					maxi = shadow_fd;
2135219820Sjeff				}
2136219820Sjeff			}
2137219820Sjeff		}
2138219820Sjeff	}
2139219820Sjeff
2140219820Sjeff	__sdp_log(1, "PSELECT: invoking pselect n=<%d>\n", 1 + maxi);
2141219820Sjeff	ret = _socket_funcs.pselect(1 + maxi,
2142219820Sjeff								&new_fds, writefds, exceptfds,
2143219820Sjeff								timeout, sigmask);
2144219820Sjeff
2145219820Sjeff	/* remove the count and bits of the shadows */
2146219820Sjeff	if (ret >= 0) {
2147219820Sjeff		for (current = 0; current < n; current++) {
2148219820Sjeff			shadow_fd = get_shadow_fd_by_fd(current);
2149219820Sjeff			if (shadow_fd == -1) {
2150219820Sjeff				if (FD_ISSET(current, readfds) &&
2151219820Sjeff					FD_ISSET(current, &new_fds) == 0) {
2152219820Sjeff					FD_CLR(current, readfds);
2153219820Sjeff				}
2154219820Sjeff			} else {
2155219820Sjeff				if (FD_ISSET(current, readfds) && FD_ISSET(current, &new_fds)
2156219820Sjeff					&& FD_ISSET(shadow_fd, &new_fds)) {
2157219820Sjeff					ret -= 1;
2158219820Sjeff				}
2159219820Sjeff				if (FD_ISSET(current, readfds) &&
2160219820Sjeff					FD_ISSET(current, &new_fds) == 0 &&
2161219820Sjeff					FD_ISSET(shadow_fd, &new_fds) == 0) {
2162219820Sjeff					FD_CLR(current, readfds);
2163219820Sjeff				}
2164219820Sjeff			}
2165219820Sjeff		}
2166219820Sjeff	}
2167219820Sjeff
2168219820Sjeffdone:
2169219820Sjeff
2170219820Sjeff	__sdp_log(2, "PSELECT: <%s:%d> return <%d>\n",
2171219820Sjeff			  program_invocation_short_name, n, ret);
2172219820Sjeff	return ret;
2173219820Sjeff}								/* pselect */
2174219820Sjeff
2175219820Sjeff/* ========================================================================= */
2176219820Sjeff/*..poll -- replacement socket call.                                      */
2177219820Sjeff/*
2178219820Sjeff   if we have shadow we must poll on it too - which requires a hack back
2179219820Sjeff   and forth
2180219820Sjeff*/
2181219820Sjeffint poll(struct pollfd *ufds, nfds_t nfds, int timeout)
2182219820Sjeff{
2183219820Sjeff	int ret;
2184219820Sjeff	int shadow_fd;
2185219820Sjeff	int current;
2186219820Sjeff	int extra = 0;
2187219820Sjeff	struct pollfd *poll_fds = NULL;
2188219820Sjeff	struct pollfd *poll_fd_ptr = NULL;
2189219820Sjeff
2190219820Sjeff	if (init_status == 0)
2191219820Sjeff		__sdp_init();
2192219820Sjeff
2193219820Sjeff	if (NULL == _socket_funcs.poll) {
2194219820Sjeff		__sdp_log(9, "Error poll: no implementation for poll found\n");
2195219820Sjeff		return -1;
2196219820Sjeff	}
2197219820Sjeff
2198219820Sjeff	__sdp_log(2, "POLL: <%s:%d>\n", program_invocation_short_name, nfds);
2199219820Sjeff
2200219820Sjeff	/* if we do not have any file desc - nothing to do */
2201219820Sjeff	if (ufds == NULL) {
2202219820Sjeff		ret = _socket_funcs.poll(ufds, nfds, timeout);
2203219820Sjeff		goto done;
2204219820Sjeff	}
2205219820Sjeff
2206219820Sjeff	/* scan for how many extra fds are required */
2207219820Sjeff	for (current = 0; current < nfds; current++) {
2208219820Sjeff		shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2209219820Sjeff		if (shadow_fd != -1)
2210219820Sjeff			extra++;
2211219820Sjeff	}
2212219820Sjeff
2213219820Sjeff	if (!extra) {
2214219820Sjeff		poll_fds = ufds;
2215219820Sjeff	} else {
2216219820Sjeff		poll_fds =
2217219820Sjeff			(struct pollfd *) malloc((nfds + extra) * sizeof(struct pollfd));
2218219820Sjeff		if (!poll_fds) {
2219219820Sjeff			__sdp_log(9,
2220219820Sjeff					  "Error poll: malloc of extended pollfd array failed\n");
2221219820Sjeff			ret = -1;
2222219820Sjeff			errno = ENOMEM;
2223219820Sjeff			goto done;
2224219820Sjeff		}
2225219820Sjeff		poll_fd_ptr = poll_fds;
2226219820Sjeff		for (current = 0; current < nfds; current++) {
2227219820Sjeff			*poll_fd_ptr = ufds[current];
2228219820Sjeff			poll_fd_ptr++;
2229219820Sjeff			shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2230219820Sjeff			if (shadow_fd != -1) {
2231219820Sjeff				__sdp_log(1, "POLL: adding fd:<%d> shadow_fd:<%d> to readfs\n",
2232219820Sjeff						  current, shadow_fd);
2233219820Sjeff				*poll_fd_ptr = ufds[current];
2234219820Sjeff				poll_fd_ptr->fd = shadow_fd;
2235219820Sjeff				poll_fd_ptr++;
2236219820Sjeff			}
2237219820Sjeff		}
2238219820Sjeff	}
2239219820Sjeff
2240219820Sjeff	__sdp_log(1, "POLL: invoking poll nfds=<%d>\n", nfds + extra);
2241219820Sjeff	ret = _socket_funcs.poll(poll_fds, nfds + extra, timeout);
2242219820Sjeff
2243219820Sjeff	/* refactor into original list if any events */
2244219820Sjeff	if ((ret > 0) && extra) {
2245219820Sjeff		poll_fd_ptr = poll_fds;
2246219820Sjeff		for (current = 0; current < nfds; current++) {
2247219820Sjeff			shadow_fd = get_shadow_fd_by_fd(ufds[current].fd);
2248219820Sjeff			if (shadow_fd == -1) {
2249219820Sjeff				ufds[current] = *poll_fd_ptr;
2250219820Sjeff			} else {
2251219820Sjeff				ufds[current] = *poll_fd_ptr;
2252219820Sjeff				poll_fd_ptr++;
2253219820Sjeff				if (poll_fd_ptr->revents) {
2254219820Sjeff					if (ufds[current].revents)
2255219820Sjeff						ret--;
2256219820Sjeff					ufds[current].revents |= poll_fd_ptr->revents;
2257219820Sjeff				}
2258219820Sjeff			}
2259219820Sjeff			poll_fd_ptr++;
2260219820Sjeff		}
2261219820Sjeff	}
2262219820Sjeff
2263219820Sjeff	if (extra)
2264219820Sjeff		free(poll_fds);
2265219820Sjeffdone:
2266219820Sjeff
2267219820Sjeff	__sdp_log(2, "POLL: <%s:%d> return <%d>\n",
2268219820Sjeff			  program_invocation_short_name, nfds, ret);
2269219820Sjeff	return ret;
2270219820Sjeff}								/* poll */
2271219820Sjeff
2272219820Sjeff#ifdef __linux__
2273219820Sjeff/* ========================================================================= */
2274219820Sjeff/*..epoll_create -- replacement socket call.                                 */
2275219820Sjeff/*
2276219820Sjeff   Need to make the size twice as large for shadow fds
2277219820Sjeff*/
2278219820Sjeffint epoll_create(int size)
2279219820Sjeff{
2280219820Sjeff	int epfd;
2281219820Sjeff
2282219820Sjeff	if (init_status == 0)
2283219820Sjeff		__sdp_init();
2284219820Sjeff
2285219820Sjeff	if (NULL == _socket_funcs.epoll_create) {
2286219820Sjeff		__sdp_log(9,
2287219820Sjeff				  "Error epoll_create: no implementation for epoll_create found\n");
2288219820Sjeff		return -1;
2289219820Sjeff	}
2290219820Sjeff
2291219820Sjeff	__sdp_log(2, "EPOLL_CREATE: <%s:%d>\n", program_invocation_short_name,
2292219820Sjeff			  size);
2293219820Sjeff
2294219820Sjeff	epfd = _socket_funcs.epoll_create(size * 2);
2295219820Sjeff
2296219820Sjeff	__sdp_log(2, "EPOLL_CREATE: <%s:%d> return %d\n",
2297219820Sjeff			  program_invocation_short_name, size, epfd);
2298219820Sjeff	return epfd;
2299219820Sjeff}								/* epoll_create */
2300219820Sjeff
2301219820Sjeff/* ========================================================================= */
2302219820Sjeff/*..epoll_ctl -- replacement socket call.                                   */
2303219820Sjeff/*
2304219820Sjeff   Need to add/delete/modify shadow fds as well
2305219820Sjeff*/
2306219820Sjeffint epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
2307219820Sjeff{
2308219820Sjeff	int ret, shadow_fd, ret2;
2309219820Sjeff
2310219820Sjeff	if (init_status == 0)
2311219820Sjeff		__sdp_init();
2312219820Sjeff
2313219820Sjeff	if (NULL == _socket_funcs.epoll_ctl) {
2314219820Sjeff		__sdp_log(9,
2315219820Sjeff				  "Error epoll_ctl: no implementation for epoll_ctl found\n");
2316219820Sjeff		return -1;
2317219820Sjeff	}
2318219820Sjeff
2319219820Sjeff	__sdp_log(2, "EPOLL_CTL: <%s:%d> op <%d:%d>\n",
2320219820Sjeff			  program_invocation_short_name, epfd, op, fd);
2321219820Sjeff
2322219820Sjeff	ret = _socket_funcs.epoll_ctl(epfd, op, fd, event);
2323219820Sjeff
2324219820Sjeff	shadow_fd = get_shadow_fd_by_fd(fd);
2325219820Sjeff	if (shadow_fd != -1) {
2326219820Sjeff		ret2 = _socket_funcs.epoll_ctl(epfd, op, shadow_fd, event);
2327219820Sjeff		if (ret2 < 0) {
2328219820Sjeff			__sdp_log(9, "Error epoll_ctl <%s:%d:%d>",
2329219820Sjeff					  program_invocation_short_name, fd, shadow_fd);
2330219820Sjeff			return ret2;
2331219820Sjeff		}
2332219820Sjeff	}
2333219820Sjeff
2334219820Sjeff	__sdp_log(2, "EPOLL_CTL: <%s:%d> return <%d>\n",
2335219820Sjeff			  program_invocation_short_name, epfd, ret);
2336219820Sjeff	return ret;
2337219820Sjeff}								/* epoll_ctl */
2338219820Sjeff
2339219820Sjeff/* ========================================================================= */
2340219820Sjeff/*..epoll_wait -- replacement socket call.                                   */
2341219820Sjeff/*
2342219820Sjeff   We don't care who generated the event because all we get is user-context
2343219820Sjeff   values.
2344219820Sjeff*/
2345219820Sjeffint epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)
2346219820Sjeff{
2347219820Sjeff	int ret;
2348219820Sjeff
2349219820Sjeff	if (init_status == 0)
2350219820Sjeff		__sdp_init();
2351219820Sjeff
2352219820Sjeff	if (NULL == _socket_funcs.epoll_wait) {
2353219820Sjeff		__sdp_log(9,
2354219820Sjeff				  "Error epoll_wait: no implementation for epoll_wait found\n");
2355219820Sjeff		return -1;
2356219820Sjeff	}
2357219820Sjeff
2358219820Sjeff	__sdp_log(2, "EPOLL_WAIT: <%s:%d>\n", program_invocation_short_name, epfd);
2359219820Sjeff
2360219820Sjeff	ret = _socket_funcs.epoll_wait(epfd, events, maxevents, timeout);
2361219820Sjeff
2362219820Sjeff	__sdp_log(2, "EPOLL_WAIT: <%s:%d> return <%d>\n",
2363219820Sjeff			  program_invocation_short_name, epfd, ret);
2364219820Sjeff	return ret;
2365219820Sjeff}								/* epoll_wait */
2366219820Sjeff
2367219820Sjeff/* ========================================================================= */
2368219820Sjeff/*..epoll_pwait -- replacement socket call.                                  */
2369219820Sjeff/*
2370219820Sjeff   We don't care who generated the event because all we get is user-context
2371219820Sjeff   values.
2372219820Sjeff*/
2373219820Sjeffint
2374219820Sjeffepoll_pwait(int epfd,
2375219820Sjeff			struct epoll_event *events,
2376219820Sjeff			int maxevents, int timeout, const sigset_t * sigmask)
2377219820Sjeff{
2378219820Sjeff	int ret;
2379219820Sjeff
2380219820Sjeff	if (init_status == 0)
2381219820Sjeff		__sdp_init();
2382219820Sjeff
2383219820Sjeff	if (NULL == _socket_funcs.epoll_pwait) {
2384219820Sjeff		__sdp_log(9,
2385219820Sjeff				  "Error epoll_pwait: no implementation for epoll_pwait found\n");
2386219820Sjeff		return -1;
2387219820Sjeff	}
2388219820Sjeff
2389219820Sjeff	__sdp_log(2, "EPOLL_PWAIT: <%s:%d>\n", program_invocation_short_name, epfd);
2390219820Sjeff
2391219820Sjeff	ret = _socket_funcs.epoll_pwait(epfd, events, maxevents, timeout, sigmask);
2392219820Sjeff
2393219820Sjeff	__sdp_log(2, "EPOLL_PWAIT: <%s:%d> return <%d>\n",
2394219820Sjeff			  program_invocation_short_name, epfd, ret);
2395219820Sjeff	return ret;
2396219820Sjeff}								/* epoll_pwait */
2397219820Sjeff#endif
2398219820Sjeff
2399219820Sjeff/* ========================================================================= */
2400219820Sjeff
2401219820Sjeff/* --------------------------------------------------------------------- */
2402219820Sjeff/*                                                                       */
2403219820Sjeff/* Library load/unload initialization/cleanup                            */
2404219820Sjeff/*                                                                       */
2405219820Sjeff/* --------------------------------------------------------------------- */
2406219820Sjeff/* ========================================================================= */
2407219820Sjeff/*..__sdp_init -- intialize the library */
2408219820Sjeffvoid __sdp_init(void)
2409219820Sjeff{
2410219820Sjeff	char *config_file, *error_str;
2411219820Sjeff	int fd;
2412219820Sjeff	struct rlimit nofiles_limit;
2413219820Sjeff
2414219820Sjeff	/* HACK: races might apply here: can we assume init is happening
2415219820Sjeff	   only within one thread ? */
2416219820Sjeff	if (init_status != 0)
2417219820Sjeff		return;
2418219820Sjeff	init_status = 1;
2419219820Sjeff
2420219820Sjeff	dev_null_fd = open("/dev/null", O_WRONLY);
2421219820Sjeff
2422219820Sjeff	/* figure out the max number of file descriptors */
2423219820Sjeff	if (getrlimit(RLIMIT_NOFILE, &nofiles_limit))
2424219820Sjeff		max_file_descriptors = 1024;
2425219820Sjeff	else
2426219820Sjeff		max_file_descriptors = nofiles_limit.rlim_cur;
2427219820Sjeff
2428219820Sjeff	/* allocate and initialize the shadow sdp sockets array */
2429219820Sjeff	libsdp_fd_attributes =
2430219820Sjeff		(struct sdp_extra_fd_attributes *) calloc(max_file_descriptors,
2431219820Sjeff												  sizeof(struct
2432219820Sjeff														 sdp_extra_fd_attributes));
2433219820Sjeff	for (fd = 0; fd < max_file_descriptors; fd++)
2434219820Sjeff		init_extra_attribute(fd);
2435219820Sjeff
2436219820Sjeff#ifndef RTLD_NEXT
2437219820Sjeff	/*
2438219820Sjeff	 * open libc for original socket call.
2439219820Sjeff	 * Solaris relies on RTLD next - since the socket calls are
2440219820Sjeff	 * actually in libsocket rather than libc.
2441219820Sjeff	 */
2442219820Sjeff	__libc_dl_handle = dlopen("/lib64/libc.so.6", RTLD_LAZY);
2443219820Sjeff	if (NULL == __libc_dl_handle) {
2444219820Sjeff		__libc_dl_handle = dlopen("/lib/libc.so.6", RTLD_LAZY);
2445219820Sjeff		if (NULL == __libc_dl_handle) {
2446219820Sjeff			fprintf(stderr, "%s\n", dlerror());
2447219820Sjeff			return;
2448219820Sjeff		}
2449219820Sjeff	}
2450219820Sjeff#endif
2451219820Sjeff
2452219820Sjeff	/*
2453219820Sjeff	 * Get the original functions
2454219820Sjeff	 */
2455219820Sjeff	_socket_funcs.ioctl = dlsym(__libc_dl_handle, "ioctl");
2456219820Sjeff	if (NULL != (error_str = dlerror())) {
2457219820Sjeff		fprintf(stderr, "%s\n", error_str);
2458219820Sjeff	}
2459219820Sjeff
2460219820Sjeff	_socket_funcs.fcntl = dlsym(__libc_dl_handle, "fcntl");
2461219820Sjeff	if (NULL != (error_str = dlerror())) {
2462219820Sjeff		fprintf(stderr, "%s\n", error_str);
2463219820Sjeff	}
2464219820Sjeff
2465219820Sjeff	_socket_funcs.socket = dlsym(__libc_dl_handle, "socket");
2466219820Sjeff	if (NULL != (error_str = dlerror())) {
2467219820Sjeff		fprintf(stderr, "%s\n", error_str);
2468219820Sjeff	}
2469219820Sjeff
2470219820Sjeff	_socket_funcs.setsockopt = dlsym(__libc_dl_handle, "setsockopt");
2471219820Sjeff	if (NULL != (error_str = dlerror())) {
2472219820Sjeff		fprintf(stderr, "%s\n", error_str);
2473219820Sjeff	}
2474219820Sjeff
2475219820Sjeff	_socket_funcs.connect = dlsym(__libc_dl_handle, "connect");
2476219820Sjeff	if (NULL != (error_str = dlerror())) {
2477219820Sjeff		fprintf(stderr, "%s\n", error_str);
2478219820Sjeff	}
2479219820Sjeff
2480219820Sjeff	_socket_funcs.listen = dlsym(__libc_dl_handle, "listen");
2481219820Sjeff	if (NULL != (error_str = dlerror())) {
2482219820Sjeff		fprintf(stderr, "%s\n", error_str);
2483219820Sjeff	}
2484219820Sjeff
2485219820Sjeff	_socket_funcs.bind = dlsym(__libc_dl_handle, "bind");
2486219820Sjeff	if (NULL != (error_str = dlerror())) {
2487219820Sjeff		fprintf(stderr, "%s\n", error_str);
2488219820Sjeff	}
2489219820Sjeff
2490219820Sjeff	_socket_funcs.close = dlsym(__libc_dl_handle, "close");
2491219820Sjeff	if (NULL != (error_str = dlerror())) {
2492219820Sjeff		fprintf(stderr, "%s\n", error_str);
2493219820Sjeff	}
2494219820Sjeff
2495219820Sjeff	_socket_funcs.dup = dlsym(__libc_dl_handle, "dup");
2496219820Sjeff	if (NULL != (error_str = dlerror())) {
2497219820Sjeff		fprintf(stderr, "%s\n", error_str);
2498219820Sjeff	}
2499219820Sjeff
2500219820Sjeff	_socket_funcs.dup2 = dlsym(__libc_dl_handle, "dup2");
2501219820Sjeff	if (NULL != (error_str = dlerror())) {
2502219820Sjeff		fprintf(stderr, "%s\n", error_str);
2503219820Sjeff	}
2504219820Sjeff
2505219820Sjeff	_socket_funcs.getpeername = dlsym(__libc_dl_handle, "getpeername");
2506219820Sjeff	if (NULL != (error_str = dlerror())) {
2507219820Sjeff		fprintf(stderr, "%s\n", error_str);
2508219820Sjeff	}
2509219820Sjeff
2510219820Sjeff	_socket_funcs.getsockname = dlsym(__libc_dl_handle, "getsockname");
2511219820Sjeff	if (NULL != (error_str = dlerror())) {
2512219820Sjeff		fprintf(stderr, "%s\n", error_str);
2513219820Sjeff	}
2514219820Sjeff
2515219820Sjeff	_socket_funcs.accept = dlsym(__libc_dl_handle, "accept");
2516219820Sjeff	if (NULL != (error_str = dlerror())) {
2517219820Sjeff		fprintf(stderr, "%s\n", error_str);
2518219820Sjeff	}
2519219820Sjeff
2520219820Sjeff	_socket_funcs.select = dlsym(__libc_dl_handle, "select");
2521219820Sjeff	if (NULL != (error_str = dlerror())) {
2522219820Sjeff		fprintf(stderr, "%s\n", error_str);
2523219820Sjeff	}
2524219820Sjeff
2525219820Sjeff	_socket_funcs.pselect = dlsym(__libc_dl_handle, "pselect");
2526219820Sjeff	if (NULL != (error_str = dlerror())) {
2527219820Sjeff		fprintf(stderr, "%s\n", error_str);
2528219820Sjeff	}
2529219820Sjeff
2530219820Sjeff	_socket_funcs.poll = dlsym(__libc_dl_handle, "poll");
2531219820Sjeff	if (NULL != (error_str = dlerror())) {
2532219820Sjeff		fprintf(stderr, "%s\n", error_str);
2533219820Sjeff	}
2534219820Sjeff
2535219820Sjeff#ifdef __linux__
2536219820Sjeff	_socket_funcs.epoll_create = dlsym(__libc_dl_handle, "epoll_create");
2537219820Sjeff	if (NULL != (error_str = dlerror())) {
2538219820Sjeff		fprintf(stderr, "%s\n", error_str);
2539219820Sjeff	}
2540219820Sjeff
2541219820Sjeff	_socket_funcs.epoll_ctl = dlsym(__libc_dl_handle, "epoll_ctl");
2542219820Sjeff	if (NULL != (error_str = dlerror())) {
2543219820Sjeff		fprintf(stderr, "%s\n", error_str);
2544219820Sjeff	}
2545219820Sjeff
2546219820Sjeff	_socket_funcs.epoll_wait = dlsym(__libc_dl_handle, "epoll_wait");
2547219820Sjeff	if (NULL != (error_str = dlerror())) {
2548219820Sjeff		fprintf(stderr, "%s\n", error_str);
2549219820Sjeff	}
2550219820Sjeff
2551219820Sjeff	_socket_funcs.epoll_pwait = dlsym(__libc_dl_handle, "epoll_pwait");
2552219820Sjeff	if (NULL != (error_str = dlerror())) {
2553219820Sjeff		fprintf(stderr, "%s\n", error_str);
2554219820Sjeff	}
2555219820Sjeff#endif
2556219820Sjeff#ifdef SOLARIS_BUILD
2557219820Sjeff	_socket_xnet_funcs.socket = dlsym(__libc_dl_handle, "__xnet_socket");
2558219820Sjeff	if (NULL != (error_str = dlerror())) {
2559219820Sjeff		fprintf(stderr, "%s\n", error_str);
2560219820Sjeff	}
2561219820Sjeff
2562219820Sjeff	_socket_xnet_funcs.connect = dlsym(__libc_dl_handle, "__xnet_connect");
2563219820Sjeff	if (NULL != (error_str = dlerror())) {
2564219820Sjeff		fprintf(stderr, "%s\n", error_str);
2565219820Sjeff	}
2566219820Sjeff
2567219820Sjeff	_socket_xnet_funcs.listen = dlsym(__libc_dl_handle, "__xnet_listen");
2568219820Sjeff	if (NULL != (error_str = dlerror())) {
2569219820Sjeff		fprintf(stderr, "%s\n", error_str);
2570219820Sjeff	}
2571219820Sjeff
2572219820Sjeff	_socket_xnet_funcs.bind = dlsym(__libc_dl_handle, "__xnet_bind");
2573219820Sjeff	if (NULL != (error_str = dlerror())) {
2574219820Sjeff		fprintf(stderr, "%s\n", error_str);
2575219820Sjeff	}
2576219820Sjeff
2577219820Sjeff	/* Determine program name by asking libdl */
2578219820Sjeff	Dl_argsinfo args_info;
2579219820Sjeff	if (NULL != dlinfo(RTLD_SELF, RTLD_DI_ARGSINFO, &args_info)) {
2580219820Sjeff		fprintf(stderr, "args_info: %s\n", dlerror());
2581219820Sjeff	} else {
2582219820Sjeff		program_invocation_name = args_info.dla_argv[0];
2583219820Sjeff		program_invocation_short_name = basename(args_info.dla_argv[0]);
2584219820Sjeff	}
2585219820Sjeff#endif
2586219820Sjeff
2587219820Sjeff	if (getenv("SIMPLE_LIBSDP") != NULL) {
2588219820Sjeff		simple_sdp_library = 1;
2589219820Sjeff	}
2590219820Sjeff
2591219820Sjeff	if (getenv("ALWAYS_USE_SDP") != NULL) {
2592219820Sjeff		simple_sdp_library = 1;
2593219820Sjeff	}
2594219820Sjeff#define LIBSDP_DEFAULT_CONFIG_FILE  SYSCONFDIR "/libsdp.conf"
2595219820Sjeff	if (!simple_sdp_library) {
2596219820Sjeff		config_file = getenv("LIBSDP_CONFIG_FILE");
2597219820Sjeff		if (!config_file)
2598219820Sjeff			config_file = LIBSDP_DEFAULT_CONFIG_FILE;
2599219820Sjeff
2600219820Sjeff		if (__sdp_parse_config(config_file)) {
2601219820Sjeff			fprintf(stderr,
2602219820Sjeff					"libsdp Error: failed to parse config file:%s. Using defaults.\n",
2603219820Sjeff					config_file);
2604219820Sjeff		}
2605219820Sjeff	}
2606219820Sjeff
2607219820Sjeff	__sdp_log(1, "Max file descriptors:%d\n", max_file_descriptors);
2608219820Sjeff	init_status = 2;
2609219820Sjeff
2610219820Sjeff}								/* __sdp_init */
2611219820Sjeff
2612219820Sjeff/* ========================================================================= */
2613219820Sjeff/*..__sdp_fini -- when the library is unloaded this is called */
2614219820Sjeffvoid __sdp_fini(void)
2615219820Sjeff{
2616219820Sjeff	struct use_family_rule *rule;
2617219820Sjeff	for (rule = __sdp_clients_family_rules_head; rule != NULL;
2618219820Sjeff		 rule = rule->next)
2619219820Sjeff		free(rule->prog_name_expr);
2620219820Sjeff	for (rule = __sdp_servers_family_rules_head; rule != NULL;
2621219820Sjeff		 rule = rule->next)
2622219820Sjeff		free(rule->prog_name_expr);
2623219820Sjeff
2624219820Sjeff	free(libsdp_fd_attributes);
2625219820Sjeff
2626219820Sjeff#ifndef RTLD_NEXT
2627219820Sjeff	dlclose(__libc_dl_handle);
2628219820Sjeff#endif
2629219820Sjeff}								/* _fini */
2630