ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/IO-FDPass/FDPass.xs
Revision: 1.4
Committed: Fri Apr 5 05:04:59 2013 UTC (11 years, 1 month ago) by root
Branch: MAIN
CVS Tags: rel-0_1
Changes since 1.3: +1 -1 lines
Log Message:
0.1

File Contents

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