#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <netdb.h>
#include "types.h"
#include "distcc.h"
#include "trace.h"
#include "exitcode.h"
#include "clinet.h"
#include "util.h"
#include "netutil.h"
#ifndef h_errno
extern int h_errno;
#endif
const int dcc_connect_timeout = 4;
int dcc_connect_by_addr(struct sockaddr *sa, size_t salen,
int *p_fd)
{
int fd;
int ret;
char *s;
int failed;
int connecterr;
int tries = 3;
dcc_sockaddr_to_string(sa, salen, &s);
rs_trace("started connecting to %s", s);
if ((fd = socket(sa->sa_family, SOCK_STREAM, 0)) == -1) {
rs_log_error("failed to create socket: %s", strerror(errno));
ret = EXIT_CONNECT_FAILED;
goto out_failed;
}
dcc_set_nonblocking(fd);
do
failed = connect(fd, sa, salen);
while (failed == -1 &&
(errno == EINTR ||
(errno == EAGAIN && tries-- && poll(NULL, 0, 500) == 0)));
if (failed == -1 && errno != EINPROGRESS) {
rs_log(RS_LOG_ERR|RS_LOG_NONAME,
"failed to connect to %s: %s", s, strerror(errno));
ret = EXIT_CONNECT_FAILED;
goto out_failed;
}
do {
socklen_t len;
if ((ret = dcc_select_for_write(fd, dcc_connect_timeout))) {
rs_log(RS_LOG_ERR|RS_LOG_NONAME,
"timeout while connecting to %s", s);
goto out_failed;
}
connecterr = -1;
len = sizeof(connecterr);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (char *)&connecterr, &len) < 0) {
rs_log_error("getsockopt SO_ERROR failed?!");
ret = EXIT_CONNECT_FAILED;
goto out_failed;
}
} while (connecterr == EINPROGRESS);
if (connecterr) {
rs_log(RS_LOG_ERR|RS_LOG_NONAME,
"nonblocking connect to %s failed: %s", s, strerror(connecterr));
ret = EXIT_CONNECT_FAILED;
goto out_failed;
}
*p_fd = fd;
free(s);
return 0;
out_failed:
free(s);
return ret;
}
#if defined(ENABLE_RFC2553)
int dcc_connect_by_name(const char *host, int port, int *p_fd)
{
struct addrinfo hints;
struct addrinfo *res;
int error;
int ret;
char portname[20];
rs_trace("connecting to %s port %d", host, port);
snprintf(portname, sizeof portname, "%d", port);
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
error = getaddrinfo(host, portname, &hints, &res);
if (error) {
rs_log_error("failed to resolve host %s port %d: %s", host, port,
gai_strerror(error));
return EXIT_CONNECT_FAILED;
}
do {
ret = dcc_connect_by_addr(res->ai_addr, res->ai_addrlen, p_fd);
} while (ret != 0 && (res = res->ai_next));
return ret;
}
#else
int dcc_connect_by_name(const char *host, int port, int *p_fd)
{
struct sockaddr_in sock_out;
struct hostent *hp;
hp = gethostbyname(host);
if (!hp) {
rs_log_error("failed to look up host \"%s\": %s", host,
hstrerror(h_errno));
return EXIT_CONNECT_FAILED;
}
memcpy(&sock_out.sin_addr, hp->h_addr, (size_t) hp->h_length);
sock_out.sin_port = htons((in_port_t) port);
sock_out.sin_family = PF_INET;
return dcc_connect_by_addr((struct sockaddr *) &sock_out,
sizeof sock_out, p_fd);
}
#endif