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 <vppinfra/clib.h>
68 #include <vcl/ldp_socket_wrapper.h>
80 /* Macros for accessing mutexes */
81 #define SWRAP_LOCK(m) do { \
82 pthread_mutex_lock(&(m ## _mutex)); \
85 #define SWRAP_UNLOCK(m) do { \
86 pthread_mutex_unlock(&(m ## _mutex)); \
89 /* Add new global locks here please */
90 #define SWRAP_LOCK_ALL \
91 SWRAP_LOCK(libc_symbol_binding); \
93 #define SWRAP_UNLOCK_ALL \
94 SWRAP_UNLOCK(libc_symbol_binding); \
98 /* The mutex for accessing the global libc.symbols */
99 static pthread_mutex_t libc_symbol_binding_mutex = PTHREAD_MUTEX_INITIALIZER;
101 /* Function prototypes */
104 #define SWRAP_LOG(...)
106 static unsigned int swrap_log_lvl = SWRAP_LOG_WARN;
109 swrap_log (enum swrap_dbglvl_e dbglvl, const char *func,
110 const char *format, ...)
111 PRINTF_ATTRIBUTE (3, 4);
112 #define SWRAP_LOG(dbglvl, ...) swrap_log((dbglvl), __func__, __VA_ARGS__)
115 swrap_log (enum swrap_dbglvl_e dbglvl,
116 const char *func, const char *format, ...)
121 va_start (va, format);
122 vsnprintf (buffer, sizeof (buffer), format, va);
125 if (dbglvl <= swrap_log_lvl)
129 case SWRAP_LOG_ERROR:
131 "SWRAP_ERROR(%d) - %s: %s\n",
132 (int) getpid (), func, buffer);
136 "SWRAP_WARN(%d) - %s: %s\n",
137 (int) getpid (), func, buffer);
139 case SWRAP_LOG_DEBUG:
141 "SWRAP_DEBUG(%d) - %s: %s\n",
142 (int) getpid (), func, buffer);
144 case SWRAP_LOG_TRACE:
146 "SWRAP_TRACE(%d) - %s: %s\n",
147 (int) getpid (), func, buffer);
155 /*********************************************************
156 * SWRAP LOADING LIBC FUNCTIONS
157 *********************************************************/
159 typedef int (*__libc_accept4) (int sockfd,
160 struct sockaddr * addr,
161 socklen_t * addrlen, int flags);
162 typedef int (*__libc_accept) (int sockfd,
163 struct sockaddr * addr, socklen_t * addrlen);
164 typedef int (*__libc_bind) (int sockfd,
165 const struct sockaddr * addr, socklen_t addrlen);
166 typedef int (*__libc_close) (int fd);
167 typedef int (*__libc_connect) (int sockfd,
168 const struct sockaddr * addr,
172 /* TBD: dup and dup2 to be implemented later */
173 typedef int (*__libc_dup) (int fd);
174 typedef int (*__libc_dup2) (int oldfd, int newfd);
177 typedef int (*__libc_fcntl) (int fd, int cmd, ...);
179 typedef int (*__libc_fcntl64) (int fd, int cmd, ...);
181 typedef FILE *(*__libc_fopen) (const char *name, const char *mode);
183 typedef FILE *(*__libc_fopen64) (const char *name, const char *mode);
186 typedef int (*__libc_eventfd) (int count, int flags);
188 typedef int (*__libc_getpeername) (int sockfd,
189 struct sockaddr * addr,
190 socklen_t * addrlen);
191 typedef int (*__libc_getsockname) (int sockfd,
192 struct sockaddr * addr,
193 socklen_t * addrlen);
194 typedef int (*__libc_getsockopt) (int sockfd,
197 void *optval, socklen_t * optlen);
198 typedef int (*__libc_ioctl) (int d, unsigned long int request, ...);
199 typedef int (*__libc_listen) (int sockfd, int backlog);
200 typedef int (*__libc_open) (const char *pathname, int flags, mode_t mode);
202 typedef int (*__libc_open64) (const char *pathname, int flags, mode_t mode);
203 #endif /* HAVE_OPEN64 */
204 typedef int (*__libc_openat) (int dirfd, const char *path, int flags, ...);
205 typedef int (*__libc_pipe) (int pipefd[2]);
206 typedef int (*__libc_read) (int fd, void *buf, size_t count);
207 typedef ssize_t (*__libc_readv) (int fd, const struct iovec * iov,
209 typedef int (*__libc_recv) (int sockfd, void *buf, size_t len, int flags);
210 typedef int (*__libc_recvfrom) (int sockfd,
214 struct sockaddr * src_addr,
215 socklen_t * addrlen);
216 typedef int (*__libc_recvmsg) (int sockfd, const struct msghdr * msg,
218 typedef int (*__libc_send) (int sockfd, const void *buf, size_t len,
220 typedef ssize_t (*__libc_sendfile) (int out_fd, int in_fd, off_t * offset,
222 typedef int (*__libc_sendmsg) (int sockfd, const struct msghdr * msg,
224 typedef int (*__libc_sendto) (int sockfd, const void *buf, size_t len,
225 int flags, const struct sockaddr * dst_addr,
227 typedef int (*__libc_setsockopt) (int sockfd, int level, int optname,
228 const void *optval, socklen_t optlen);
230 typedef int (*__libc_signalfd) (int fd, const sigset_t * mask, int flags);
232 typedef int (*__libc_socket) (int domain, int type, int protocol);
233 typedef int (*__libc_socketpair) (int domain, int type, int protocol,
235 #ifdef HAVE_TIMERFD_CREATE
236 typedef int (*__libc_timerfd_create) (int clockid, int flags);
238 typedef ssize_t (*__libc_write) (int fd, const void *buf, size_t count);
239 typedef ssize_t (*__libc_writev) (int fd, const struct iovec * iov,
242 typedef int (*__libc_shutdown) (int fd, int how);
244 typedef int (*__libc_select) (int __nfds, fd_set * __restrict __readfds,
245 fd_set * __restrict __writefds,
246 fd_set * __restrict __exceptfds,
247 struct timeval * __restrict __timeout);
250 typedef int (*__libc_pselect) (int __nfds, fd_set * __restrict __readfds,
251 fd_set * __restrict __writefds,
252 fd_set * __restrict __exceptfds,
253 const struct timespec * __restrict __timeout,
254 const __sigset_t * __restrict __sigmask);
257 typedef int (*__libc_epoll_create) (int __size);
259 typedef int (*__libc_epoll_create1) (int __flags);
261 typedef int (*__libc_epoll_ctl) (int __epfd, int __op, int __fd,
262 struct epoll_event * __event);
264 typedef int (*__libc_epoll_wait) (int __epfd, struct epoll_event * __events,
265 int __maxevents, int __timeout);
267 typedef int (*__libc_epoll_pwait) (int __epfd, struct epoll_event * __events,
268 int __maxevents, int __timeout,
269 const __sigset_t * __ss);
271 typedef int (*__libc_poll) (struct pollfd * __fds, nfds_t __nfds,
275 typedef int (*__libc_ppoll) (struct pollfd * __fds, nfds_t __nfds,
276 const struct timespec * __timeout,
277 const __sigset_t * __ss);
281 #define SWRAP_SYMBOL_ENTRY(i) \
287 struct swrap_libc_symbols
289 SWRAP_SYMBOL_ENTRY (accept4);
290 SWRAP_SYMBOL_ENTRY (accept);
291 SWRAP_SYMBOL_ENTRY (bind);
292 SWRAP_SYMBOL_ENTRY (close);
293 SWRAP_SYMBOL_ENTRY (connect);
295 /* TBD: dup and dup2 to be implemented later */
296 SWRAP_SYMBOL_ENTRY (dup);
297 SWRAP_SYMBOL_ENTRY (dup2);
299 SWRAP_SYMBOL_ENTRY (fcntl);
301 SWRAP_SYMBOL_ENTRY (fcntl64);
303 SWRAP_SYMBOL_ENTRY (fopen);
305 SWRAP_SYMBOL_ENTRY (fopen64);
308 SWRAP_SYMBOL_ENTRY (eventfd);
310 SWRAP_SYMBOL_ENTRY (getpeername);
311 SWRAP_SYMBOL_ENTRY (getsockname);
312 SWRAP_SYMBOL_ENTRY (getsockopt);
313 SWRAP_SYMBOL_ENTRY (ioctl);
314 SWRAP_SYMBOL_ENTRY (listen);
315 SWRAP_SYMBOL_ENTRY (open);
317 SWRAP_SYMBOL_ENTRY (open64);
319 SWRAP_SYMBOL_ENTRY (openat);
320 SWRAP_SYMBOL_ENTRY (pipe);
321 SWRAP_SYMBOL_ENTRY (read);
322 SWRAP_SYMBOL_ENTRY (readv);
323 SWRAP_SYMBOL_ENTRY (recv);
324 SWRAP_SYMBOL_ENTRY (recvfrom);
325 SWRAP_SYMBOL_ENTRY (recvmsg);
326 SWRAP_SYMBOL_ENTRY (send);
327 SWRAP_SYMBOL_ENTRY (sendfile);
328 SWRAP_SYMBOL_ENTRY (sendmsg);
329 SWRAP_SYMBOL_ENTRY (sendto);
330 SWRAP_SYMBOL_ENTRY (setsockopt);
332 SWRAP_SYMBOL_ENTRY (signalfd);
334 SWRAP_SYMBOL_ENTRY (socket);
335 SWRAP_SYMBOL_ENTRY (socketpair);
336 #ifdef HAVE_TIMERFD_CREATE
337 SWRAP_SYMBOL_ENTRY (timerfd_create);
339 SWRAP_SYMBOL_ENTRY (write);
340 SWRAP_SYMBOL_ENTRY (writev);
342 SWRAP_SYMBOL_ENTRY (shutdown);
343 SWRAP_SYMBOL_ENTRY (select);
345 SWRAP_SYMBOL_ENTRY (pselect);
347 SWRAP_SYMBOL_ENTRY (epoll_create);
348 SWRAP_SYMBOL_ENTRY (epoll_create1);
349 SWRAP_SYMBOL_ENTRY (epoll_ctl);
350 SWRAP_SYMBOL_ENTRY (epoll_wait);
351 SWRAP_SYMBOL_ENTRY (epoll_pwait);
352 SWRAP_SYMBOL_ENTRY (poll);
354 SWRAP_SYMBOL_ENTRY (ppoll);
364 struct swrap_libc_symbols symbols;
368 static struct swrap swrap;
370 #define LIBC_NAME "libc.so"
379 swrap_str_lib (enum swrap_lib lib)
387 /* Compiler would warn us about unhandled enum value if we get here */
393 swrap_load_lib_handle (enum swrap_lib lib)
395 int flags = RTLD_LAZY;
399 #if defined(RTLD_DEEPBIND) && !defined(CLIB_SANITIZE_ADDR)
400 flags |= RTLD_DEEPBIND;
406 handle = swrap.libc.handle;
410 handle = dlopen (LIBC_SO, flags);
412 swrap.libc.handle = handle;
417 for (i = 10; i >= 0; i--)
419 char soname[256] = { 0 };
421 snprintf (soname, sizeof (soname), "libc.so.%d", i);
422 handle = dlopen (soname, flags);
429 swrap.libc.handle = handle;
436 SWRAP_LOG (SWRAP_LOG_ERROR,
437 "Failed to dlopen library: %s\n", dlerror ());
445 _swrap_bind_symbol (enum swrap_lib lib, const char *fn_name)
450 handle = swrap_load_lib_handle (lib);
452 func = dlsym (handle, fn_name);
455 SWRAP_LOG (SWRAP_LOG_ERROR,
456 "Failed to find %s: %s\n", fn_name, dlerror ());
460 SWRAP_LOG (SWRAP_LOG_TRACE,
461 "Loaded %s from %s", fn_name, swrap_str_lib (lib));
466 #define swrap_bind_symbol_libc(sym_name) \
467 SWRAP_LOCK(libc_symbol_binding); \
468 if (swrap.libc.symbols._libc_##sym_name.obj == NULL) { \
469 swrap.libc.symbols._libc_##sym_name.obj = \
470 _swrap_bind_symbol(SWRAP_LIBC, #sym_name); \
472 SWRAP_UNLOCK(libc_symbol_binding)
477 * Functions especially from libc need to be loaded individually, you can't load
478 * all at once or gdb will segfault at startup. The same applies to valgrind and
479 * has probably something todo with with the linker.
480 * So we need load each function at the point it is called the first time.
483 libc_accept4 (int sockfd,
484 struct sockaddr *addr, socklen_t * addrlen, int flags)
486 swrap_bind_symbol_libc (accept4);
488 return swrap.libc.symbols._libc_accept4.f (sockfd, addr, addrlen, flags);
492 libc_accept (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
494 swrap_bind_symbol_libc (accept);
496 return swrap.libc.symbols._libc_accept.f (sockfd, addr, addrlen);
500 libc_bind (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
502 swrap_bind_symbol_libc (bind);
504 return swrap.libc.symbols._libc_bind.f (sockfd, addr, addrlen);
510 swrap_bind_symbol_libc (close);
512 return swrap.libc.symbols._libc_close.f (fd);
516 libc_connect (int sockfd, const struct sockaddr *addr, socklen_t addrlen)
518 swrap_bind_symbol_libc (connect);
520 return swrap.libc.symbols._libc_connect.f (sockfd, addr, addrlen);
524 /* TBD: dup and dup2 to be implemented later */
528 swrap_bind_symbol_libc (dup);
530 return swrap.libc.symbols._libc_dup.f (fd);
534 libc_dup2 (int oldfd, int newfd)
536 swrap_bind_symbol_libc (dup2);
538 return swrap.libc.symbols._libc_dup2.f (oldfd, newfd);
544 libc_eventfd (int count, int flags)
546 swrap_bind_symbol_libc (eventfd);
548 return swrap.libc.symbols._libc_eventfd.f (count, flags);
553 libc_vfcntl (int fd, int cmd, va_list ap)
555 swrap_bind_symbol_libc (fcntl);
556 return swrap.libc.symbols._libc_fcntl.f (fd, cmd, va_arg (ap, long int));
561 libc_vfcntl64 (int fd, int cmd, va_list ap)
563 swrap_bind_symbol_libc (fcntl64);
564 return swrap.libc.symbols._libc_fcntl64.f (fd, cmd, va_arg (ap, long int));
569 libc_vioctl (int fd, int cmd, va_list ap)
575 swrap_bind_symbol_libc (ioctl);
577 for (i = 0; i < 4; i++)
579 args[i] = va_arg (ap, long int);
582 rc = swrap.libc.symbols._libc_ioctl.f (fd,
584 args[0], args[1], args[2], args[3]);
590 libc_getpeername (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
592 swrap_bind_symbol_libc (getpeername);
594 return swrap.libc.symbols._libc_getpeername.f (sockfd, addr, addrlen);
598 libc_getsockname (int sockfd, struct sockaddr *addr, socklen_t * addrlen)
600 swrap_bind_symbol_libc (getsockname);
602 return swrap.libc.symbols._libc_getsockname.f (sockfd, addr, addrlen);
606 libc_getsockopt (int sockfd,
607 int level, int optname, void *optval, socklen_t * optlen)
609 swrap_bind_symbol_libc (getsockopt);
611 return swrap.libc.symbols._libc_getsockopt.f (sockfd,
613 optname, optval, optlen);
617 libc_listen (int sockfd, int backlog)
619 swrap_bind_symbol_libc (listen);
621 return swrap.libc.symbols._libc_listen.f (sockfd, backlog);
624 /* TBD: libc_read() should return ssize_t not an int */
626 libc_read (int fd, void *buf, size_t count)
628 swrap_bind_symbol_libc (read);
630 return swrap.libc.symbols._libc_read.f (fd, buf, count);
634 libc_readv (int fd, const struct iovec * iov, int iovcnt)
636 swrap_bind_symbol_libc (readv);
638 return swrap.libc.symbols._libc_readv.f (fd, iov, iovcnt);
642 libc_recv (int sockfd, void *buf, size_t len, int flags)
644 swrap_bind_symbol_libc (recv);
646 return swrap.libc.symbols._libc_recv.f (sockfd, buf, len, flags);
650 libc_recvfrom (int sockfd,
653 int flags, struct sockaddr *src_addr, socklen_t * addrlen)
655 swrap_bind_symbol_libc (recvfrom);
657 return swrap.libc.symbols._libc_recvfrom.f (sockfd,
659 len, flags, src_addr, addrlen);
663 libc_recvmsg (int sockfd, struct msghdr *msg, int flags)
665 swrap_bind_symbol_libc (recvmsg);
667 return swrap.libc.symbols._libc_recvmsg.f (sockfd, msg, flags);
671 libc_send (int sockfd, const void *buf, size_t len, int flags)
673 swrap_bind_symbol_libc (send);
675 return swrap.libc.symbols._libc_send.f (sockfd, buf, len, flags);
679 libc_sendfile (int out_fd, int in_fd, off_t * offset, size_t len)
681 swrap_bind_symbol_libc (sendfile);
683 return swrap.libc.symbols._libc_sendfile.f (out_fd, in_fd, offset, len);
687 libc_sendmsg (int sockfd, const struct msghdr *msg, int flags)
689 swrap_bind_symbol_libc (sendmsg);
691 return swrap.libc.symbols._libc_sendmsg.f (sockfd, msg, flags);
695 libc_sendto (int sockfd,
698 int flags, const struct sockaddr *dst_addr, socklen_t addrlen)
700 swrap_bind_symbol_libc (sendto);
702 return swrap.libc.symbols._libc_sendto.f (sockfd,
704 len, flags, dst_addr, addrlen);
708 libc_setsockopt (int sockfd,
709 int level, int optname, const void *optval, socklen_t optlen)
711 swrap_bind_symbol_libc (setsockopt);
713 return swrap.libc.symbols._libc_setsockopt.f (sockfd,
715 optname, optval, optlen);
719 libc_socket (int domain, int type, int protocol)
721 swrap_bind_symbol_libc (socket);
723 return swrap.libc.symbols._libc_socket.f (domain, type, protocol);
727 libc_socketpair (int domain, int type, int protocol, int sv[2])
729 swrap_bind_symbol_libc (socketpair);
731 return swrap.libc.symbols._libc_socketpair.f (domain, type, protocol, sv);
735 libc_write (int fd, const void *buf, size_t count)
737 swrap_bind_symbol_libc (write);
739 return swrap.libc.symbols._libc_write.f (fd, buf, count);
743 libc_writev (int fd, const struct iovec * iov, int iovcnt)
745 swrap_bind_symbol_libc (writev);
747 return swrap.libc.symbols._libc_writev.f (fd, iov, iovcnt);
751 libc_shutdown (int fd, int how)
753 swrap_bind_symbol_libc (shutdown);
755 return swrap.libc.symbols._libc_shutdown.f (fd, how);
759 libc_select (int __nfds, fd_set * __restrict __readfds,
760 fd_set * __restrict __writefds,
761 fd_set * __restrict __exceptfds,
762 struct timeval *__restrict __timeout)
764 swrap_bind_symbol_libc (select);
766 return swrap.libc.symbols._libc_select.f (__nfds, __readfds,
768 __exceptfds, __timeout);
773 libc_pselect (int __nfds, fd_set * __restrict __readfds,
774 fd_set * __restrict __writefds,
775 fd_set * __restrict __exceptfds,
776 const struct timespec *__restrict __timeout,
777 const __sigset_t * __restrict __sigmask)
779 swrap_bind_symbol_libc (pselect);
781 return swrap.libc.symbols._libc_pselect.f (__nfds, __readfds,
784 __timeout, __sigmask);
789 libc_epoll_create (int __size)
791 swrap_bind_symbol_libc (epoll_create);
793 return swrap.libc.symbols._libc_epoll_create.f (__size);
797 libc_epoll_create1 (int __flags)
799 swrap_bind_symbol_libc (epoll_create1);
801 return swrap.libc.symbols._libc_epoll_create1.f (__flags);
805 libc_epoll_ctl (int __epfd, int __op, int __fd, struct epoll_event *__event)
807 swrap_bind_symbol_libc (epoll_ctl);
809 return swrap.libc.symbols._libc_epoll_ctl.f (__epfd, __op, __fd, __event);
813 libc_epoll_wait (int __epfd, struct epoll_event *__events,
814 int __maxevents, int __timeout)
816 swrap_bind_symbol_libc (epoll_wait);
818 return swrap.libc.symbols._libc_epoll_wait.f (__epfd, __events,
819 __maxevents, __timeout);
823 libc_epoll_pwait (int __epfd, struct epoll_event *__events,
824 int __maxevents, int __timeout, const __sigset_t * __ss)
826 swrap_bind_symbol_libc (epoll_pwait);
828 return swrap.libc.symbols._libc_epoll_pwait.f (__epfd, __events,
829 __maxevents, __timeout,
834 libc_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
836 swrap_bind_symbol_libc (poll);
838 return swrap.libc.symbols._libc_poll.f (__fds, __nfds, __timeout);
843 libc_ppoll (struct pollfd *__fds, nfds_t __nfds,
844 const struct timespec *__timeout, const __sigset_t * __ss)
846 swrap_bind_symbol_libc (ppoll);
848 return swrap.libc.symbols._libc_ppoll.f (__fds, __nfds, __timeout, __ss);
853 swrap_thread_prepare (void)
859 swrap_thread_parent (void)
865 swrap_thread_child (void)
870 /****************************
872 ***************************/
874 swrap_constructor (void)
877 * If we hold a lock and the application forks, then the child
878 * is not able to unlock the mutex and we are in a deadlock.
879 * This should prevent such deadlocks.
881 pthread_atfork (&swrap_thread_prepare,
882 &swrap_thread_parent, &swrap_thread_child);
885 /****************************
887 ***************************/
890 * This function is called when the library is unloaded and makes sure that
891 * sockets get closed and the unix file for the socket are unlinked.
894 swrap_destructor (void)
896 if (swrap.libc.handle != NULL)
898 dlclose (swrap.libc.handle);
900 if (swrap.libc.socket_handle)
902 dlclose (swrap.libc.socket_handle);
907 * fd.io coding-style-patch-verification: ON
910 * eval: (c-set-style "gnu")