commit 09bda953d3b4050864a963801e3d6c952fb9fafa
parent 6978db7265432123927e85930c131872f971319c
Author: Mario Rosell R. Martinez <mario@mariorosell.es>
Date: Fri, 20 Mar 2026 12:47:16 +0100
Make error handling clearer.
Made a new struct, AnntpErrCode, and added some error codes to it rather than
-1. ssize_t-returning functions return the error code in negative.
Diffstat:
| M | anntp.h | | | 122 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
1 file changed, 90 insertions(+), 32 deletions(-)
diff --git a/anntp.h b/anntp.h
@@ -48,6 +48,9 @@
#define Bool int
#define true 1
#define false 0
+#define ANNTPE(e) (-(ssize_t)(e))
+#define ANNTP_ISERR(x) ((x) < 0)
+#define ANNTP_CODE(x) ((AnntpErrCode)(-(x)))
typedef unsigned char uchar_t;
@@ -58,7 +61,18 @@ enum anntp_state {
ANS_ERROR,
};
+/* NOTE: often given as negative for functions returning ssize_t */
+enum anntp_errcode {
+ ANE_OK = 0,
+ ANE_PARAMS,
+ ANE_TLS,
+ ANE_IO,
+ ANE_PROTO,
+ ANE_AUTH,
+};
+
typedef enum anntp_state AnntpState;
+typedef enum anntp_errcode AnntpErrCode;
struct anntp_connection {
int fd; /* socket file descriptor */
@@ -83,15 +97,16 @@ typedef int (*AnntpLineCb)(const char* line, void* extra);
ANNTP_API void anntp_init(void);
ANNTP_API AnntpConnection* anntp_mkconn(const char* host, const char* port, Bool tls);
-ANNTP_API void anntp_freeconn(AnntpConnection* conn);
-ANNTP_API ssize_t anntp_read(AnntpConnection* conn, uchar_t* buf, size_t bufsize);
-ANNTP_API ssize_t anntp_write(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
-ANNTP_API ssize_t anntp_write_all(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
-ANNTP_API ssize_t anntp_writeline(AnntpConnection* conn, const char* buf);
-ANNTP_API ssize_t anntp_readline(AnntpConnection* conn, char* buf, size_t maxlen);
-ANNTP_API ssize_t anntp_readdot(AnntpConnection* conn, char* buf, size_t maxlen);
-ANNTP_API int anntp_readdot_cb(AnntpConnection* conn, AnntpLineCb cb, void* extra);
-ANNTP_API int anntp_auth(AnntpConnection* conn, const char* login, const char* password);
+ANNTP_API void anntp_freeconn(AnntpConnection* conn);
+ANNTP_API ssize_t anntp_read(AnntpConnection* conn, uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_write(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_write_all(AnntpConnection* conn, const uchar_t* buf, size_t bufsize);
+ANNTP_API ssize_t anntp_writeline(AnntpConnection* conn, const char* buf);
+ANNTP_API ssize_t anntp_readline(AnntpConnection* conn, char* buf, size_t maxlen);
+ANNTP_API ssize_t anntp_readdot(AnntpConnection* conn, char* buf, size_t maxlen);
+ANNTP_API int anntp_readdot_cb(AnntpConnection* conn, AnntpLineCb cb, void* extra);
+ANNTP_API int anntp_auth(AnntpConnection* conn, const char* login, const char* password);
+ANNTP_API char* anntp_strerr(AnntpErrCode err);
#endif /* ANNTP_H */
@@ -209,25 +224,33 @@ anntp_freeconn(AnntpConnection* cv)
ssize_t
anntp_read(AnntpConnection* cv, uchar_t* buf, size_t len)
{
- if (!cv || !buf) return -1;
+ if (!cv || !buf) ANNTPE(ANE_PARAMS);
#ifdef ANNTP_TLS
- if (cv->use_tls && cv->ssl) return SSL_read(cv->ssl, buf, (int)len);
+ if (cv->use_tls && cv->ssl) {
+ int n = SSL_read(cv->ssl, buf, (int)len);
+ return (n <= 0) ? ANNTPE(ANE_TLS) : n;
+ }
#endif
- return read(cv->fd, buf, len);
+ ssize_t n = read(cv->fd, buf, len);
+ return (n < 0) ? ANNTPE(ANE_IO) : n;
}
ssize_t
anntp_write(AnntpConnection* cv, const uchar_t* buf, size_t len)
{
- if (!cv || !buf) return -1;
+ if (!cv || !buf) return ANNTPE(ANE_PARAMS);
#ifdef ANNTP_TLS
- if (cv->use_tls && cv->ssl) return SSL_write(cv->ssl, buf, (int)len);
+ if (cv->use_tls && cv->ssl) {
+ int n = SSL_write(cv->ssl, buf, (int)len);
+ return (n <= 0) ? ANNTPE(ANE_TLS) : n;
+ }
#endif
- return write(cv->fd, buf, len);
+ ssize_t n = write(cv->fd, buf, len);
+ return (n < 0) ? ANNTPE(ANE_IO) : write(cv->fd, buf, len);
}
ssize_t
@@ -245,7 +268,7 @@ anntp_write_all(AnntpConnection* cv, const uchar_t* buf, size_t len)
ssize_t
anntp_readline(AnntpConnection* cv, char* buf, size_t maxlen)
{
- if (!cv || !buf || maxlen == 0) return -1;
+ if (!cv || !buf || maxlen == 0) return ANNTPE(ANE_PARAMS);
size_t pos = 0;
@@ -325,7 +348,7 @@ anntp_readdot(AnntpConnection* cv, char* buf, size_t maxlen)
int
anntp_readdot_cb(AnntpConnection* cv, AnntpLineCb cb, void* extra)
{
- if (!cv || !cb) return -1;
+ if (!cv || !cb) return ANE_PARAMS;
char line[ANNTP_BUFSIZE];
ssize_t n;
@@ -333,7 +356,7 @@ anntp_readdot_cb(AnntpConnection* cv, AnntpLineCb cb, void* extra)
for (;;) {
n = anntp_readline(cv, line, sizeof(line));
if (n <= 0)
- return -1;
+ return ANE_IO;
/* logic here is a bit like on anntp_readdot */
if (strcmp(line, ".\r\n") == 0)
@@ -344,10 +367,10 @@ anntp_readdot_cb(AnntpConnection* cv, AnntpLineCb cb, void* extra)
out++;
if (cb(out, extra) != 0)
- return 1; /* user aborted */
+ return ANE_OK; /* user aborted */
}
- return 0;
+ return ANE_OK;
}
/* NOTE: I have a gut feeling this auth mechanism is probably a bit insecure... */
@@ -363,7 +386,7 @@ anntp_auth(AnntpConnection* cv, const char* user, const char* pass)
*/
if (!cv || !user || !pass)
- return -1;
+ return ANE_PARAMS;
char line[ANNTP_BUFSIZE];
char cmd[ANNTP_BUFSIZE];
@@ -374,21 +397,21 @@ anntp_auth(AnntpConnection* cv, const char* user, const char* pass)
n = anntp_writeline(cv, cmd);
if (n <= 0)
- return -1;
+ return ANE_IO;
/* read response */
n = anntp_readline(cv, line, sizeof(line));
if (n <= 0)
- return -1;
+ return ANE_IO;
/* already authenticated */
if (strncmp(line, "281", 3) == 0) {
- return 0;
+ return ANE_OK; /* it isn't an error to be already authenticated */
}
/* must be 381 to continue */
if (strncmp(line, "381", 3) != 0) {
- return -1;
+ return ANE_PROTO; /* that isn't a valid response, probably */
}
snprintf(cmd, sizeof(cmd), "AUTHINFO PASS %s", pass);
@@ -399,19 +422,19 @@ anntp_auth(AnntpConnection* cv, const char* user, const char* pass)
memset(cmd, 0, sizeof(cmd));
if (n <= 0)
- return -1;
+ return ANE_IO;
n = anntp_readline(cv, line, sizeof(line));
if (n <= 0)
- return -1;
+ return ANE_IO;
/* success */
if (strncmp(line, "281", 3) == 0) {
- return 0;
+ return ANE_OK;
}
/* failure */
- return -1;
+ return ANE_AUTH;
}
/* fill read buffer with data */
@@ -430,11 +453,46 @@ _afillbuf(AnntpConnection* c)
if (n > 0) {
c->read_len = (size_t)n;
c->read_pos = 0;
- } else {
- c->read_len = 0;
+ return n;
}
- return n;
+ c->read_len = 0;
+
+ if (n == 0)
+ return 0; /* EOF */
+
+#ifdef ANNTP_TLS
+ if (c->use_tls && c->ssl)
+ return ANNTPE(ANE_TLS);
+#endif
+
+ return ANNTPE(ANE_IO);
+}
+
+char*
+anntp_strerror(AnntpErrCode c)
+{
+ /* ssize_t-returning functions will report errors in negative */
+ if (c < 0)
+ c = (AnntpErrCode)(-c); /* "i never said const!" */
+
+ switch (c) {
+ case ANE_OK:
+ return "<ok>";
+ case ANE_PARAMS:
+ return "invalid parameters";
+ case ANE_TLS:
+ return "security (cryptography/TLS) error";
+ case ANE_IO:
+ return "I/O error";
+ case ANE_PROTO:
+ return "protocol error, unexpected server response";
+ case ANE_AUTH:
+ return "authentication failed";
+
+ default:
+ return "unknown error";
+ }
}
#endif /* ANNTP_IMPLEMENTATION */