static int _try_to_connect_tcp()

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);
}