in spamc/libspamc.c [449:608]
static int _try_to_connect_tcp(const struct transport *tp, int *sockptr)
{
int numloops;
int origerr = 0;
int ret;
#ifdef SPAMC_HAS_ADDRINFO
struct addrinfo *res = NULL;
char port[SPAMC_MAXSERV-1]; /* port, for logging */
#else
int res = PF_INET;
#endif
char host[SPAMC_MAXHOST-1]; /* hostname, for logging */
int connect_retries, retry_sleep;
assert(tp != 0);
assert(sockptr != 0);
assert(tp->nhosts > 0);
/* default values */
retry_sleep = tp->retry_sleep;
connect_retries = tp->connect_retries;
if (connect_retries == 0) {
connect_retries = 3;
}
if (retry_sleep < 0) {
retry_sleep = 1;
}
for (numloops = 0; numloops < connect_retries; numloops++) {
const int hostix = numloops % tp->nhosts;
int status, mysock;
int innocent = 0;
/*--------------------------------------------------------
* We always start by creating the socket, as we get only
* one attempt to connect() on each one. If this fails,
* we're done.
*/
#ifdef SPAMC_HAS_ADDRINFO
res = tp->hosts[hostix];
while(res) {
char *family = NULL;
switch(res->ai_family) {
case AF_INET:
family = "AF_INET";
break;
case AF_INET6:
family = "AF_INET6";
break;
default:
family = "Unknown";
break;
}
if ((ret = _opensocket(tp->flags, res, &mysock)) != EX_OK) {
res = res->ai_next;
continue;
}
getnameinfo(res->ai_addr, res->ai_addrlen,
host, sizeof(host),
port, sizeof(port),
NI_NUMERICHOST|NI_NUMERICSERV);
#ifdef DO_CONNECT_DEBUG_SYSLOGS
libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL,
"dbg: connect(%s) to spamd (host %s, port %s) (try #%d of %d)",
family, host, port, numloops + 1, connect_retries);
#endif
/* this is special-cased so that we have an address we can
* safely use as an "always fail" test case */
if (!strcmp(host, "255.255.255.255")) {
libspamc_log(tp->flags, LOG_ERR,
"connect to spamd on %s failed, broadcast addr",
host);
status = -1;
}
else {
status = timeout_connect(mysock, res->ai_addr, res->ai_addrlen);
if (status != 0) origerr = spamc_get_errno();
}
#else
struct sockaddr_in addrbuf;
const char *ipaddr;
const char* family="AF_INET";
if ((ret = _opensocket(tp->flags, PF_INET, &mysock)) != EX_OK)
return ret;
memset(&addrbuf, 0, sizeof(addrbuf));
addrbuf.sin_family = AF_INET;
addrbuf.sin_port = htons(tp->port);
addrbuf.sin_addr = tp->hosts[hostix];
ipaddr = inet_ntoa(addrbuf.sin_addr);
/* make a copy in host, for logging (bug 5577) */
strncpy (host, ipaddr, sizeof(host) - 1);
#ifdef DO_CONNECT_DEBUG_SYSLOGS
libspamc_log(tp->flags, LOG_DEBUG,
"dbg: connect(AF_INET) to spamd at %s (try #%d of %d)",
ipaddr, numloops + 1, connect_retries);
#endif
/* this is special-cased so that we have an address we can
* safely use as an "always fail" test case */
if (!strcmp(ipaddr, "255.255.255.255")) {
libspamc_log(tp->flags, LOG_ERR,
"connect to spamd on %s failed, broadcast addr",
ipaddr);
status = -1;
}
else {
status = timeout_connect(mysock, (struct sockaddr *) &addrbuf,
sizeof(addrbuf));
if (status != 0) origerr = spamc_get_errno();
}
#endif
if (status != 0) {
closesocket(mysock);
innocent = origerr == ECONNREFUSED && numloops+1 < tp->nhosts;
libspamc_log(tp->flags, innocent ? LOG_DEBUG : LOG_ERR,
"connect to spamd on %s failed, retrying (#%d of %d): %s",
host, numloops+1, connect_retries,
#ifdef _WIN32
origerr
#else
strerror(origerr)
#endif
);
} else {
#ifdef DO_CONNECT_DEBUG_SYSLOGS
libspamc_log(tp->flags, CONNECT_DEBUG_LEVEL,
"dbg: connect(%s) to spamd done",family);
#endif
*sockptr = mysock;
return EX_OK;
}
#ifdef SPAMC_HAS_ADDRINFO
res = res->ai_next;
}
#endif
if (numloops+1 < connect_retries && !innocent) sleep(retry_sleep);
} /* for(numloops...) */
libspamc_log(tp->flags, LOG_ERR,
"connection attempt to spamd aborted after %d retries",
connect_retries);
return _translate_connect_errno(origerr);
}