2 * Copyright (c) 2016-2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 * Copyright (c) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
18 * Copyright (C) 2006-2014 Stefan Metzmacher <metze@samba.org>
19 * Copyright (C) 2013-2014 Andreas Schneider <asn@samba.org>
21 * All rights reserved.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
34 * 3. Neither the name of the author nor the names of its contributors
35 * may be used to endorse or promote products derived from this software
36 * without specific prior written permission.
38 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 Socket wrapper library. Passes all socket communication over
54 unix domain sockets if the environment variable SOCKET_WRAPPER_DIR
66 #include <vcl/ldp_socket_wrapper.h>
78 /* Macros for accessing mutexes */
79 #define SWRAP_LOCK(m) do { \
80 pthread_mutex_lock(&(m ## _mutex)); \
83 #define SWRAP_UNLOCK(m) do { \
84 pthread_mutex_unlock(&(m ## _mutex)); \
87 /* Add new global locks here please */
88 #define SWRAP_LOCK_ALL \
89 SWRAP_LOCK(libc_symbol_binding); \
91 #define SWRAP_UNLOCK_ALL \
92 SWRAP_UNLOCK(libc_symbol_binding); \
96 /* The mutex for accessing the global libc.symbols */
97 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
99 /* Function prototypes */
102 #define SWRAP_LOG(...)
104 static unsigned int swrap_log_lvl = SWRAP_LOG_WARN;
107 swrap_log (enum swrap_dbglvl_e dbglvl, const char *func,
108 const char *format, ...)
109 PRINTF_ATTRIBUTE (3, 4);
110 #define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__)
113 swrap_log (enum swrap_dbglvl_e dbglvl,
114 const char *func, const char *format, ...)
119 va_start (va, format);
120 vsnprintf (buffer, sizeof (buffer), format, va);
123 if (dbglvl <= swrap_log_lvl)
127 case SWRAP_LOG_ERROR:
129 "SWRAP_ERROR(%d) - %s: %s\n",
130 (int) getpid (), func, buffer);
134 "SWRAP_WARN(%d) - %s: %s\n",
135 (int) getpid (), func, buffer);
137 case SWRAP_LOG_DEBUG:
139 "SWRAP_DEBUG(%d) - %s: %s\n",
140 (int) getpid (), func, buffer);
142 case SWRAP_LOG_TRACE:
144 "SWRAP_TRACE(%d) - %s: %s\n",
145 (int) getpid (), func, buffer);
153 /*********************************************************
154 * SWRAP LOADING LIBC FUNCTIONS
155 *********************************************************/
157 typedef int (*__libc_accept4) (int sockfd,
158 struct sockaddr * addr,
159 socklen_t * addrlen, int flags);
160 typedef int (*__libc_accept) (int sockfd,
161 struct sockaddr * addr, socklen_t * addrlen);
162 typedef int (*__libc_bind) (int sockfd,
163 const struct sockaddr * addr, socklen_t addrlen);
164 typedef int (*__libc_close) (int fd);
165 typedef int (*__libc_connect) (int sockfd,
166 const struct sockaddr * addr,
170 /* TBD: dup and dup2 to be implemented later */
171 typedef int (*__libc_dup) (int fd);
172 typedef int (*__libc_dup2) (int oldfd, int newfd);
175 typedef int (*__libc_fcntl) (int fd, int cmd, ...);
177 typedef int (*__libc_fcntl64) (int fd, int cmd, ...);
179 typedef FILE *(*__libc_fopen) (const char *name, const char *mode);
181 typedef FILE *(*__libc_fopen64) (const char *name, const char *mode);
184 typedef int (*__libc_eventfd) (int count, int flags);
186 typedef int (*__libc_getpeername) (int sockfd,
187 struct sockaddr * addr,
188 socklen_t * addrlen);
189 typedef int (*__libc_getsockname) (int sockfd,
190 struct sockaddr * addr,
191 socklen_t * addrlen);
192 typedef int (*__libc_getsockopt) (int sockfd,
195 void *optval, socklen_t * optlen);
196 typedef int (*__libc_ioctl) (int d, unsigned long int request, ...);
197 typedef int (*__libc_listen) (int sockfd, int backlog);
198 typedef int (*__libc_open) (const char *pathname, int flags, mode_t mode);
200 typedef int (*__libc_open64) (const char *pathname, int flags, mode_t mode);
201 #endif /* HAVE_OPEN64 */
202 typedef int (*__libc_openat) (int dirfd, const char *path, int flags, ...);
203 typedef int (*__libc_pipe) (int pipefd[2]);
204 typedef int (*__libc_read) (int fd, void *buf, size_t count);
205 typedef ssize_t (*__libc_readv) (int fd, const struct iovec * iov,
207 typedef int (*__libc_recv) (int sockfd, void *buf, size_t len, int flags);
208 typedef int (*__libc_recvfrom) (int sockfd,
212 struct sockaddr * src_addr,
213 socklen_t * addrlen);
214 typedef int (*__libc_recvmsg) (int sockfd, const struct msghdr * msg,
216 typedef int (*__libc_send) (int sockfd, const void *buf, size_t len,
218 typedef ssize_t (*__libc_sendfile) (int out_fd, int in_fd, off_t * offset,
220 typedef int (*__libc_sendmsg) (int sockfd, const struct msghdr * msg,
222 typedef int (*__libc_sendto) (int sockfd, const void *buf, size_t len,
223 int flags, const struct sockaddr * dst_addr,
225 typedef int (*__libc_setsockopt) (int sockfd, int level, int optname,
226 const void *optval, socklen_t optlen);
228 typedef int (*__libc_signalfd) (int fd, const sigset_t * mask, int flags);
230 typedef int (*__libc_socket) (int domain, int type, int protocol);
231 typedef int (*__libc_socketpair) (int domain, int type, int protocol,
233 #ifdef HAVE_TIMERFD_CREATE
234 typedef int (*__libc_timerfd_create) (int clockid, int flags);
236 typedef ssize_t (*__libc_write) (int fd, const void *buf, size_t count);
237 typedef ssize_t (*__libc_writev) (int fd, const struct iovec * iov,
240 typedef int (*__libc_shutdown) (int fd, int how);
242 typedef int (*__libc_select) (int __nfds, fd_set * __restrict __readfds,
243 fd_set * __restrict __writefds,
244 fd_set * __restrict __exceptfds,
245 struct timeval * __restrict __timeout);
248 typedef int (*__libc_pselect) (int __nfds, fd_set * __restrict __readfds,
249 fd_set * __restrict __writefds,
250 fd_set * __restrict __exceptfds,
251 const struct timespec * __restrict __timeout,
252 const __sigset_t * __restrict __sigmask);
255 typedef int (*__libc_epoll_create) (int __size);
257 typedef int (*__libc_epoll_create1) (int __flags);
259 typedef int (*__libc_epoll_ctl) (int __epfd, int __op, int __fd,
260 struct epoll_event * __event);
262 typedef int (*__libc_epoll_wait) (int __epfd, struct epoll_event * __events,
263 int __maxevents, int __timeout);
265 typedef int (*__libc_epoll_pwait) (int __epfd, struct epoll_event * __events,
266 int __maxevents, int __timeout,
267 const __sigset_t * __ss);
269 typedef int (*__libc_poll) (struct pollfd * __fds, nfds_t __nfds,
273 typedef int (*__libc_ppoll) (struct pollfd * __fds, nfds_t __nfds,
274 const struct timespec * __timeout,
275 const __sigset_t * __ss);
279 #define SWRAP_SYMBOL_ENTRY(i) \
285 struct swrap_libc_symbols
287 SWRAP_SYMBOL_ENTRY (accept4);
288 SWRAP_SYMBOL_ENTRY (accept);
289 SWRAP_SYMBOL_ENTRY (bind);
290 SWRAP_SYMBOL_ENTRY (close);
291 SWRAP_SYMBOL_ENTRY (connect);
293 /* TBD: dup and dup2 to be implemented later */
294 SWRAP_SYMBOL_ENTRY (dup);
295 SWRAP_SYMBOL_ENTRY (dup2);
297 SWRAP_SYMBOL_ENTRY (fcntl);
299 SWRAP_SYMBOL_ENTRY (fcntl64);
301 SWRAP_SYMBOL_ENTRY (fopen);
303 SWRAP_SYMBOL_ENTRY (fopen64);
306 SWRAP_SYMBOL_ENTRY (eventfd);
308 SWRAP_SYMBOL_ENTRY (getpeername);
309 SWRAP_SYMBOL_ENTRY (getsockname);
310 SWRAP_SYMBOL_ENTRY (getsockopt);
311 SWRAP_SYMBOL_ENTRY (ioctl);
312 SWRAP_SYMBOL_ENTRY (listen);
313 SWRAP_SYMBOL_ENTRY (open);
315 SWRAP_SYMBOL_ENTRY (open64);
317 SWRAP_SYMBOL_ENTRY (openat);
318 SWRAP_SYMBOL_ENTRY (pipe);
319 SWRAP_SYMBOL_ENTRY (read);
320 SWRAP_SYMBOL_ENTRY (readv);
321 SWRAP_SYMBOL_ENTRY (recv);
322 SWRAP_SYMBOL_ENTRY (recvfrom);
323 SWRAP_SYMBOL_ENTRY (recvmsg);
324 SWRAP_SYMBOL_ENTRY (send);
325 SWRAP_SYMBOL_ENTRY (sendfile);
326 SWRAP_SYMBOL_ENTRY (sendmsg);
327 SWRAP_SYMBOL_ENTRY (sendto);
328 SWRAP_SYMBOL_ENTRY (setsockopt);
330 SWRAP_SYMBOL_ENTRY (signalfd);
332 SWRAP_SYMBOL_ENTRY (socket);
333 SWRAP_SYMBOL_ENTRY (socketpair);
334 #ifdef HAVE_TIMERFD_CREATE
335 SWRAP_SYMBOL_ENTRY (timerfd_create);
337 SWRAP_SYMBOL_ENTRY (write);
338 SWRAP_SYMBOL_ENTRY (writev);
340 SWRAP_SYMBOL_ENTRY (shutdown);
341 SWRAP_SYMBOL_ENTRY (select);
343 SWRAP_SYMBOL_ENTRY (pselect);
345 SWRAP_SYMBOL_ENTRY (epoll_create);
346 SWRAP_SYMBOL_ENTRY (epoll_create1);
347 SWRAP_SYMBOL_ENTRY (epoll_ctl);
348 SWRAP_SYMBOL_ENTRY (epoll_wait);
349 SWRAP_SYMBOL_ENTRY (epoll_pwait);
350 SWRAP_SYMBOL_ENTRY (poll);
352 SWRAP_SYMBOL_ENTRY (ppoll);
362 struct swrap_libc_symbols symbols;
366 static struct swrap swrap;
368 #define LIBC_NAME "libc.so"
377 swrap_str_lib (enum swrap_lib lib)
385 /* Compiler would warn us about unhandled enum value if we get here */
391 swrap_load_lib_handle (enum swrap_lib lib)
393 int flags = RTLD_LAZY;
397 #if defined(RTLD_DEEPBIND) && !defined(CLIB_SANITIZE_ADDR)
398 flags |= RTLD_DEEPBIND;
404 handle = swrap.libc.handle;
408 handle = dlopen (LIBC_SO, flags);
410 swrap.libc.handle = handle;
415 for (i = 10; i >= 0; i--)
417 char soname[256] = { 0 };
419 snprintf (soname, sizeof (soname), "libc.so.%d", i);
420 handle = dlopen (soname, flags);
427 swrap.libc.handle = handle;
434 SWRAP_LOG (SWRAP_LOG_ERROR,
435 "Failed to dlopen library: %s\n", dlerror ());
443 _swrap_bind_symbol (enum swrap_lib lib, const char *fn_name)
448 handle = swrap_load_lib_handle (lib);
450 func = dlsym (handle, fn_name);
453 SWRAP_LOG (SWRAP_LOG_ERROR,
454 "Failed to find %s: %s\n", fn_name, dlerror ());
458 SWRAP_LOG (SWRAP_LOG_TRACE,
459 "Loaded %s from %s", fn_name, swrap_str_lib (lib));
464 #define swrap_bind_symbol_libc(sym_name) \
465 SWRAP_LOCK(libc_symbol_binding); \
466 if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
467 swrap.libc.symbols._libc_##sym_name.obj = \
468 _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
470 SWRAP_UNLOCK(libc_symbol_binding)
475 * Functions especially from libc need to be loaded individually, you can't load
476 * all at once or gdb will segfault at startup. The same applies to valgrind and
477 * has probably something todo with with the linker.
478 * So we need load each function at the point it is called the first time.
481 libc_accept4 (int sockfd,
482 struct sockaddr *addr, socklen_t * addrlen, int flags)
484 swrap_bind_symbol_libc (accept4);
486 return swrap.libc.symbols._libc_accept4.f (sockfd, addr, addrlen, flags);
490 libc_accept (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
492 swrap_bind_symbol_libc (accept);
494 return swrap.libc.symbols._libc_accept.f (sockfd, addr, addrlen);
498 libc_bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
500 swrap_bind_symbol_libc (bind);
502 return swrap.libc.symbols._libc_bind.f (sockfd, addr, addrlen);
508 swrap_bind_symbol_libc (close);
510 return swrap.libc.symbols._libc_close.f (fd);
514 libc_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
516 swrap_bind_symbol_libc (connect);
518 return swrap.libc.symbols._libc_connect.f (sockfd, addr, addrlen);
522 /* TBD: dup and dup2 to be implemented later */
526 swrap_bind_symbol_libc (dup);
528 return swrap.libc.symbols._libc_dup.f (fd);
532 libc_dup2 (int oldfd, int newfd)
534 swrap_bind_symbol_libc (dup2);
536 return swrap.libc.symbols._libc_dup2.f (oldfd, newfd);
542 libc_eventfd (int count, int flags)
544 swrap_bind_symbol_libc (eventfd);
546 return swrap.libc.symbols._libc_eventfd.f (count, flags);
551 libc_vfcntl (int fd, int cmd, va_list ap)
557 swrap_bind_symbol_libc (fcntl);
559 for (i = 0; i < 4; i++)
561 args[i] = va_arg (ap, long int);
564 rc = swrap.libc.symbols._libc_fcntl.f (fd,
566 args[0], args[1], args[2], args[3]);
573 libc_vfcntl64 (int fd, int cmd, va_list ap)
579 swrap_bind_symbol_libc (fcntl64);
581 for (i = 0; i < 4; i++)
583 args[i] = va_arg (ap, long int);
586 rc = swrap.libc.symbols._libc_fcntl64.f (fd,
588 args[0], args[1], args[2],
596 libc_vioctl (int fd, int cmd, va_list ap)
602 swrap_bind_symbol_libc (ioctl);
604 for (i = 0; i < 4; i++)
606 args[i] = va_arg (ap, long int);
609 rc = swrap.libc.symbols._libc_ioctl.f (fd,
611 args[0], args[1], args[2], args[3]);
617 libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
619 swrap_bind_symbol_libc (getpeername);
621 return swrap.libc.symbols._libc_getpeername.f (sockfd, addr, addrlen);
625 libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
627 swrap_bind_symbol_libc (getsockname);
629 return swrap.libc.symbols._libc_getsockname.f (sockfd, addr, addrlen);
633 libc_getsockopt (int sockfd,
634 int level, int optname, void *optval, socklen_t * optlen)
636 swrap_bind_symbol_libc (getsockopt);
638 return swrap.libc.symbols._libc_getsockopt.f (sockfd,
640 optname, optval, optlen);
644 libc_listen (int sockfd, int backlog)
646 swrap_bind_symbol_libc (listen);
648 return swrap.libc.symbols._libc_listen.f (sockfd, backlog);
651 /* TBD: libc_read() should return ssize_t not an int */
653 libc_read (int fd, void *buf, size_t count)
655 swrap_bind_symbol_libc (read);
657 return swrap.libc.symbols._libc_read.f (fd, buf, count);
661 libc_readv (int fd, const struct iovec * iov, int iovcnt)
663 swrap_bind_symbol_libc (readv);
665 return swrap.libc.symbols._libc_readv.f (fd, iov, iovcnt);
669 libc_recv (int sockfd, void *buf, size_t len, int flags)
671 swrap_bind_symbol_libc (recv);
673 return swrap.libc.symbols._libc_recv.f (sockfd, buf, len, flags);
677 libc_recvfrom (int sockfd,
680 int flags, struct sockaddr *src_addr, socklen_t * addrlen)
682 swrap_bind_symbol_libc (recvfrom);
684 return swrap.libc.symbols._libc_recvfrom.f (sockfd,
686 len, flags, src_addr, addrlen);
690 libc_recvmsg (int sockfd, struct msghdr *msg, int flags)
692 swrap_bind_symbol_libc (recvmsg);
694 return swrap.libc.symbols._libc_recvmsg.f (sockfd, msg, flags);
698 libc_send (int sockfd, const void *buf, size_t len, int flags)
700 swrap_bind_symbol_libc (send);
702 return swrap.libc.symbols._libc_send.f (sockfd, buf, len, flags);
706 libc_sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
708 swrap_bind_symbol_libc (sendfile);
710 return swrap.libc.symbols._libc_sendfile.f (out_fd, in_fd, offset, len);
714 libc_sendmsg (int sockfd, const struct msghdr *msg, int flags)
716 swrap_bind_symbol_libc (sendmsg);
718 return swrap.libc.symbols._libc_sendmsg.f (sockfd, msg, flags);
722 libc_sendto (int sockfd,
725 int flags, const struct sockaddr *dst_addr, socklen_t addrlen)
727 swrap_bind_symbol_libc (sendto);
729 return swrap.libc.symbols._libc_sendto.f (sockfd,
731 len, flags, dst_addr, addrlen);
735 libc_setsockopt (int sockfd,
736 int level, int optname, const void *optval, socklen_t optlen)
738 swrap_bind_symbol_libc (setsockopt);
740 return swrap.libc.symbols._libc_setsockopt.f (sockfd,
742 optname, optval, optlen);
746 libc_socket (int domain, int type, int protocol)
748 swrap_bind_symbol_libc (socket);
750 return swrap.libc.symbols._libc_socket.f (domain, type, protocol);
754 libc_socketpair (int domain, int type, int protocol, int sv[2])
756 swrap_bind_symbol_libc (socketpair);
758 return swrap.libc.symbols._libc_socketpair.f (domain, type, protocol, sv);
762 libc_write (int fd, const void *buf, size_t count)
764 swrap_bind_symbol_libc (write);
766 return swrap.libc.symbols._libc_write.f (fd, buf, count);
770 libc_writev (int fd, const struct iovec * iov, int iovcnt)
772 swrap_bind_symbol_libc (writev);
774 return swrap.libc.symbols._libc_writev.f (fd, iov, iovcnt);
778 libc_shutdown (int fd, int how)
780 swrap_bind_symbol_libc (shutdown);
782 return swrap.libc.symbols._libc_shutdown.f (fd, how);
786 libc_select (int __nfds, fd_set * __restrict __readfds,
787 fd_set * __restrict __writefds,
788 fd_set * __restrict __exceptfds,
789 struct timeval *__restrict __timeout)
791 swrap_bind_symbol_libc (select);
793 return swrap.libc.symbols._libc_select.f (__nfds, __readfds,
795 __exceptfds, __timeout);
800 libc_pselect (int __nfds, fd_set * __restrict __readfds,
801 fd_set * __restrict __writefds,
802 fd_set * __restrict __exceptfds,
803 const struct timespec *__restrict __timeout,
804 const __sigset_t * __restrict __sigmask)
806 swrap_bind_symbol_libc (pselect);
808 return swrap.libc.symbols._libc_pselect.f (__nfds, __readfds,
811 __timeout, __sigmask);
816 libc_epoll_create (int __size)
818 swrap_bind_symbol_libc (epoll_create);
820 return swrap.libc.symbols._libc_epoll_create.f (__size);
824 libc_epoll_create1 (int __flags)
826 swrap_bind_symbol_libc (epoll_create1);
828 return swrap.libc.symbols._libc_epoll_create1.f (__flags);
832 libc_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
834 swrap_bind_symbol_libc (epoll_ctl);
836 return swrap.libc.symbols._libc_epoll_ctl.f (__epfd, __op, __fd, __event);
840 libc_epoll_wait (int __epfd, struct epoll_event *__events,
841 int __maxevents, int __timeout)
843 swrap_bind_symbol_libc (epoll_wait);
845 return swrap.libc.symbols._libc_epoll_wait.f (__epfd, __events,
846 __maxevents, __timeout);
850 libc_epoll_pwait (int __epfd, struct epoll_event *__events,
851 int __maxevents, int __timeout, const __sigset_t * __ss)
853 swrap_bind_symbol_libc (epoll_pwait);
855 return swrap.libc.symbols._libc_epoll_pwait.f (__epfd, __events,
856 __maxevents, __timeout,
861 libc_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
863 swrap_bind_symbol_libc (poll);
865 return swrap.libc.symbols._libc_poll.f (__fds, __nfds, __timeout);
870 libc_ppoll (struct pollfd *__fds, nfds_t __nfds,
871 const struct timespec *__timeout, const __sigset_t * __ss)
873 swrap_bind_symbol_libc (ppoll);
875 return swrap.libc.symbols._libc_ppoll.f (__fds, __nfds, __timeout, __ss);
880 swrap_thread_prepare (void)
886 swrap_thread_parent (void)
892 swrap_thread_child (void)
897 /****************************
899 ***************************/
901 swrap_constructor (void)
904 * If we hold a lock and the application forks, then the child
905 * is not able to unlock the mutex and we are in a deadlock.
906 * This should prevent such deadlocks.
908 pthread_atfork (&swrap_thread_prepare,
909 &swrap_thread_parent, &swrap_thread_child);
912 /****************************
914 ***************************/
917 * This function is called when the library is unloaded and makes sure that
918 * sockets get closed and the unix file for the socket are unlinked.
921 swrap_destructor (void)
923 if (swrap.libc.handle != NULL)
925 dlclose (swrap.libc.handle);
927 if (swrap.libc.socket_handle)
929 dlclose (swrap.libc.socket_handle);
934 * fd.io coding-style-patch-verification: ON
937 * eval: (c-set-style "gnu")