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