[PATCH] Improve NNTPconnect error reporting
Ian Jackson
ijackson at chiark.greenend.org.uk
Sat May 22 23:18:00 UTC 2010
In inn2 2.4.5, NNTPconnect does not always report errors very well.
In particular:
* If the domain name lookup fails or gives a permanent error, it
returns -1, leaves the buffer without a message, but doesn't set
errno; inn's internal callers seem to assume that errno will be set
appropriately if the buffer has no message.
* Connection failures of various kinds result in a pretty much
arbitrary choice of errno. In particular, I think (although I
haven't tested this) that on some systems with IPv6 library support
but no kernel support a useful errno value from connect failing
with ECONNREFUSED (say) may be replaced by a comparatively useless
one from socket saying Address family not supported.
* The documentation doesn't make it clear how to handle the return
values.
In the patch below I address this by always arranging for the buffer
to contain a useful message. It either contains the message from the
peer, or a message in [square brackets] indicating which call failed
and how, including the results from gai_strerror et al.
I don't think this is perfect but it does at least mean that you
always get a useful error message.
Ian.
diff --git a/lib/remopen.c b/lib/remopen.c
index ab8a770..595f620 100644
--- a/lib/remopen.c
+++ b/lib/remopen.c
@@ -19,6 +19,16 @@
#include "paths.h"
/*
+** store an error message in buff like libinn(3) says NNTPconnect does
+*/
+static void store_error(char *buff, const char *string1, const char *string2) {
+ /* we put these in [...] to make it easier to tell them apart
+ * from messages sent by the server */
+ snprintf(buff, NNTP_STRLEN, "[%s%s]", string1, string2);
+ buff[NNTP_STRLEN-1] = 0;
+}
+
+/*
** Open a connection to an NNTP server and create stdio FILE's for talking
** to it. Return -1 on error.
*/
@@ -29,6 +39,7 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
int i = -1;
int j;
int oerrno;
+ int gai_r;
FILE *F;
#ifdef HAVE_INET6
struct addrinfo hints, *ressave, *addr;
@@ -53,8 +64,11 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
sprintf(portbuf, "%d", port);
- if (getaddrinfo(host, portbuf, &hints, &addr) != 0)
+ if ((gai_r = getaddrinfo(host, portbuf, &hints, &addr)) != 0) {
+ store_error(buff, "getaddrinfo failed: ", gai_strerror(gai_r));
+ errno = 0;
return -1;
+ }
for (ressave = addr; addr; addr = addr->ai_next) {
if ((i = socket(addr->ai_family, addr->ai_socktype,
@@ -103,6 +117,7 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
/* all connect(2) calls failed or some other error has occurred */
oerrno = errno;
close(i);
+ store_error(buff, "connect(s) failed: ", strerror(oerrno));
errno = oerrno;
return -1;
}
@@ -120,9 +135,12 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
}
else if ((hp = gethostbyname(host)) != NULL)
ap = hp->h_addr_list;
- else
+ else {
/* Not a host name. */
+ store_error(buff, "gethostbyname failed: ", hstrerror(h_errno));
+ errno = 0;
return -1;
+ }
/* Set up the socket address. */
memset(&server, 0, sizeof server);
@@ -139,20 +157,31 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
client.sin_len = sizeof( struct sockaddr_in );
#endif
if (innconf->sourceaddress) {
- if (!inet_aton(innconf->sourceaddress, &client.sin_addr))
+ if (!inet_aton(innconf->sourceaddress, &client.sin_addr)) {
+ store_error(buff, "inet_aton failed on innconf's"
+ " source address: ", innconf->sourceaddress);
+ errno = EINVAL;
return -1;
+ }
} else
client.sin_addr.s_addr = htonl(INADDR_ANY);
-
+
/* Loop through the address list, trying to connect. */
for (; ap && *ap; ap++) {
/* Make a socket and try to connect. */
- if ((i = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0)
+ if ((i = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) {
+ if (!buff[0]) {
+ oerrno = errno;
+ store_error(buff, "create socket failed: ", strerror(oerrno));
+ errno = oerrno;
+ }
break;
+ }
/* Bind to the source address we want. */
if (bind(i, (struct sockaddr *)&client, sizeof client) < 0) {
oerrno = errno;
close(i);
+ store_error(buff, "bind failed: ", strerror(oerrno));
errno = oerrno;
continue;
}
@@ -164,6 +193,7 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
if (connect(i, (struct sockaddr *)&server, sizeof server) < 0) {
oerrno = errno;
close(i);
+ store_error(buff, "connect failed: ", strerror(oerrno));
errno = oerrno;
continue;
}
@@ -174,9 +204,13 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
oerrno = errno;
close(i);
errno = oerrno;
+ store_error(buff, "fdopen failed: ", strerror(oerrno));
+ errno = EINVAL;
return -1;
}
if (fgets(buff, sizeof mybuff, F) == NULL) {
+ if (!ferror(F)) store_error(buff, "peer closed connection","");
+ else store_error(buff, "fgets failed: ", strerror(errno));
oerrno = errno;
fclose(F);
errno = oerrno;
@@ -194,12 +228,16 @@ int NNTPconnect(char *host, int port, FILE **FromServerp, FILE **ToServerp, char
if ((*ToServerp = fdopen(dup(i), "w")) == NULL) {
oerrno = errno;
fclose(F);
+ store_error(buff, "fdopen/dup failed: ", strerror(oerrno));
errno = oerrno;
return -1;
}
return 0;
}
+ if (!buff[0])
+ store_error(buff, "no address(es) for host","");
+
return -1;
}
--
Ian Jackson personal email: <ijackson at chiark.greenend.org.uk>
These opinions are my own. http://www.chiark.greenend.org.uk/~ijackson/
PGP2 key 1024R/0x23f5addb, fingerprint 5906F687 BD03ACAD 0D8E602E FCF37657
More information about the inn-workers
mailing list