1 kumpf 1.2 /*
|
2 martin 1.5 //%LICENSE////////////////////////////////////////////////////////////////
|
3 martin 1.6 //
|
4 martin 1.5 // Licensed to The Open Group (TOG) under one or more contributor license
5 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
6 // this work for additional information regarding copyright ownership.
7 // Each contributor licenses this file to you under the OpenPegasus Open
8 // Source License; you may not use this file except in compliance with the
9 // License.
|
10 martin 1.6 //
|
11 martin 1.5 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
|
17 martin 1.6 //
|
18 martin 1.5 // The above copyright notice and this permission notice shall be included
19 // in all copies or substantial portions of the Software.
|
20 martin 1.6 //
|
21 martin 1.5 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
22 martin 1.6 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
23 martin 1.5 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
28 martin 1.6 //
|
29 martin 1.5 //////////////////////////////////////////////////////////////////////////
|
30 kumpf 1.2 */
|
31 martin 1.5
|
32 kumpf 1.2 #include "Socket.h"
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <signal.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/socket.h>
39 #include "Exit.h"
40 #include "Globals.h"
41 #include "Defines.h"
42 #include "Socket.h"
43
44 /*
45 **==============================================================================
46 **
47 ** CloseOnExec()
48 **
49 ** Direct the kernel not to keep the given file descriptor open across
50 ** exec() system call.
51 **
52 **==============================================================================
53 kumpf 1.2 */
54
55 int CloseOnExec(int fd)
56 {
57 return fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
58 }
59
60 /*
61 **==============================================================================
62 **
63 ** SetNonBlocking()
64 **
65 ** Set the given socket into non-blocking mode.
66 **
67 **==============================================================================
68 */
69
70 int SetNonBlocking(int sock)
71 {
72 return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);
73 }
74 kumpf 1.2
75 /*
76 **==============================================================================
77 **
78 ** SetBlocking()
79 **
80 ** Set the given socket into blocking mode.
81 **
82 **==============================================================================
83 */
84
85 int SetBlocking(int sock)
86 {
87 return fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) & ~O_NONBLOCK);
88 }
89
90 /*
91 **==============================================================================
92 **
|
93 kumpf 1.3 ** WaitForReadEnable()
|
94 kumpf 1.2 **
95 ** Wait until the given socket is read-enabled. Returns 1 if read enabled
96 ** and 0 on timed out.
97 **
98 **==============================================================================
99 */
100
|
101 kumpf 1.3 int WaitForReadEnable(int sock, long timeoutMsec)
|
102 kumpf 1.2 {
103 struct timeval timeout;
104
105 fd_set readSet;
106 FD_ZERO(&readSet);
107 FD_SET(sock, &readSet);
108
109 timeout.tv_sec = timeoutMsec / 1000;
110 timeout.tv_usec = (timeoutMsec % 1000) * 1000;
111
112 return select(sock + 1, &readSet, 0, 0, &timeout);
113 }
114
115 /*
116 **==============================================================================
117 **
118 ** _waitForWriteEnable()
119 **
120 ** Wait until the given socket is write-enabled. Returns 1 if write enabled
121 ** and 0 on timed out.
122 **
123 kumpf 1.2 **==============================================================================
124 */
125
126 static int _waitForWriteEnable(int sock, long timeoutMsec)
127 {
128 fd_set writeSet;
129 struct timeval timeout;
130
131 FD_ZERO(&writeSet);
132 FD_SET(sock, &writeSet);
133
134 timeout.tv_sec = timeoutMsec / 1000;
135 timeout.tv_usec = (timeoutMsec % 1000) * 1000;
136
137 return select(sock + 1, 0, &writeSet, 0, &timeout);
138 }
139
140 /*
141 **==============================================================================
142 **
143 ** RecvNonBlock()
144 kumpf 1.2 **
145 ** Receive at least size bytes from the given non-blocking socket.
146 **
147 **==============================================================================
148 */
149
150 ssize_t RecvNonBlock(
151 int sock,
152 void* buffer,
153 size_t size)
154 {
155 const long TIMEOUT_MSEC = 250;
156 size_t r = size;
157 char* p = (char*)buffer;
158
159 if (size == 0)
160 return -1;
161
162 while (r)
163 {
|
164 kumpf 1.3 int status = WaitForReadEnable(sock, TIMEOUT_MSEC);
|
165 kumpf 1.2 ssize_t n;
166
167 if ((globals.signalMask & (1 << SIGTERM)) ||
168 (globals.signalMask & (1 << SIGINT)))
169 {
170 /* Exit on either of these signals. */
171 Exit(0);
172 }
173
174 if (status == 0)
175 continue;
176
177 EXECUTOR_RESTART(read(sock, p, r), n);
178
179 if (n == -1 && errno == EINTR)
180 continue;
181
182 if (n == -1)
183 {
184 if (errno == EWOULDBLOCK)
185 {
186 kumpf 1.2 size_t total = size - r;
187
188 if (total)
189 return total;
190
191 return -1;
192 }
193 else
194 return -1;
195 }
196 else if (n == 0)
197 return size - r;
198
199 r -= n;
200 p += n;
201 }
202
203 return size - r;
204 }
205
206 /*
207 kumpf 1.2 **==============================================================================
208 **
209 ** SendNonBlock()
210 **
211 ** Sends at least size bytes on the given non-blocking socket.
212 **
213 **==============================================================================
214 */
215
216 ssize_t SendNonBlock(
217 int sock,
218 const void* buffer,
219 size_t size)
220 {
221 const long TIMEOUT_MSEC = 250;
222 size_t r = size;
223 char* p = (char*)buffer;
224
225 while (r)
226 {
227 int status = _waitForWriteEnable(sock, TIMEOUT_MSEC);
228 kumpf 1.2 ssize_t n;
229
230 if ((globals.signalMask & (1 << SIGTERM)) ||
231 (globals.signalMask & (1 << SIGINT)))
232 {
233 /* Exit on either of these signals. */
234 Exit(0);
235 }
236
237 if (status == 0)
238 continue;
239
240 EXECUTOR_RESTART(write(sock, p, r), n);
241
242 if (n == -1)
243 {
244 if (errno == EWOULDBLOCK)
245 return size - r;
246 else
247 return -1;
248 }
249 kumpf 1.2 else if (n == 0)
250 return size - r;
251
252 r -= n;
253 p += n;
254 }
255
256 return size - r;
257 }
258
259 /*
260 **==============================================================================
261 **
262 ** SendDescriptorArray()
263 **
264 ** Send an array of descriptors (file, socket, pipe) to the child process.
265 **
266 **==============================================================================
267 */
268
269 ssize_t SendDescriptorArray(int sock, int descriptors[], size_t count)
270 kumpf 1.2 {
271 struct iovec iov[1];
272 char dummy;
273 struct msghdr mh;
274 int result;
275 #if defined(HAVE_MSG_CONTROL)
276 size_t size;
277 char* data;
278 struct cmsghdr* cmh;
279
280 /* Allocate space for control header plus descriptors. */
281
282 size = CMSG_SPACE(sizeof(int) * count);
283 data = (char*)malloc(size);
|
284 kumpf 1.4 memset(data, 0, size);
|
285 kumpf 1.2
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 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 kumpf 1.2 #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 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 kumpf 1.2
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 **
338 **==============================================================================
339 */
340
341 int CreateSocketPair(int pair[2])
342 {
343 return socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
344 }
|