/[Apache-SVN]/spamassassin/trunk/spamc/libspamc.c
ViewVC logotype

Diff of /spamassassin/trunk/spamc/libspamc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

--- spamassassin/trunk/spamc/libspamc.c	2005/06/28 12:01:43	202162
+++ spamassassin/trunk/spamc/libspamc.c	2005/06/28 12:17:58	202163
@@ -57,6 +57,7 @@
 #include <sys/time.h>
 #endif
 
+/* FIXME: Make this configurable */
 #define MAX_CONNECT_RETRIES 3
 #define CONNECT_RETRY_SLEEP 1
 
@@ -559,6 +560,8 @@ static int _message_read_bsmtp(int fd, s
 
 int message_read(int fd, int flags, struct message *m)
 {
+    assert(m != NULL);
+
     libspamc_timeout = 0;
 
     /* create the "private" part of the struct message */
@@ -590,6 +593,8 @@ long message_write(int fd, struct messag
     off_t jlimit;
     char buffer[1024];
 
+    assert(m != NULL);
+
     if (m->priv->flags & SPAMC_CHECK_ONLY) {
 	if (m->is_spam == EX_ISSPAM || m->is_spam == EX_NOTSPAM) {
 	    return full_write(fd, 1, m->out, m->out_len);
@@ -856,6 +861,9 @@ int message_filter(struct transport *tp,
     SSL *ssl = NULL;
     SSL_METHOD *meth;
 
+    assert(tp != NULL);
+    assert(m != NULL);
+
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
 	SSLeay_add_ssl_algorithms();
@@ -1079,6 +1087,8 @@ int message_process(struct transport *tr
     int ret;
     struct message m;
 
+    assert(trans != NULL);
+
     m.type = MESSAGE_NONE;
 
     m.max_len = max_size;
@@ -1127,6 +1137,9 @@ int message_tell(struct transport *tp, c
     SSL *ssl = NULL;
     SSL_METHOD *meth;
 
+    assert(tp != NULL);
+    assert(m != NULL);
+
     if (flags & SPAMC_USE_SSL) {
 #ifdef SPAMC_SSL
 	SSLeay_add_ssl_algorithms();
@@ -1327,7 +1340,8 @@ int message_tell(struct transport *tp, c
 
 void message_cleanup(struct message *m)
 {
-    if (m->outbuf)
+    assert(m != NULL);
+    if (m->outbuf != NULL)
         free(m->outbuf);
     if (m->raw != NULL)
         free(m->raw);
@@ -1418,7 +1432,9 @@ static void _randomize_hosts(struct tran
 */
 int transport_setup(struct transport *tp, int flags)
 {
-    struct hostent *hp = 0;
+    struct hostent *hp;
+    char *hostlist, *hostname;
+    int errbits;
     char **addrp;
 
 #ifdef _WIN32
@@ -1432,10 +1448,9 @@ int transport_setup(struct transport *tp
 
 #endif
 
+    assert(tp != NULL);
     tp->flags = flags;
 
-    assert(tp != 0);
-
     switch (tp->type) {
 #ifndef _WIN32
     case TRANSPORT_UNIX:
@@ -1448,82 +1463,124 @@ int transport_setup(struct transport *tp
         return EX_OK;
 
     case TRANSPORT_TCP:
-        if (NULL == (hp = gethostbyname(tp->hostname))) {
-            int origherr = h_errno;	/* take a copy before syslog() */
-
-            libspamc_log(flags, LOG_ERR, "gethostbyname(%s) failed: h_errno=%d",
-                    tp->hostname, origherr);
-            switch (origherr) {
-            case HOST_NOT_FOUND:
-            case NO_ADDRESS:
-            case NO_RECOVERY:
-                return EX_NOHOST;
-            case TRY_AGAIN:
-                return EX_TEMPFAIL;
-            default:
-                return EX_OSERR;
-            }
-        }
-
-                /*--------------------------------------------------------
-                * If we have no hosts at all, or if they are some other
-                * kind of address family besides IPv4, then we really
-                * just have no hosts at all.
-                */
-        if (hp->h_addr_list[0] == 0) {
-            /* no hosts in this list */
-            return EX_NOHOST;
-        }
+        if ((hostlist = strdup(tp->hostname)) == NULL)
+            return EX_OSERR;
 
-        if (hp->h_length != sizeof tp->hosts[0]
-            || hp->h_addrtype != AF_INET) {
-            /* FAIL - bad size/protocol/family? */
-            return EX_NOHOST;
-        }
-
-                /*--------------------------------------------------------
-                * Copy all the IP addresses into our private structure.
-                * This gets them out of the resolver's static area and
-                * means we won't ever walk all over the list with other
-                * calls.
-                */
+        /* We want to return the least permanent error, in this bitmask we
+         * record the errors seen with:
+         *  0: no error
+         *  1: EX_TEMPFAIL
+         *  2: EX_NOHOST
+         * EX_OSERR will return immediately.
+         * Bits aren't reset so a check against nhosts is needed to determine
+         * if something went wrong.
+         */
+        errbits = 0;
         tp->nhosts = 0;
-
-        for (addrp = hp->h_addr_list; *addrp; addrp++) {
-            if (tp->nhosts >= TRANSPORT_MAX_HOSTS - 1) {
-                libspamc_log(flags, LOG_ERR, "hit limit of %d hosts, ignoring remainder",
-                      TRANSPORT_MAX_HOSTS - 1);
-                break;
+        /* Start with char offset in front of the string because we'll add 
+         * one in the loop
+         */
+        hostname = hostlist - 1;
+        do {
+            char *hostend;
+            
+            hostname += 1;
+            hostend = strchr(hostname, ',');
+            if (hostend != NULL) {
+                *hostend = '\0';
+            }
+            
+            if ((hp = gethostbyname(hostname)) == NULL) {
+                int origerr = h_errno; /* take a copy before syslog() */
+                libspamc_log(flags, LOG_DEBUG, "gethostbyname(%s) failed: h_errno=%d",
+                    hostname, origerr);
+                switch (origerr) {
+                case TRY_AGAIN:
+                    errbits |= 1;
+                    break;
+                case HOST_NOT_FOUND:
+                case NO_ADDRESS:
+                case NO_RECOVERY:
+                    errbits |= 2;
+                    break;
+                default:
+                    /* should not happen, all errors are checked above */
+                    free(hostlist);
+                    return EX_OSERR;
+                }
+                goto nexthost; /* try next host in list */
+            }
+            
+            /* If we have no hosts at all, or if they are some other
+             * kind of address family besides IPv4, then we really
+             * just have no hosts at all. TODO: IPv6
+             */
+            if (hp->h_addr_list[0] == NULL
+             || hp->h_length != sizeof tp->hosts[0]
+             || hp->h_addrtype != AF_INET) {
+                /* no hosts/bad size/wrong family */
+                errbits |= 1;
+                goto nexthost; /* try next host in list */
             }
 
-            memcpy(&tp->hosts[tp->nhosts], *addrp, sizeof tp->hosts[0]);
-
-            tp->nhosts++;
+            /* Copy all the IP addresses into our private structure.
+             * This gets them out of the resolver's static area and
+             * means we won't ever walk all over the list with other
+             * calls.
+             */
+            for (addrp = hp->h_addr_list; *addrp; addrp++) {
+                if (tp->nhosts == TRANSPORT_MAX_HOSTS) {
+                    libspamc_log(flags, LOG_NOTICE, "hit limit of %d hosts, ignoring remainder",
+                        TRANSPORT_MAX_HOSTS);
+                    break;
+                }
+                memcpy(&tp->hosts[tp->nhosts], *addrp, hp->h_length);
+                tp->nhosts++;
+            }
+            
+nexthost:
+            hostname = hostend;
+        } while (hostname != NULL);
+        free(hostlist);
+        
+        if (tp->nhosts == 0) {
+            if (errbits & 1) {
+                libspamc_log(flags, LOG_ERR, "could not resolve any hosts (%s): a temporary error occurred",
+                    tp->hostname); 
+                return EX_TEMPFAIL;
+            }
+            else {
+                libspamc_log(flags, LOG_ERR, "could not resolve any hosts (%s): no such host",
+                    tp->hostname); 
+                return EX_NOHOST;
+            }
         }
-
-                /*--------------------------------------------------------
-                * QUASI-LOAD-BALANCING
-                *
-                * If the user wants to do quasi load balancing, "rotate"
-                * the list by a random amount based on the current time.
-                * This may later be truncated to a single item. This is
-                * meaningful only if we have more than one host.
-                */
+        
+        /* QUASI-LOAD-BALANCING
+         *
+         * If the user wants to do quasi load balancing, "rotate"
+         * the list by a random amount based on the current time.
+         * This may later be truncated to a single item. This is
+         * meaningful only if we have more than one host.
+         */
         if ((flags & SPAMC_RANDOMIZE_HOSTS) && tp->nhosts > 1) {
             _randomize_hosts(tp);
         }
 
-                /*--------------------------------------------------------
-                * If the user wants no fallback, simply truncate the host
-                * list to just one - this pretends that this is the extent
-                * of our connection list - then it's not a special case.
-                */
+        /* If the user wants no fallback, simply truncate the host
+         * list to just one - this pretends that this is the extent
+         * of our connection list - then it's not a special case.
+         */
         if (!(flags & SPAMC_SAFE_FALLBACK) && tp->nhosts > 1) {
             /* truncating list */
             tp->nhosts = 1;
         }
+        
+        return EX_OK;
     }
-    return EX_OK;
+    
+    /* oops, unknown transport type */
+    return EX_OSERR;
 }
 
 /* --------------------------------------------------------------------------- */

 

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26