1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3 * (C) 2008 by Argonne National Laboratory.
4 * See COPYRIGHT in top-level directory.
5 */
6
7 #include "hydra.h"
8 #include "demux.h"
9
10 struct fwd_hash {
11 int in;
12 int out;
13
14 char buf[HYD_TMPBUF_SIZE];
15 int buf_offset;
16 int buf_count;
17
18 struct fwd_hash *next;
19 };
20
HYDU_sock_listen(int * listen_fd,char * port_range,uint16_t * port)21 HYD_status HYDU_sock_listen(int *listen_fd, char *port_range, uint16_t * port)
22 {
23 struct sockaddr_in sa;
24 int one = 1;
25 uint16_t low_port, high_port;
26 char *port_str;
27 uint16_t i;
28 HYD_status status = HYD_SUCCESS;
29
30 HYDU_FUNC_ENTER();
31
32 low_port = 0;
33 high_port = 0;
34 if (port_range) {
35 /* If port range is set, we always pick from there */
36 *port = 0;
37
38 port_str = strtok(port_range, ":");
39 if (port_str == NULL)
40 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "error parsing port range\n");
41 low_port = atoi(port_str);
42
43 port_str = strtok(NULL, ":");
44 if (port_str == NULL)
45 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "error parsing port range\n");
46 high_port = atoi(port_str);
47
48 if (high_port < low_port)
49 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "high port < low port\n");
50 }
51 else {
52 /* If port range is NULL, if a port is already provided, we
53 * pick that. Otherwise, we search for an available port. */
54 low_port = *port;
55 high_port = *port;
56 }
57
58 *listen_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
59 if (*listen_fd < 0)
60 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot open socket (%s)\n",
61 HYDU_strerror(errno));
62
63 if (setsockopt(*listen_fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int)) < 0)
64 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot set TCP_NODELAY\n");
65
66 /* The sockets standard does not guarantee that a successful
67 * return here means that this is set. However, REUSEADDR not
68 * being set is not a fatal error, so we ignore that
69 * case. However, we do check for error cases, which means that
70 * something bad has happened. */
71 if (setsockopt(*listen_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) < 0)
72 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot set SO_REUSEADDR\n");
73
74 for (i = low_port; i <= high_port; i++) {
75 memset((void *) &sa, 0, sizeof(sa));
76 sa.sin_family = AF_INET;
77 sa.sin_port = htons(i);
78 sa.sin_addr.s_addr = INADDR_ANY;
79
80 if (bind(*listen_fd, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
81 /* If the address is in use, we should try the next
82 * port. Otherwise, it's an error. */
83 if (errno != EADDRINUSE)
84 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "bind error (%s)\n",
85 HYDU_strerror(errno));
86 }
87 else /* We got a port */
88 break;
89 }
90
91 *port = i;
92 if (*port > high_port)
93 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "no port to bind\n");
94
95 if (listen(*listen_fd, SOMAXCONN) < 0)
96 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "listen error (%s)\n",
97 HYDU_strerror(errno));
98
99 /* We asked for any port, so we need to find out which port we
100 * actually got. */
101 if (*port == 0) {
102 socklen_t sinlen = sizeof(sa);
103
104 if (getsockname(*listen_fd, (struct sockaddr *) &sa, &sinlen) < 0)
105 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "getsockname error (%s)\n",
106 HYDU_strerror(errno));
107 *port = ntohs(sa.sin_port);
108 }
109
110 fn_exit:
111 HYDU_FUNC_EXIT();
112 return status;
113
114 fn_fail:
115 goto fn_exit;
116 }
117
118
HYDU_sock_connect(const char * host,uint16_t port,int * fd,int retries,unsigned long delay)119 HYD_status HYDU_sock_connect(const char *host, uint16_t port, int *fd, int retries,
120 unsigned long delay)
121 {
122 struct hostent *ht;
123 struct sockaddr_in sa;
124 int one = 1, ret, retry_count;
125 HYD_status status = HYD_SUCCESS;
126
127 HYDU_FUNC_ENTER();
128
129 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
130 sa.sin_family = AF_INET;
131 sa.sin_port = htons(port);
132
133 /* Get the remote host's IP address. Note that this is not
134 * thread-safe. Since we don't use threads right now, we don't
135 * worry about locking it. */
136 ht = gethostbyname(host);
137 if (ht == NULL)
138 HYDU_ERR_SETANDJUMP(status, HYD_INVALID_PARAM,
139 "unable to get host address for %s (%s)\n", host,
140 HYDU_herror(h_errno));
141 memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
142
143 /* Create a socket and set the required options */
144 *fd = socket(AF_INET, SOCK_STREAM, 0);
145 if (*fd < 0)
146 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot open socket (%s)\n",
147 HYDU_strerror(errno));
148
149 /* Not being able to connect is not an error in all cases. So we
150 * return an error, but only print a warning message. The upper
151 * layer can decide what to do with the return status. */
152 retry_count = 0;
153 do {
154 ret = connect(*fd, (struct sockaddr *) &sa, sizeof(sa));
155 if (ret < 0 && errno == ECONNREFUSED) {
156 /* connection error; increase retry count and delay */
157 retry_count++;
158 if (retry_count > retries)
159 break;
160 HYDU_delay(delay);
161 }
162 else
163 break;
164 } while (1);
165
166 if (ret < 0) {
167 char localhost[MAX_HOSTNAME_LEN] = { 0 };
168
169 status = HYDU_gethostname(localhost);
170 HYDU_ERR_POP(status, "unable to get local hostname\n");
171
172 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR,
173 "unable to connect from \"%s\" to \"%s\" (%s)\n",
174 localhost, host, HYDU_strerror(errno));
175 }
176
177 /* Disable nagle */
178 if (setsockopt(*fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int)) < 0)
179 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot set TCP_NODELAY\n");
180
181 fn_exit:
182 HYDU_FUNC_EXIT();
183 return status;
184
185 fn_fail:
186 goto fn_exit;
187 }
188
189
HYDU_sock_accept(int listen_fd,int * fd)190 HYD_status HYDU_sock_accept(int listen_fd, int *fd)
191 {
192 int one = 1;
193 HYD_status status = HYD_SUCCESS;
194
195 HYDU_FUNC_ENTER();
196
197 *fd = accept(listen_fd, 0, 0);
198 if (*fd < 0)
199 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "accept error (%s)\n",
200 HYDU_strerror(errno));
201
202 /* Disable nagle */
203 if (setsockopt(*fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(int)) < 0)
204 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "cannot set TCP_NODELAY\n");
205
206 fn_exit:
207 HYDU_FUNC_EXIT();
208 return status;
209
210 fn_fail:
211 goto fn_exit;
212 }
213
HYDU_sock_read(int fd,void * buf,int maxlen,int * recvd,int * closed,enum HYDU_sock_comm_flag flag)214 HYD_status HYDU_sock_read(int fd, void *buf, int maxlen, int *recvd, int *closed,
215 enum HYDU_sock_comm_flag flag)
216 {
217 int tmp;
218 HYD_status status = HYD_SUCCESS;
219
220 HYDU_FUNC_ENTER();
221
222 HYDU_ASSERT(maxlen, status);
223
224 *recvd = 0;
225 *closed = 0;
226 while (1) {
227 do {
228 tmp = read(fd, (char *) buf + *recvd, maxlen - *recvd);
229 if (tmp < 0) {
230 if (errno == ECONNRESET || fd == STDIN_FILENO) {
231 /* If the remote end closed the socket or if we
232 * get an EINTR on stdin, set the socket to be
233 * closed and jump out */
234 *closed = 1;
235 status = HYD_SUCCESS;
236 goto fn_exit;
237 }
238 }
239 } while (tmp < 0 && errno == EINTR);
240
241 if (tmp < 0) {
242 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "read error (%s)\n",
243 HYDU_strerror(errno));
244 }
245 else if (tmp == 0) {
246 *closed = 1;
247 goto fn_exit;
248 }
249 else {
250 *recvd += tmp;
251 }
252
253 if (flag != HYDU_SOCK_COMM_MSGWAIT || *recvd == maxlen)
254 break;
255 };
256
257 fn_exit:
258 HYDU_FUNC_EXIT();
259 return status;
260
261 fn_fail:
262 goto fn_exit;
263 }
264
HYDU_sock_write(int fd,const void * buf,int maxlen,int * sent,int * closed)265 HYD_status HYDU_sock_write(int fd, const void *buf, int maxlen, int *sent, int *closed)
266 {
267 int tmp;
268 HYD_status status = HYD_SUCCESS;
269
270 HYDU_FUNC_ENTER();
271
272 HYDU_ASSERT(maxlen, status);
273
274 *sent = 0;
275 *closed = 0;
276 while (1) {
277 do {
278 tmp = write(fd, (char *) buf + *sent, maxlen - *sent);
279 } while (tmp < 0 && (errno == EINTR || errno == EAGAIN));
280
281 if (tmp < 0 || tmp == 0) {
282 *closed = 1;
283 goto fn_exit;
284 }
285 *sent += tmp;
286
287 if (*sent == maxlen)
288 break;
289 };
290
291 fn_exit:
292 HYDU_FUNC_EXIT();
293 return status;
294
295 fn_fail:
296 goto fn_exit;
297 }
298
set_nonblock(int fd)299 static HYD_status set_nonblock(int fd)
300 {
301 int flags;
302 HYD_status status = HYD_SUCCESS;
303
304 HYDU_FUNC_ENTER();
305
306 if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
307 flags = 0;
308 #if defined O_NONBLOCK
309 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
310 HYDU_ERR_SETANDJUMP(status, HYD_SOCK_ERROR, "fcntl failed on %d\n", fd);
311 #endif /* O_NONBLOCK */
312
313 fn_exit:
314 HYDU_FUNC_EXIT();
315 return status;
316
317 fn_fail:
318 goto fn_exit;
319 }
320
alloc_fwd_hash(struct fwd_hash ** fwd_hash,int in,int out)321 static HYD_status alloc_fwd_hash(struct fwd_hash **fwd_hash, int in, int out)
322 {
323 HYD_status status = HYD_SUCCESS;
324
325 HYDU_FUNC_ENTER();
326
327 HYDU_MALLOC(*fwd_hash, struct fwd_hash *, sizeof(struct fwd_hash), status);
328 (*fwd_hash)->in = in;
329 (*fwd_hash)->out = out;
330
331 (*fwd_hash)->buf_offset = 0;
332 (*fwd_hash)->buf_count = 0;
333
334 (*fwd_hash)->next = NULL;
335
336 status = set_nonblock(in);
337 HYDU_ERR_POP(status, "unable to set out-socket to non-blocking\n");
338
339 status = set_nonblock(out);
340 HYDU_ERR_POP(status, "unable to set out-socket to non-blocking\n");
341
342 fn_exit:
343 HYDU_FUNC_EXIT();
344 return status;
345
346 fn_fail:
347 goto fn_exit;
348 }
349
350 /* This function does not provide any flow control. We just read from
351 * the incoming socket as much as we can and push out to the outgoing
352 * socket as much as we can. This can result in the process calling it
353 * polling continuously waiting for events, but that's a rare case for
354 * stdio (which is what this function is meant to provide
355 * functionality for). */
HYDU_sock_forward_stdio(int in,int out,int * closed)356 HYD_status HYDU_sock_forward_stdio(int in, int out, int *closed)
357 {
358 static struct fwd_hash *fwd_hash_list = NULL;
359 struct fwd_hash *fwd_hash, *tmp;
360 int count;
361 HYD_status status = HYD_SUCCESS;
362
363 HYDU_FUNC_ENTER();
364
365 /* find the fwd hash */
366 for (tmp = fwd_hash_list; tmp; tmp = tmp->next)
367 if (out == tmp->out)
368 break;
369
370 if (tmp == NULL) { /* No hash found; create one */
371 status = alloc_fwd_hash(&fwd_hash, in, out);
372 HYDU_ERR_POP(status, "unable to allocate forward hash\n");
373 if (fwd_hash_list == NULL)
374 fwd_hash_list = fwd_hash;
375 else {
376 for (tmp = fwd_hash_list; tmp->next; tmp = tmp->next);
377 tmp->next = fwd_hash;
378 }
379 }
380 else {
381 fwd_hash = tmp;
382 }
383
384 *closed = 0;
385 if (fwd_hash->buf_count == 0) {
386 /* there is no data in the buffer, read something into it */
387 status = HYDU_sock_read(in, fwd_hash->buf, HYD_TMPBUF_SIZE, &count, closed,
388 HYDU_SOCK_COMM_NONE);
389 HYDU_ERR_POP(status, "read error\n");
390
391 if (!*closed) {
392 fwd_hash->buf_offset = 0;
393 fwd_hash->buf_count += count;
394
395 /* We should never get a zero count, as the upper-layer
396 * should have waited for an event from the demux engine
397 * before calling us. */
398 HYDU_ASSERT(count, status);
399 }
400 }
401
402 if (fwd_hash->buf_count) {
403 /* there is data in the buffer, send it out first */
404 status =
405 HYDU_sock_write(out, fwd_hash->buf + fwd_hash->buf_offset, fwd_hash->buf_count,
406 &count, closed);
407 HYDU_ERR_POP(status, "write error\n");
408
409 if (!*closed) {
410 fwd_hash->buf_offset += count;
411 fwd_hash->buf_count -= count;
412 }
413 }
414
415 /* If the incoming socket is closed, make sure we forward out all
416 * of the buffered data */
417 while (*closed && fwd_hash->buf_count) {
418 status =
419 HYDU_sock_write(out, fwd_hash->buf + fwd_hash->buf_offset, fwd_hash->buf_count,
420 &count, closed);
421 HYDU_ERR_POP(status, "write error\n");
422
423 if (!*closed) {
424 fwd_hash->buf_offset += count;
425 fwd_hash->buf_count -= count;
426 }
427 }
428
429 fn_exit:
430 HYDU_FUNC_EXIT();
431 return status;
432
433 fn_fail:
434 goto fn_exit;
435 }
436
HYDU_sock_get_iface_ip(char * iface,char ** ip)437 HYD_status HYDU_sock_get_iface_ip(char *iface, char **ip)
438 {
439 HYD_status status = HYD_SUCCESS;
440
441 #if defined(HAVE_GETIFADDRS)
442 struct ifaddrs *ifaddr, *ifa;
443 char buf[INET_ADDRSTRLEN];
444 struct sockaddr_in *sa;
445
446 /* Got the interface name; let's query for the IP address */
447 if (getifaddrs(&ifaddr) == -1)
448 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "getifaddrs failed\n");
449
450 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next)
451 if (!strcmp(ifa->ifa_name, iface) && (ifa->ifa_addr) &&
452 (ifa->ifa_addr->sa_family == AF_INET))
453 break;
454
455 if (!ifa)
456 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "unable to find interface %s\n",
457 iface);
458
459 sa = (struct sockaddr_in *) ifa->ifa_addr;
460 #if defined HAVE_INET_NTOP
461 (*ip) = HYDU_strdup((char *)
462 inet_ntop(AF_INET, (const void *) &(sa->sin_addr), buf,
463 MAX_HOSTNAME_LEN));
464 #else
465 (*ip) = NULL;
466 #endif /* HAVE_INET_NTOP */
467 if (!*ip)
468 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR,
469 "unable to find IP for interface %s\n", iface);
470
471 freeifaddrs(ifaddr);
472 #else
473 /* For now just disable interface selection when getifaddrs isn't
474 * available, such as on AIX. In the future we can implement in MPL
475 * something along the lines of MPIDI_GetIPInterface from tcp_getip.c in
476 * nemesis. */
477 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR,
478 "interface selection not supported on this platform\n");
479 #endif
480
481 fn_exit:
482 return status;
483
484 fn_fail:
485 goto fn_exit;
486 }
487
HYDU_sock_is_local(char * host,int * is_local)488 HYD_status HYDU_sock_is_local(char *host, int *is_local)
489 {
490 struct hostent *ht;
491 char *ip1 = NULL, *ip2 = NULL;
492 char buf1[INET_ADDRSTRLEN], buf2[INET_ADDRSTRLEN];
493 struct sockaddr_in *sa_ptr, sa;
494
495 #if defined(HAVE_GETIFADDRS)
496 struct ifaddrs *ifaddr, *ifa;
497 #endif /* HAVE_GETIFADDRS */
498
499 #if defined (HAVE_INET_NTOP)
500 int remote_access;
501 #endif /* HAVE_INET_NTOP */
502
503 HYD_status status = HYD_SUCCESS;
504
505 *is_local = 0;
506
507 /* If we are unable to resolve the remote host name, it need not
508 * be an error. It could mean that the user is using an alias for
509 * the hostname (e.g., an ssh config alias) */
510 if ((ht = gethostbyname(host)) == NULL)
511 goto fn_exit;
512
513 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
514 memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
515
516 #if defined HAVE_INET_NTOP
517 ip1 = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf1,
518 MAX_HOSTNAME_LEN));
519 HYDU_ASSERT(ip1, status);
520
521 status = HYDU_sock_remote_access(ip1, &remote_access);
522 HYDU_ERR_POP(status, "unable to check if the IP is remotely accessible\n");
523
524 if (!remote_access) {
525 *is_local = 1;
526 goto fn_exit;
527 }
528 #else
529 goto fn_exit;
530 #endif /* HAVE_INET_NTOP */
531
532 #if defined(HAVE_GETIFADDRS)
533 /* Got the interface name; let's query for the IP address */
534 if (getifaddrs(&ifaddr) == -1)
535 HYDU_ERR_SETANDJUMP(status, HYD_INTERNAL_ERROR, "getifaddrs failed\n");
536
537 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
538 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
539 sa_ptr = (struct sockaddr_in *) ifa->ifa_addr;
540
541 #if defined HAVE_INET_NTOP
542 ip2 = HYDU_strdup((char *)
543 inet_ntop(AF_INET, (const void *) &(sa_ptr->sin_addr), buf2,
544 MAX_HOSTNAME_LEN));
545 HYDU_ASSERT(ip2, status);
546 #endif /* HAVE_INET_NTOP */
547
548 if (!strcmp(ip1, ip2)) {
549 *is_local = 1;
550 freeifaddrs(ifaddr);
551 goto fn_exit;
552 }
553
554 HYDU_FREE(ip2);
555 ip2 = NULL;
556 }
557 }
558
559 freeifaddrs(ifaddr);
560 #endif
561
562 fn_exit:
563 if (ip1)
564 HYDU_FREE(ip1);
565 if (ip2)
566 HYDU_FREE(ip2);
567 return status;
568
569 fn_fail:
570 goto fn_exit;
571 }
572
HYDU_sock_remote_access(char * host,int * remote_access)573 HYD_status HYDU_sock_remote_access(char *host, int *remote_access)
574 {
575 struct hostent *ht;
576 char *ip = NULL, buf[INET_ADDRSTRLEN];
577 struct sockaddr_in sa;
578 HYD_status status = HYD_SUCCESS;
579
580 if ((ht = gethostbyname(host))) {
581 memset((char *) &sa, 0, sizeof(struct sockaddr_in));
582 memcpy(&sa.sin_addr, ht->h_addr_list[0], ht->h_length);
583
584 #if defined HAVE_INET_NTOP
585 ip = HYDU_strdup((char *) inet_ntop(AF_INET, (const void *) &sa.sin_addr, buf,
586 MAX_HOSTNAME_LEN));
587 HYDU_ASSERT(ip, status);
588 #else
589 ip = HYDU_strdup(host);
590 #endif
591 }
592 else {
593 ip = HYDU_strdup(host);
594 }
595
596 /* FIXME: Comparing the hostname to "127.*" does not seem like a
597 * good way of checking if a hostname is remotely accessible */
598 if (!MPL_strncmp(ip, "127.", strlen("127.")))
599 *remote_access = 0;
600 else
601 *remote_access = 1;
602
603 fn_exit:
604 HYDU_FREE(ip);
605 return status;
606
607 fn_fail:
608 goto fn_exit;
609 }
610
611 HYD_status
HYDU_sock_create_and_listen_portstr(char * iface,char * hostname,char * port_range,char ** port_str,HYD_status (* callback)(int fd,HYD_event_t events,void * userp),void * userp)612 HYDU_sock_create_and_listen_portstr(char *iface, char *hostname, char *port_range,
613 char **port_str,
614 HYD_status(*callback) (int fd, HYD_event_t events,
615 void *userp), void *userp)
616 {
617 int listenfd;
618 char *sport, *real_port_range, *ip = NULL;
619 uint16_t port;
620 HYD_status status = HYD_SUCCESS;
621
622 /* Listen on a port in the port range */
623 port = 0;
624 real_port_range = port_range ? HYDU_strdup(port_range) : NULL;
625 status = HYDU_sock_listen(&listenfd, real_port_range, &port);
626 HYDU_ERR_POP(status, "unable to listen on port\n");
627
628 /* Register the listening socket with the demux engine */
629 status = HYDT_dmx_register_fd(1, &listenfd, HYD_POLLIN, userp, callback);
630 HYDU_ERR_POP(status, "unable to register fd\n");
631
632 /* Create a port string for MPI processes to use to connect to */
633 if (iface) {
634 status = HYDU_sock_get_iface_ip(iface, &ip);
635 HYDU_ERR_POP(status, "unable to get network interface IP\n");
636 }
637 else if (hostname) {
638 ip = HYDU_strdup(hostname);
639 }
640 else {
641 char localhost[MAX_HOSTNAME_LEN] = { 0 };
642
643 status = HYDU_gethostname(localhost);
644 HYDU_ERR_POP(status, "unable to get local hostname\n");
645
646 ip = HYDU_strdup(localhost);
647 }
648
649 sport = HYDU_int_to_str(port);
650 HYDU_MALLOC(*port_str, char *, strlen(ip) + 1 + strlen(sport) + 1, status);
651 HYDU_snprintf(*port_str, strlen(ip) + 1 + strlen(sport) + 1, "%s:%s", ip, sport);
652 HYDU_FREE(sport);
653
654 fn_exit:
655 if (ip)
656 HYDU_FREE(ip);
657 return status;
658
659 fn_fail:
660 goto fn_exit;
661 }
662
HYDU_sock_cloexec(int fd)663 HYD_status HYDU_sock_cloexec(int fd)
664 {
665 int flags;
666 HYD_status status = HYD_SUCCESS;
667
668 #if defined HAVE_FCNTL
669 flags = fcntl(fd, F_GETFD, 0);
670 if (flags < 0)
671 HYDU_ERR_POP(status, "unable to get fd flags\n");
672 flags |= FD_CLOEXEC;
673 if (fcntl(fd, F_SETFD, flags) < 0)
674 HYDU_ERR_POP(status, "unable to set fd flags\n");
675 #endif /* HAVE_FCNTL */
676
677 fn_exit:
678 return status;
679
680 fn_fail:
681 goto fn_exit;
682 }
683