#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <netdb.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#ifdef HAVE_ARPA_NAMESER_H
# include <arpa/nameser.h>
#endif
#include <arpa/inet.h>
#ifdef HAVE_RESOLV_H
# include <resolv.h>
#endif
#include <netdb.h>
#include "types.h"
#include "exitcode.h"
#include "distcc.h"
#include "trace.h"
#include "util.h"
#include "srvnet.h"
#include "access.h"
#include "netutil.h"
#include "snprintf.h"
#ifdef O_NONBLOCK
# define NONBLOCK_FLAG O_NONBLOCK
#elif defined(SYSV)
# define NONBLOCK_FLAG O_NDELAY
#else
# define NONBLOCK_FLAG FNDELAY
#endif
#ifndef AF_UNIX
# define AF_UNIX AF_LOCAL
#endif
#ifndef HAVE_HSTRERROR
const char *hstrerror(int err) {
switch (err) {
case HOST_NOT_FOUND:
return "Host not found";
case TRY_AGAIN:
return "Name server not contacted";
case NO_RECOVERY:
return "Non-recoverable error";
case NO_ADDRESS:
return "No IP address for host";
default:
return "Unknown error";
}
}
#endif
void dcc_set_blocking(int fd)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) == -1)
return;
if (val & NONBLOCK_FLAG) {
val &= ~NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}
void dcc_set_nonblocking(int fd)
{
int val;
if ((val = fcntl(fd, F_GETFL, 0)) == -1)
return;
if (!(val & NONBLOCK_FLAG)) {
val |= NONBLOCK_FLAG;
fcntl(fd, F_SETFL, val);
}
}
void dcc_defer_accept(int POSSIBLY_UNUSED(listen_fd))
{
#ifdef TCP_DEFER_ACCEPT
int val = 1;
if (!dcc_getenv_bool("DISTCC_TCP_DEFER_ACCEPT", 1)) {
rs_trace("TCP_DEFER_ACCEPT disabled");
return;
}
if (setsockopt(listen_fd, SOL_TCP, TCP_DEFER_ACCEPT, &val, sizeof val) == -1) {
rs_log_warning("failed to set TCP_DEFER_ACCEPT: %s", strerror(errno));
} else {
rs_trace("TCP_DEFER_ACCEPT turned on");
}
#endif
}
#ifdef ENABLE_RFC2553
int dcc_sockaddr_to_string(struct sockaddr *sa,
size_t salen,
char **p_buf)
{
int err;
char host[1024];
char port[32];
if (!sa) {
*p_buf = strdup("NOTSOCKET");
return 0;
} else if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) {
err = getnameinfo(sa, salen,
host, sizeof host,
port, sizeof port,
NI_NUMERICHOST | NI_NUMERICSERV);
if (err) {
rs_log_warning("getnameinfo failed: %s", gai_strerror(err));
*p_buf = strdup("(UNKNOWN)");
return 0;
}
asprintf(p_buf, "%s:%s", host, port);
} else if (sa->sa_family == AF_UNIX) {
struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path);
} else {
asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family);
}
return 0;
}
#else
int dcc_sockaddr_to_string(struct sockaddr *sa,
size_t UNUSED(salen),
char **p_buf)
{
if (!sa) {
*p_buf = strdup("NOTSOCKET");
return 0;
} else if (sa->sa_family == AF_INET) {
struct sockaddr_in *sain = (struct sockaddr_in *) (void *) sa;
asprintf(p_buf, "%s:%d", inet_ntoa(sain->sin_addr),
ntohs(sain->sin_port));
} else if (sa->sa_family == AF_UNIX) {
struct sockaddr_un *sa_un = (struct sockaddr_un *) sa;
asprintf(p_buf, "UNIX-DOMAIN %s", sa_un->sun_path);
} else {
asprintf(p_buf, "UNKNOWN-FAMILY %d", sa->sa_family);
}
return 0;
}
#endif