File Coverage

FDPass.xs
Criterion Covered Total %
statement 44 48 91.6
branch 10 20 50.0
condition n/a
subroutine n/a
pod n/a
total 54 68 79.4


line stmt bran cond sub pod time code
1             #ifdef __sun
2             #define _XOPEN_SOURCE 1
3             #define _XOPEN_SOURCE_EXTENDED 1
4             #define __EXTENSIONS__ 1
5             #endif
6              
7             #include "EXTERN.h"
8             #include "perl.h"
9             #include "XSUB.h"
10              
11             #if WIN32
12              
13             /* perl probably did this already */
14             #include
15              
16             #elif __CYGWIN__
17              
18             #include
19             #include
20             #include
21              
22             #define _open_osfhandle(h,m) cygwin_attach_handle_to_fd ("/dev/tcp", -1, (HANDLE)h, 1, GENERIC_READ | GENERIC_WRITE)
23             typedef int SOCKET;
24              
25             #else
26              
27             #include // needed by broken bsds for NULL used in sys/uio.h
28             #include
29             #include
30              
31             /* send_fd/recv_fd taken from libptytty */
32             #include
33             #include
34             #include
35              
36             #ifndef CMSG_SPACE
37             # define CMSG_SPACE(len) (sizeof (struct cmsghdr) + len)
38             #endif
39              
40             #ifndef CMSG_LEN
41             # define CMSG_LEN(len) (sizeof (struct cmsghdr) + len)
42             #endif
43              
44             #endif
45              
46             #if defined(WIN32)
47             /* the rub is this: win32 doesn't seem to have a way to query whether a socket */
48             /* is non-blocking or not. so we assume it is blocking, make it so if it isn't */
49             /* and reset it afterwards */
50             static int
51             rw (int wr, int fd, char *buf, int len)
52             {
53             u_long nbio = 0;
54             int got = 0;
55              
56             while (got != len)
57             {
58             int sze = wr
59             ? send ((SOCKET)fd, buf, len - got, 0) /* we assume send and recv are macros with arguments */
60             : recv ((SOCKET)fd, buf, len - got, 0); /* to be on the safe side */
61              
62             if (sze < 0)
63             {
64             if (errno == EAGAIN || errno == WSAEWOULDBLOCK)
65             {
66             ioctl (fd, FIONBIO, (void *)&nbio);
67             nbio = 1;
68             }
69             else
70             break;
71             }
72             else if (sze == 0)
73             break;
74             else
75             got += sze;
76             }
77              
78             if (nbio)
79             ioctl (fd, FIONBIO, (void *)&nbio);
80              
81             return got == len;
82             }
83             #endif
84              
85             static int
86 1           fd_send (int socket, int fd)
87             {
88             #if defined(WIN32)
89             DWORD pid;
90             HANDLE hdl;
91            
92             pid = GetCurrentProcessId ();
93              
94             if (!rw (1, socket, (char *)&pid, sizeof (pid)))
95             return 0;
96              
97             errno = EBADF;
98             if (!DuplicateHandle ((HANDLE)-1, (HANDLE)_get_osfhandle (fd), (HANDLE)-1, &hdl, 0, FALSE, DUPLICATE_SAME_ACCESS))
99             return 0;
100              
101             if (!rw (1, socket, (char *)&hdl, sizeof (hdl)))
102             {
103             CloseHandle (hdl);
104             return 0;
105             }
106              
107             return 1;
108              
109             #else
110 1           void *buf = malloc (CMSG_SPACE (sizeof (int)));
111              
112 1 50         if (!buf)
113 0           return 0;
114              
115             struct msghdr msg;
116             struct iovec iov;
117             struct cmsghdr *cmsg;
118 1           char data = 0;
119              
120 1           iov.iov_base = &data;
121 1           iov.iov_len = 1;
122              
123 1           msg.msg_name = 0;
124 1           msg.msg_namelen = 0;
125 1           msg.msg_iov = &iov;
126 1           msg.msg_iovlen = 1;
127 1           msg.msg_control = buf;
128 1           msg.msg_controllen = CMSG_SPACE (sizeof (int));
129              
130 1 50         cmsg = CMSG_FIRSTHDR (&msg);
131 1           cmsg->cmsg_level = SOL_SOCKET;
132 1           cmsg->cmsg_type = SCM_RIGHTS;
133 1           cmsg->cmsg_len = CMSG_LEN (sizeof (int));
134              
135 1           *(int *)CMSG_DATA (cmsg) = fd;
136              
137 1           ssize_t result = sendmsg (socket, &msg, 0);
138              
139 1           free (buf);
140              
141 1           return result >= 0;
142             #endif
143             }
144              
145             static int
146 1           fd_recv (int socket)
147             {
148             #if defined(WIN32)
149             DWORD pid;
150             HANDLE source, rhd, lhd;
151              
152             if (!rw (0, socket, (char *)&pid, sizeof (pid)))
153             return -1;
154              
155             if (!rw (0, socket, (char *)&rhd, sizeof (rhd)))
156             return -1;
157              
158             source = OpenProcess (PROCESS_DUP_HANDLE, FALSE, pid);
159             errno = EACCES;
160             if (!source)
161             return -1;
162              
163             pid = DuplicateHandle (source, rhd, (HANDLE)-1, &lhd,
164             0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
165              
166             CloseHandle (source);
167              
168             errno = EBADF;
169             if (!pid)
170             return -1;
171              
172             return _open_osfhandle ((intptr_t)lhd, 0);
173             #else
174 1           void *buf = malloc (CMSG_SPACE (sizeof (int)));
175              
176 1 50         if (!buf)
177 0           return -1;
178              
179             struct msghdr msg;
180             struct iovec iov;
181 1           char data = 1;
182              
183 1           iov.iov_base = &data;
184 1           iov.iov_len = 1;
185              
186 1           msg.msg_name = 0;
187 1           msg.msg_namelen = 0;
188 1           msg.msg_iov = &iov;
189 1           msg.msg_iovlen = 1;
190 1           msg.msg_control = buf;
191 1           msg.msg_controllen = CMSG_SPACE (sizeof (int));
192              
193 1 50         if (recvmsg (socket, &msg, 0) <= 0)
194             {
195 0           free (buf);
196 0           return -1;
197             }
198              
199 1           int fd = -1;
200 1           errno = EDOM;
201              
202 1 50         struct cmsghdr *cmsg = CMSG_FIRSTHDR (&msg);
203              
204 1 50         if (data == 0
205 1 50         && cmsg
206 1 50         && cmsg->cmsg_level == SOL_SOCKET
207 1 50         && cmsg->cmsg_type == SCM_RIGHTS
208 1 50         && cmsg->cmsg_len >= CMSG_LEN (sizeof (int)))
209 1           fd = *(int *)CMSG_DATA (cmsg);
210              
211 1           free (buf);
212              
213 1           return fd;
214             #endif
215             }
216              
217             MODULE = IO::FDPass PACKAGE = IO::FDPass PREFIX = fd_
218              
219             PROTOTYPES: DISABLE
220              
221             int
222             fd_send (int socket, int fd)
223              
224             int
225             fd_recv (int socket)
226