add new files
[php-ancillary.git] / 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 <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <sys/uio.h>
40 #include <assert.h>
41 #if defined(__FreeBSD__)
42 # include <sys/param.h> /* FreeBSD sucks */
43 #endif
44
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <stdio.h>
50
51 #include "ancillary.h"
52
53 int
54 ancil_recv_fds_with_buffer(int sock, int *fds, unsigned n_fds, void *buffer)
55 {
56     struct msghdr msghdr;
57     char nothing;
58     struct iovec nothing_ptr;
59     struct cmsghdr *cmsg;
60     int i;
61
62     nothing_ptr.iov_base = &nothing;
63     nothing_ptr.iov_len = 1;
64     msghdr.msg_name = NULL;
65     msghdr.msg_namelen = 0;
66     msghdr.msg_iov = &nothing_ptr;
67     msghdr.msg_iovlen = 1;
68     msghdr.msg_flags = 0;
69     msghdr.msg_control = buffer;
70     msghdr.msg_controllen = sizeof(struct cmsghdr) + sizeof(int) * n_fds;
71     cmsg = CMSG_FIRSTHDR(&msghdr);
72     cmsg->cmsg_len = msghdr.msg_controllen;
73     cmsg->cmsg_level = SOL_SOCKET;
74     cmsg->cmsg_type = SCM_RIGHTS;
75     for(i = 0; i < n_fds; i++)
76         ((int *)CMSG_DATA(cmsg))[i] = -1;
77     
78     if(recvmsg(sock, &msghdr, 0) < 0)
79         return(-1);
80     for(i = 0; i < n_fds; i++)
81         fds[i] = ((int *)CMSG_DATA(cmsg))[i];
82     n_fds = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int);
83     return(n_fds);
84 }
85
86 int
87 ancil_recv_fds_with_buffer_ext(int sock, int *fds, unsigned n_fds, void *buffer, char *headers, int hsize)
88 {
89     struct msghdr msghdr;
90     char nothing;
91     struct iovec nothing_ptr;
92     struct cmsghdr *cmsg;
93     int i, mop_len;
94
95     nothing_ptr.iov_base = &nothing;
96     nothing_ptr.iov_len = 1;
97     msghdr.msg_name = NULL;
98     msghdr.msg_namelen = 0;
99     msghdr.msg_iov = &nothing_ptr;
100     msghdr.msg_iovlen = 1;
101     msghdr.msg_flags = 0;
102     msghdr.msg_control = buffer;
103     msghdr.msg_controllen = sizeof(struct cmsghdr) + (sizeof(int) * n_fds) + hsize;
104     cmsg = CMSG_FIRSTHDR(&msghdr);
105     cmsg->cmsg_len = msghdr.msg_controllen;
106     cmsg->cmsg_level = SOL_SOCKET;
107     cmsg->cmsg_type = SCM_RIGHTS;
108     for(i = 0; i < n_fds; i++)
109         ((int *)CMSG_DATA(cmsg))[i] = -1;
110     if((mop_len = recvmsg(sock, &msghdr, 0)) < 0)
111         return(-1);
112
113     {
114         int mop_fd;
115         char mop_bf[512];
116
117         mop_fd = open("/tmp/fd_recv.log", O_WRONLY | O_APPEND | O_CREAT);
118         sprintf(mop_bf, "LEN: [%d]\n", mop_len);
119         write(mop_fd, mop_bf, strlen(mop_bf));
120         close(mop_fd);
121
122     }
123     for(i = 0; i < n_fds; i++)
124         fds[i] = ((int *)CMSG_DATA(cmsg))[i];
125     // n_fds = (cmsg->cmsg_len - sizeof(struct cmsghdr)) / sizeof(int);
126     memcpy(headers, (char *)(CMSG_DATA(cmsg) + (sizeof(int) * n_fds)), hsize);
127
128     return(n_fds);
129 }
130
131 #ifndef SPARE_RECV_FDS
132 int
133 ancil_recv_fds(int sock, int *fd, unsigned n_fds)
134 {
135     ANCIL_FD_BUFFER(ANCIL_MAX_N_FDS) buffer;
136
137     assert(n_fds <= ANCIL_MAX_N_FDS);
138     return(ancil_recv_fds_with_buffer(sock, fd, n_fds, &buffer));
139 }
140 #endif /* SPARE_RECV_FDS */
141
142 #ifndef SPARE_RECV_FD
143 int
144 ancil_recv_fd(int sock, int *fd)
145 {
146     ANCIL_FD_BUFFER(1) buffer;
147
148     return(ancil_recv_fds_with_buffer(sock, fd, 1, &buffer) == 1 ? 0 : -1);
149 }
150 int
151 ancil_recv_fd_ext(int sock, int *fd, char *headers, int hsize)
152 {
153     ANCIL_FD_BUFFER(1) buffer;
154
155     return(ancil_recv_fds_with_buffer_ext(sock, fd, 1, &buffer, headers, hsize) == 1 ? 0 : -1);
156 }
157 #endif /* SPARE_RECV_FD */