├── API ├── CMakeLists.txt ├── COPYING ├── Makefile ├── README ├── README.md ├── ancillary.h ├── evclient.c ├── evserver.c ├── fd_recv.c ├── fd_send.c └── test.c /API: -------------------------------------------------------------------------------- 1 | This library provide an easy interface to the black magic that can be done 2 | on Unix domain sockets, like passing file descriptors from one process to 3 | another. 4 | 5 | Programs that uses this library should include the ancillary.h header file. 6 | Nothing else is required. 7 | 8 | All functions of this library require the following header: 9 | 10 | #include 11 | 12 | At this time, the only ancillary data defined by the Single Unix 13 | Specification (v3) is file descriptors. 14 | 15 | Passing file descriptors 16 | 17 | int ancil_send_fd(socket, file_descriptor) 18 | int socket: the Unix socket 19 | int file_descriptor: the file descriptor 20 | Return value: 0 for success, -1 for failure. 21 | 22 | Sends one file descriptor on a socket. 23 | In case of failure, errno is set; the possible values are the ones of the 24 | sendmsg(2) system call. 25 | 26 | 27 | int ancil_recv_fd(socket, file_descriptor) 28 | int socket: the Unix socket 29 | int *file_descriptor: pointer to the returned file descriptor 30 | Return value: 0 for success, -1 for failure 31 | 32 | Receives one file descriptor from a socket. 33 | In case of success, the file descriptor is stored in the integer pointed 34 | to by file_descriptor. 35 | In case of failure, errno is set; the possible values are the ones of the 36 | recvmsg(2) system call. 37 | The behavior is undefined if the recv_fd does not match a send_fd* on the 38 | other side. 39 | 40 | 41 | int ancil_send_fds(socket, file_descriptors, num_file_descriptors) 42 | int socket: the Unix socket 43 | const int *file_descriptors: array of file descriptors 44 | unsigned num_file_descriptors: number of file descriptors 45 | Return value: 0 for success, -1 for failure 46 | 47 | Sends several file descriptors on a socket. 48 | In case of failure, errno is set; the possible values are the ones of the 49 | sendmsg(2) system call. 50 | The maximum number of file descriptors that can be sent using this 51 | function is ANCIL_MAX_N_FDS; the behavior is undefined in case of 52 | overflow, probably a stack corruption. 53 | 54 | 55 | int ancil_recv_fds(socket, file_descriptors, num_file_descriptors) 56 | int socket: the Unix socket 57 | int *file_descriptors: return array of file descriptors 58 | unsigned num_file_descriptors: number of file descriptors 59 | Return value: number of received fd for success, -1 for failure 60 | 61 | Receives several file descriptors from a socket, no more than 62 | num_file_descriptors. 63 | In case of success, the received file descriptors are stored in the array 64 | pointed to by file_descriptors. 65 | In case of failure, errno is set; the possible values are the ones of the 66 | recvmsg(2) system call. 67 | The maximum number of file descriptors that can be received using this 68 | function is ANCIL_MAX_N_FDS; the behavior is undefined in case of 69 | overflow, probably a stack corruption. 70 | The behavior is undefined if the recv_fds does not match a send_fd* on 71 | the other side, or if the number of received file descriptors is more than 72 | num_file_descriptors. 73 | 74 | 75 | int ancil_send_fds_with_buffer(socket, fds, num, buffer) 76 | int socket: the Unix socket 77 | const int *fds: array of file descriptors 78 | unsigned num: number of file descriptors 79 | void *buffer: buffer to hold the system data structures 80 | Return value: 0 for success, -1 for failure 81 | 82 | Sends several file descriptors on a socket. 83 | In case of failure, errno is set; the possible values are the ones of the 84 | sendmsg(2) system call. 85 | The buffer argument must point to a memory area large enough to hold the 86 | system data structures, see ANCIL_FD_BUFFER. 87 | 88 | 89 | int ancil_send_fds_with_buffer(socket, fds, num, buffer) 90 | int socket: the Unix socket 91 | int *fds: return array of file descriptors 92 | unsigned num: number of file descriptors 93 | void *buffer: buffer to hold the system data structures 94 | Return value: number of received fd for success, -1 for failure 95 | 96 | Receives several file descriptors from a socket, no more than 97 | num_file_descriptors. 98 | In case of success, the received file descriptors are stored in the array 99 | pointed to by file_descriptors. 100 | In case of failure, errno is set; the possible values are the ones of the 101 | recvmsg(2) system call. 102 | The behavior is undefined if the recv_fds does not match a send_fd* on 103 | the other side, or if the number of received file descriptors is more than 104 | num_file_descriptors. 105 | The buffer argument must point to a memory area large enough to hold the 106 | system data structures, see ANCIL_FD_BUFFER. 107 | 108 | 109 | ANCIL_MAX_N_FDS 110 | 111 | Maximum number of file descriptors that can be sent with the sent_fds and 112 | recv_fds functions. If you have to send more at once, use the 113 | *_with_buffer versions. The value is enough to send "quite a few" file 114 | descriptors. 115 | 116 | 117 | ANCIL_FD_BUFFER(n) 118 | int n: number of file descriptors 119 | 120 | Expands to a structure data type large enough to hold the system data 121 | structures for n file descriptors. So the address of a variable declared 122 | of type ANCIL_FD_BUFFER(n) is suitable as the buffer argument for 123 | *_with_buffer on n file descriptors. 124 | To use this macro, you need and . Bevare: with 125 | Solaris, the _XPG4_2 macro must be defined before sys/socket is included. 126 | 127 | 128 | Tuning the compilation 129 | 130 | This library is designed to be included in projects, not installed in 131 | /usr/lib. If your project does not use some of the functions, the 132 | TUNE_OPTS variable in the Makefile allows not to build them. It is a list 133 | of proprocessor options: 134 | 135 | -DNDEBUG: turn assertions off (see assert(3)) 136 | -DSPARE_SEND_FDS: do not build ancil_send_fds 137 | -DSPARE_SEND_FD: do not build ancil_send_fd 138 | -DSPARE_RECV_FDS: do not build ancil_recv_fds 139 | -DSPARE_RECV_FD: do not build ancil_recv_fd 140 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | cmake_minimum_required(VERSION 3.4.1) 3 | project(ancillary C) 4 | 5 | set(CMAKE_C_STANDARD 11) 6 | 7 | set(LIB_ANCILLARY_DIR ${CMAKE_CURRENT_SOURCE_DIR} CACHE INTERNAL "ancillary library path" FORCE) 8 | 9 | include_directories(.) 10 | 11 | add_library( ancillary STATIC ancillary.h fd_recv.c fd_send.c ) 12 | 13 | option(libancillary_build_test OFF) 14 | 15 | if (libancillary_build_test) 16 | add_executable( test_exe test.c ) 17 | target_link_libraries( test_exe ancillary ) 18 | 19 | add_executable( evclient evclient.c ) 20 | target_link_libraries( evclient ancillary ) 21 | 22 | add_executable( evserver evserver.c ) 23 | target_link_libraries( evserver ancillary ) 24 | endif (libancillary_build_test) 25 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without 2 | modification, are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, 5 | this list of conditions and the following disclaimer. 6 | 2. Redistributions in binary form must reproduce the above copyright 7 | notice, this list of conditions and the following disclaimer in the 8 | documentation and/or other materials provided with the distribution. 9 | 3. The name of the author may not be used to endorse or promote products 10 | derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 13 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 14 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 15 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 16 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 17 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 18 | OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 19 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 20 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ########################################################################### 2 | # libancillary - black magic on Unix domain sockets 3 | # (C) Nicolas George 4 | # Makefile - guess what 5 | ########################################################################### 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # 1. Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # 2. Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in the 14 | # documentation and/or other materials provided with the distribution. 15 | # 3. The name of the author may not be used to endorse or promote products 16 | # derived from this software without specific prior written permission. 17 | # 18 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 19 | # WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 20 | # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 21 | # EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 23 | # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 24 | # OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 26 | # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 27 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | CC=gcc 30 | CFLAGS=-Wall -g -O0 31 | LDFLAGS= -g 32 | LIBS= 33 | AR=ar 34 | RANLIB=ranlib 35 | RM=rm 36 | CP=cp 37 | MKDIR=mkdir 38 | TAR=tar 39 | GZIP=gzip -9 40 | 41 | NAME=libancillary 42 | DISTRIBUTION=API COPYING Makefile ancillary.h fd_send.c fd_recv.c test.c 43 | VERSION=0.9.1 44 | 45 | OBJECTS=fd_send.o fd_recv.o 46 | 47 | TUNE_OPTS=#-DNDEBUG 48 | #TUNE_OPTS=-DNDEBUG 49 | #TUNE_OPTS=-DNDEBUG \ 50 | -DSPARE_SEND_FDS -DSPARE_SEND_FD -DSPARE_RECV_FDS -DSPARE_RECV_FD 51 | 52 | .c.o: 53 | $(CC) -c $(CFLAGS) $(TUNE_OPTS) $< 54 | 55 | all: libancillary.a test evserver evclient 56 | 57 | libancillary.a: $(OBJECTS) 58 | $(AR) cr $@ $(OBJECTS) 59 | $(RANLIB) $@ 60 | 61 | fd_send.o: ancillary.h 62 | fd_recv.o: ancillary.h 63 | 64 | test: test.c libancillary.a 65 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) test.c libancillary.a $(LIBS) 66 | 67 | clean: 68 | -$(RM) -f *.o *.a test evserver evclient 69 | 70 | dist: 71 | $(MKDIR) $(NAME)-$(VERSION) 72 | $(CP) $(DISTRIBUTION) $(NAME)-$(VERSION) 73 | $(TAR) -cf - $(NAME)-$(VERSION) | $(GZIP) > $(NAME)-$(VERSION).tar.gz 74 | $(RM) -rf $(NAME)-$(VERSION) 75 | 76 | evclient: evclient.c libancillary.a 77 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) -L. evclient.c -lancillary $(LIBS) 78 | 79 | evserver: evserver.c libancillary.a 80 | $(CC) -o $@ $(CFLAGS) $(LDFLAGS) -L. evserver.c -lancillary $(LIBS) 81 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This example shows how eventfd(2) file descriptors can be shared 2 | over Unix sockets by processes which have no common ancestor. 3 | 4 | This problem appears frequently if one needs a poll(2) compatible 5 | notification mechanism; for instance when using queues in shared memory, 6 | to signal the reader that data is available. 7 | 8 | Usage: 9 | 10 | make 11 | run evserver in one window 12 | run evclient in another window 13 | 14 | 15 | 16 | This code uses the libancil library: http://www.normalesup.org/~george/comp/libancillary/ 17 | 18 | Michael Haberler 1/2014 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | [![Build Status](https://jenkins.stiwoll.mah.priv.at/job/libancillary/badge/icon)](https://jenkins.stiwoll.mah.priv.at/job/libancillary/) 4 | -------------------------------------------------------------------------------- /ancillary.h: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * libancillary - black magic on Unix domain sockets 3 | * (C) Nicolas George 4 | * ancillary.h - public header 5 | ***************************************************************************/ 6 | 7 | /* 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. The name of the author may not be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef ANCILLARY_H__ 32 | #define ANCILLARY_H__ 33 | 34 | #ifdef __cplusplus 35 | extern "C" { 36 | #endif 37 | 38 | /*************************************************************************** 39 | * Start of the readable part. 40 | ***************************************************************************/ 41 | 42 | #define ANCIL_MAX_N_FDS 960 43 | /* 44 | * Maximum number of fds that can be sent or received using the "esay" 45 | * functions; this is so that all can fit in one page. 46 | */ 47 | 48 | extern int 49 | ancil_send_fds_with_buffer(int, const int *, unsigned, void *); 50 | /* 51 | * ancil_send_fds_with_buffer(sock, n_fds, fds, buffer) 52 | * 53 | * Sends the file descriptors in the array pointed by fds, of length n_fds 54 | * on the socket sock. 55 | * buffer is a writeable memory area large enough to hold the required data 56 | * structures. 57 | * Returns: -1 and errno in case of error, 0 in case of success. 58 | */ 59 | 60 | extern int 61 | ancil_recv_fds_with_buffer(int, int *, unsigned, void *); 62 | /* 63 | * ancil_recv_fds_with_buffer(sock, n_fds, fds, buffer) 64 | * 65 | * Receives *n_fds file descriptors into the array pointed by fds 66 | * from the socket sock. 67 | * buffer is a writeable memory area large enough to hold the required data 68 | * structures. 69 | * Returns: -1 and errno in case of error, the actual number of received fd 70 | * in case of success 71 | */ 72 | 73 | #define ANCIL_FD_BUFFER(n) \ 74 | struct { \ 75 | struct cmsghdr h; \ 76 | int fd[n]; \ 77 | } 78 | /* ANCIL_FD_BUFFER(n) 79 | * 80 | * A structure type suitable to be used as buffer for n file descriptors. 81 | * Requires . 82 | * Example: 83 | * ANCIL_FD_BUFFER(42) buffer; 84 | * ancil_recv_fds_with_buffer(sock, 42, my_fds, &buffer); 85 | */ 86 | 87 | extern int 88 | ancil_send_fds(int, const int *, unsigned); 89 | /* 90 | * ancil_send_fds(sock, n_fds, fds) 91 | * 92 | * Sends the file descriptors in the array pointed by fds, of length n_fds 93 | * on the socket sock. 94 | * n_fds must not be greater than ANCIL_MAX_N_FDS. 95 | * Returns: -1 and errno in case of error, 0 in case of success. 96 | */ 97 | 98 | extern int 99 | ancil_recv_fds(int, int *, unsigned); 100 | /* 101 | * ancil_recv_fds(sock, n_fds, fds) 102 | * 103 | * Receives *n_fds file descriptors into the array pointed by fds 104 | * from the socket sock. 105 | * *n_fds must not be greater than ANCIL_MAX_N_FDS. 106 | * Returns: -1 and errno in case of error, the actual number of received fd 107 | * in case of success. 108 | */ 109 | 110 | 111 | extern int 112 | ancil_send_fd(int, int); 113 | /* ancil_recv_fd(sock, fd); 114 | * 115 | * Sends the file descriptor fd on the socket sock. 116 | * Returns : -1 and errno in case of error, 0 in case of success. 117 | */ 118 | 119 | extern int 120 | ancil_recv_fd(int, int *); 121 | /* ancil_send_fd(sock, &fd); 122 | * 123 | * Receives the file descriptor fd from the socket sock. 124 | * Returns : -1 and errno in case of error, 0 in case of success. 125 | */ 126 | 127 | #ifdef __cplusplus 128 | } 129 | #endif 130 | 131 | #endif /* ANCILLARY_H__ */ 132 | -------------------------------------------------------------------------------- /evclient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ancillary.h" 12 | 13 | 14 | // X will be replaced by '\0' post-snprintf 15 | char *name = "Xeventfd_socket"; 16 | 17 | int main(void) 18 | { 19 | struct sockaddr_un address; 20 | int socket_fd; 21 | int evfd; 22 | 23 | socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 24 | if (socket_fd < 0) { 25 | fprintf(stderr,"socket() failed: %s\n", strerror(errno)); 26 | return 1; 27 | } 28 | 29 | memset(&address, 0, sizeof(struct sockaddr_un)); 30 | 31 | address.sun_family = AF_UNIX; 32 | snprintf(address.sun_path,sizeof(address.sun_path), name); 33 | address.sun_path[0] = '\0'; 34 | 35 | if (connect(socket_fd, (struct sockaddr *) &address, 36 | sizeof(struct sockaddr_un)) != 0) { 37 | fprintf(stderr,"connect() failed: %s\n", strerror(errno)); 38 | return 1; 39 | } 40 | 41 | if (ancil_recv_fd(socket_fd, &evfd)) { 42 | perror("ancil_recv_fd"); 43 | exit(1); 44 | } else { 45 | printf("Received eventfd on: %d\n", evfd); 46 | } 47 | 48 | if (evfd < 0) { 49 | printf("bad event fd\n"); 50 | exit(1); 51 | } 52 | struct pollfd fds[1]; 53 | int rc; 54 | fds[0].fd = evfd; 55 | fds[0].events = POLLERR | POLLIN ; 56 | 57 | printf("starting poll\n"); 58 | 59 | while (1) { 60 | rc = poll((struct pollfd *) &fds, 1, -1); 61 | if (rc < 0) 62 | perror("poll"); 63 | else { 64 | uint64_t u; 65 | ssize_t s; 66 | if (fds[0].revents & POLLIN) { 67 | printf("about to read\n"); 68 | s = read(evfd, &u, sizeof(uint64_t)); 69 | if (s != sizeof(uint64_t)) 70 | perror("read"); 71 | printf("read %llu (0x%llx) from efd %d\n", 72 | (unsigned long long) u, (unsigned long long) u, evfd); 73 | } 74 | if (fds[0].revents & POLLERR) { 75 | printf("POLLERR \n"); 76 | break; 77 | } 78 | } 79 | } 80 | close(socket_fd); 81 | 82 | return 0; 83 | } 84 | -------------------------------------------------------------------------------- /evserver.c: -------------------------------------------------------------------------------- 1 | // based on http://www.thomasstover.com/uds.html 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "ancillary.h" 13 | 14 | // use an 'abstract socket address', whatever that is 15 | // at least not in file system 16 | // X will be replaced by '\0' post-snprintf 17 | char *name = "Xeventfd_socket"; 18 | 19 | int connection_handler(int connection_fd) 20 | { 21 | int i; 22 | int efd; 23 | 24 | efd = eventfd(0,0); 25 | assert (efd != -1); 26 | 27 | if (ancil_send_fd(connection_fd, efd)) { 28 | perror("ancil_send_fd"); 29 | exit(1); 30 | } else { 31 | printf("Sent evfd %d\n", efd); 32 | } 33 | 34 | uint64_t u = getpid(); 35 | ssize_t s; 36 | 37 | for (i = 0; i < 10; i++) { 38 | s = write(efd, &u, sizeof(uint64_t)); 39 | if (s != sizeof(uint64_t)) 40 | perror("write"); 41 | else 42 | printf("Sent %llu\n", u); 43 | u++; 44 | sleep(1); 45 | } 46 | return 0; 47 | } 48 | 49 | int main(void) 50 | { 51 | struct sockaddr_un address; 52 | int socket_fd, connection_fd; 53 | socklen_t address_length = sizeof(address); 54 | pid_t child; 55 | 56 | socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 57 | if(socket_fd < 0) { 58 | printf("socket() failed\n"); 59 | return 1; 60 | } 61 | int enable = 1; 62 | setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); 63 | 64 | memset(&address, 0, sizeof(struct sockaddr_un)); 65 | address.sun_family = AF_UNIX; 66 | snprintf(address.sun_path,sizeof(address.sun_path), name); 67 | address.sun_path[0] = '\0'; 68 | 69 | if (bind(socket_fd, (struct sockaddr *) &address, 70 | sizeof(struct sockaddr_un)) != 0) { 71 | fprintf(stderr,"bind() failed: %s\n", strerror(errno)); 72 | return 1; 73 | } 74 | 75 | if (listen(socket_fd, 5) != 0) { 76 | fprintf(stderr,"listen() failed: %s\n", strerror(errno)); 77 | return 1; 78 | } 79 | 80 | while ((connection_fd = accept(socket_fd, 81 | (struct sockaddr *) &address, 82 | &address_length)) > -1) { 83 | child = fork(); 84 | if (child == 0) { 85 | return connection_handler(connection_fd); 86 | } 87 | close(connection_fd); 88 | } 89 | 90 | fprintf(stderr,"accept() failed: %s\n", strerror(errno)); 91 | close(socket_fd); 92 | return 0; 93 | } 94 | -------------------------------------------------------------------------------- /fd_recv.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * libancillary - black magic on Unix domain sockets 3 | * (C) Nicolas George 4 | * fd_send.c - receiving file descriptors 5 | ***************************************************************************/ 6 | 7 | /* 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. The name of the author may not be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _XPG4_2 /* Solaris sucks */ 32 | # define _XPG4_2 33 | #endif 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #if defined(__FreeBSD__) 41 | # include /* FreeBSD sucks */ 42 | #endif 43 | 44 | #include "ancillary.h" 45 | 46 | int 47 | ancil_recv_fds_with_buffer(int sock, int *fds, unsigned n_fds, void *buffer) 48 | { 49 | struct msghdr msghdr; 50 | char nothing; 51 | struct iovec nothing_ptr; 52 | struct cmsghdr *cmsg; 53 | int i; 54 | 55 | nothing_ptr.iov_base = ¬hing; 56 | nothing_ptr.iov_len = 1; 57 | msghdr.msg_name = NULL; 58 | msghdr.msg_namelen = 0; 59 | msghdr.msg_iov = ¬hing_ptr; 60 | msghdr.msg_iovlen = 1; 61 | msghdr.msg_flags = 0; 62 | msghdr.msg_control = buffer; 63 | msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; 64 | cmsg = CMSG_FIRSTHDR(&msghdr); 65 | cmsg->cmsg_len = msghdr.msg_controllen; 66 | cmsg->cmsg_level = SOL_SOCKET; 67 | cmsg->cmsg_type = SCM_RIGHTS; 68 | for(i = 0; i < n_fds; i++) 69 | ((int *)CMSG_DATA(cmsg))[i] = -1; 70 | 71 | if(recvmsg(sock, &msghdr, 0) < 0) 72 | return(-1); 73 | for(i = 0; i < n_fds; i++) 74 | fds[i] = ((int *)CMSG_DATA(cmsg))[i]; 75 | n_fds = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int); 76 | return(n_fds); 77 | } 78 | 79 | #ifndef SPARE_RECV_FDS 80 | int 81 | ancil_recv_fds(int sock, int *fd, unsigned n_fds) 82 | { 83 | ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer; 84 | 85 | assert(n_fds <= ANCIL_MAX_N_FDS); 86 | return(ancil_recv_fds_with_buffer(sock, fd, n_fds, &buffer)); 87 | } 88 | #endif /* SPARE_RECV_FDS */ 89 | 90 | #ifndef SPARE_RECV_FD 91 | int 92 | ancil_recv_fd(int sock, int *fd) 93 | { 94 | ANCIL_FD_BUFFER(1) buffer; 95 | 96 | return(ancil_recv_fds_with_buffer(sock, fd, 1, &buffer) == 1 ? 0 : -1); 97 | } 98 | #endif /* SPARE_RECV_FD */ 99 | -------------------------------------------------------------------------------- /fd_send.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * libancillary - black magic on Unix domain sockets 3 | * (C) Nicolas George 4 | * fd_send.c - sending file descriptors 5 | ***************************************************************************/ 6 | 7 | /* 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. The name of the author may not be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #ifndef _XPG4_2 /* Solaris sucks */ 32 | # define _XPG4_2 33 | #endif 34 | 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #if defined(__FreeBSD__) 41 | # include /* FreeBSD sucks */ 42 | #endif 43 | 44 | #include "ancillary.h" 45 | 46 | int 47 | ancil_send_fds_with_buffer(int sock, const int *fds, unsigned n_fds, void *buffer) 48 | { 49 | struct msghdr msghdr; 50 | char nothing = '!'; 51 | struct iovec nothing_ptr; 52 | struct cmsghdr *cmsg; 53 | int i; 54 | 55 | nothing_ptr.iov_base = ¬hing; 56 | nothing_ptr.iov_len = 1; 57 | msghdr.msg_name = NULL; 58 | msghdr.msg_namelen = 0; 59 | msghdr.msg_iov = ¬hing_ptr; 60 | msghdr.msg_iovlen = 1; 61 | msghdr.msg_flags = 0; 62 | msghdr.msg_control = buffer; 63 | msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds; 64 | cmsg = CMSG_FIRSTHDR(&msghdr); 65 | cmsg->cmsg_len = msghdr.msg_controllen; 66 | cmsg->cmsg_level = SOL_SOCKET; 67 | cmsg->cmsg_type = SCM_RIGHTS; 68 | for(i = 0; i < n_fds; i++) 69 | ((int *)CMSG_DATA(cmsg))[i] = fds[i]; 70 | return(sendmsg(sock, &msghdr, 0) >= 0 ? 0 : -1); 71 | } 72 | 73 | #ifndef SPARE_SEND_FDS 74 | int 75 | ancil_send_fds(int sock, const int *fds, unsigned n_fds) 76 | { 77 | ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer; 78 | 79 | assert(n_fds <= ANCIL_MAX_N_FDS); 80 | return(ancil_send_fds_with_buffer(sock, fds, n_fds, &buffer)); 81 | } 82 | #endif /* SPARE_SEND_FDS */ 83 | 84 | #ifndef SPARE_SEND_FD 85 | int 86 | ancil_send_fd(int sock, int fd) 87 | { 88 | ANCIL_FD_BUFFER(1) buffer; 89 | 90 | return(ancil_send_fds_with_buffer(sock, &fd, 1, &buffer)); 91 | } 92 | #endif /* SPARE_SEND_FD */ 93 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | /*************************************************************************** 2 | * libancillary - black magic on Unix domain sockets 3 | * (C) Nicolas George 4 | * test.c - testing and example program 5 | ***************************************************************************/ 6 | 7 | /* 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 11 | * 1. Redistributions of source code must retain the above copyright notice, 12 | * this list of conditions and the following disclaimer. 13 | * 2. Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 3. The name of the author may not be used to endorse or promote products 17 | * derived from this software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 20 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 22 | * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 | * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 | * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 | */ 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include "ancillary.h" 39 | 40 | void child_process(int sock) 41 | { 42 | int fd; 43 | int fds[3], nfds; 44 | char b[] = "This is on the received fd!\n"; 45 | 46 | if(ancil_recv_fd(sock, &fd)) { 47 | perror("ancil_recv_fd"); 48 | exit(1); 49 | } else { 50 | printf("Received fd: %d\n", fd); 51 | } 52 | write(fd, b, sizeof(b)); 53 | close(fd); 54 | sleep(2); 55 | 56 | nfds = ancil_recv_fds(sock, fds, 3); 57 | if(nfds < 0) { 58 | perror("ancil_recv_fds"); 59 | exit(1); 60 | } else { 61 | printf("Received %d/3 fds : %d %d %d.\n", nfds, 62 | fds[0], fds[1], fds[2]); 63 | } 64 | } 65 | 66 | void parent_process(int sock) 67 | { 68 | int fds[2] = { 1, 2 }; 69 | 70 | if(ancil_send_fd(sock, 1)) { 71 | perror("ancil_send_fd"); 72 | exit(1); 73 | } else { 74 | printf("Sent fd.\n"); 75 | } 76 | sleep(1); 77 | 78 | if(ancil_send_fds(sock, fds, 2)) { 79 | perror("ancil_send_fds"); 80 | exit(1); 81 | } else { 82 | printf("Sent two fds.\n"); 83 | } 84 | } 85 | 86 | int main(void) 87 | { 88 | int sock[2]; 89 | 90 | if(socketpair(PF_UNIX, SOCK_STREAM, 0, sock)) { 91 | perror("socketpair"); 92 | exit(1); 93 | } else { 94 | printf("Established socket pair: (%d, %d)\n", sock[0], sock[1]); 95 | } 96 | 97 | switch(fork()) { 98 | case 0: 99 | close(sock[0]); 100 | child_process(sock[1]); 101 | break; 102 | case -1: 103 | perror("fork"); 104 | exit(1); 105 | default: 106 | close(sock[1]); 107 | parent_process(sock[0]); 108 | wait(NULL); 109 | break; 110 | } 111 | return(0); 112 | } 113 | --------------------------------------------------------------------------------