1 kumpf 1.2 /*
2 //%2006////////////////////////////////////////////////////////////////////////
3 //
4 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
5 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
6 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
7 // IBM Corp.; EMC Corporation, The Open Group.
8 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
9 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
10 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
11 // EMC Corporation; VERITAS Software Corporation; The Open Group.
12 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
13 // EMC Corporation; Symantec Corporation; The Open Group.
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining a copy
16 // of this software and associated documentation files (the "Software"), to
17 // deal in the Software without restriction, including without limitation the
18 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
19 // sell copies of the Software, and to permit persons to whom the Software is
20 // furnished to do so, subject to the following conditions:
21 //
22 kumpf 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
23 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
24 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
25 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
26 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 //%/////////////////////////////////////////////////////////////////////////////
32 */
33 #include "Socket.h"
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <signal.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/socket.h>
40 #include "Exit.h"
41 #include "Globals.h"
42 #include "Defines.h"
43 kumpf 1.2 #include "Socket.h"
44
45 /*
46 **==============================================================================
47 **
48 ** CloseOnExec()
49 **
50 ** Direct the kernel not to keep the given file descriptor open across
51 ** exec() system call.
52 **
53 **==============================================================================
54 */
55
56 int CloseOnExec(int fd)
57 {
58 return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
59 }
60
61 /*
62 **==============================================================================
63 **
64 kumpf 1.2 ** SetNonBlocking()
65 **
66 ** Set the given socket into non-blocking mode.
67 **
68 **==============================================================================
69 */
70
71 int SetNonBlocking(int sock)
72 {
73 return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
74 }
75
76 /*
77 **==============================================================================
78 **
79 ** SetBlocking()
80 **
81 ** Set the given socket into blocking mode.
82 **
83 **==============================================================================
84 */
85 kumpf 1.2
86 int SetBlocking(int sock)
87 {
88 return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK);
89 }
90
91 /*
92 **==============================================================================
93 **
94 ** _waitForReadEnable()
95 **
96 ** Wait until the given socket is read-enabled. Returns 1 if read enabled
97 ** and 0 on timed out.
98 **
99 **==============================================================================
100 */
101
102 static int _waitForReadEnable(int sock, long timeoutMsec)
103 {
104 struct timeval timeout;
105
106 kumpf 1.2 fd_set readSet;
107 FD_ZERO(&readSet);
108 FD_SET(sock, &readSet);
109
110 timeout.tv_sec = timeoutMsec / 1000;
111 timeout.tv_usec = (timeoutMsec % 1000) * 1000;
112
113 return select(sock + 1, &readSet, 0, 0, &timeout);
114 }
115
116 /*
117 **==============================================================================
118 **
119 ** _waitForWriteEnable()
120 **
121 ** Wait until the given socket is write-enabled. Returns 1 if write enabled
122 ** and 0 on timed out.
123 **
124 **==============================================================================
125 */
126
127 kumpf 1.2 static int _waitForWriteEnable(int sock, long timeoutMsec)
128 {
129 fd_set writeSet;
130 struct timeval timeout;
131
132 FD_ZERO(&writeSet);
133 FD_SET(sock, &writeSet);
134
135 timeout.tv_sec = timeoutMsec / 1000;
136 timeout.tv_usec = (timeoutMsec % 1000) * 1000;
137
138 return select(sock + 1, 0, &writeSet, 0, &timeout);
139 }
140
141 /*
142 **==============================================================================
143 **
144 ** RecvNonBlock()
145 **
146 ** Receive at least size bytes from the given non-blocking socket.
147 **
148 kumpf 1.2 **==============================================================================
149 */
150
151 ssize_t RecvNonBlock(
152 int sock,
153 void* buffer,
154 size_t size)
155 {
156 const long TIMEOUT_MSEC = 250;
157 size_t r = size;
158 char* p = (char*)buffer;
159
160 if (size == 0)
161 return -1;
162
163 while (r)
164 {
165 int status = _waitForReadEnable(sock, TIMEOUT_MSEC);
166 ssize_t n;
167
168 if ((globals.signalMask & (1 << SIGTERM)) ||
169 kumpf 1.2 (globals.signalMask & (1 << SIGINT)))
170 {
171 /* Exit on either of these signals. */
172 Exit(0);
173 }
174
175 if (status == 0)
176 continue;
177
178 EXECUTOR_RESTART(read(sock, p, r), n);
179
180 if (n == -1 && errno == EINTR)
181 continue;
182
183 if (n == -1)
184 {
185 if (errno == EWOULDBLOCK)
186 {
187 size_t total = size - r;
188
189 if (total)
190 kumpf 1.2 return total;
191
192 return -1;
193 }
194 else
195 return -1;
196 }
197 else if (n == 0)
198 return size - r;
199
200 r -= n;
201 p += n;
202 }
203
204 return size - r;
205 }
206
207 /*
208 **==============================================================================
209 **
210 ** SendNonBlock()
211 kumpf 1.2 **
212 ** Sends at least size bytes on the given non-blocking socket.
213 **
214 **==============================================================================
215 */
216
217 ssize_t SendNonBlock(
218 int sock,
219 const void* buffer,
220 size_t size)
221 {
222 const long TIMEOUT_MSEC = 250;
223 size_t r = size;
224 char* p = (char*)buffer;
225
226 while (r)
227 {
228 int status = _waitForWriteEnable(sock, TIMEOUT_MSEC);
229 ssize_t n;
230
231 if ((globals.signalMask & (1 << SIGTERM)) ||
232 kumpf 1.2 (globals.signalMask & (1 << SIGINT)))
233 {
234 /* Exit on either of these signals. */
235 Exit(0);
236 }
237
238 if (status == 0)
239 continue;
240
241 EXECUTOR_RESTART(write(sock, p, r), n);
242
243 if (n == -1)
244 {
245 if (errno == EWOULDBLOCK)
246 return size - r;
247 else
248 return -1;
249 }
250 else if (n == 0)
251 return size - r;
252
253 kumpf 1.2 r -= n;
254 p += n;
255 }
256
257 return size - r;
258 }
259
260 /*
261 **==============================================================================
262 **
263 ** SendDescriptorArray()
264 **
265 ** Send an array of descriptors (file, socket, pipe) to the child process.
266 **
267 **==============================================================================
268 */
269
270 ssize_t SendDescriptorArray(int sock, int descriptors[], size_t count)
271 {
272 struct iovec iov[1];
273 char dummy;
274 kumpf 1.2 struct msghdr mh;
275 int result;
276 #if defined(HAVE_MSG_CONTROL)
277 size_t size;
278 char* data;
279 struct cmsghdr* cmh;
280
281 /* Allocate space for control header plus descriptors. */
282
283 size = CMSG_SPACE(sizeof(int) * count);
284 data = (char*)malloc(size);
285
286 /* Initialize msghdr struct to refer to control data. */
287
288 memset(&mh, 0, sizeof(mh));
289 mh.msg_control = data;
290 mh.msg_controllen = size;
291
292 /* Fill in the control data struct with the descriptor and other fields. */
293
294 cmh = CMSG_FIRSTHDR(&mh);
295 kumpf 1.2 cmh->cmsg_len = CMSG_LEN(sizeof(int) * count);
296 cmh->cmsg_level = SOL_SOCKET;
297 cmh->cmsg_type = SCM_RIGHTS;
298 memcpy((int*)CMSG_DATA(cmh), descriptors, sizeof(int) * count);
299
300 #else /* defined(HAVE_MSG_CONTROL) */
301
302 memset(&mh, 0, sizeof(mh));
303 mh.msg_accrights = (caddr_t)descriptors;
304 mh.msg_accrightslen = count * sizeof(int);
305
306 #endif /* defined(HAVE_MSG_CONTROL) */
307
308 /*
309 * Prepare to send single dummy byte. It will not be used but we must send
310 * at least one byte otherwise the call will fail on some platforms.
311 */
312
313 memset(iov, 0, sizeof(iov));
314 dummy = '\0';
315 iov[0].iov_base = &dummy;
316 kumpf 1.2 iov[0].iov_len = 1;
317 mh.msg_iov = iov;
318 mh.msg_iovlen = 1;
319
320 /* Send message to child. */
321
322 result = sendmsg(sock, &mh, 0);
323
324 #if defined(HAVE_MSG_CONTROL)
325 free(data);
326 #endif
327
328 return result == -1 ? -1 : 0;
329 }
330
331 /*
332 **==============================================================================
333 **
334 ** CreateSocketPair()
335 **
336 ** Send an array of descriptors (file, socket, pipe) to the child process.
337 kumpf 1.2 **
338 **==============================================================================
339 */
340
341 int CreateSocketPair(int pair[2])
342 {
343 return socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
344 }
|