From 4d9f3abcc30bc628dd872d83233de8744136547d Mon Sep 17 00:00:00 2001 From: Alan Antonuk Date: Thu, 13 Jun 2013 13:58:58 -0700 Subject: Change amqp_error_string() to ret static strings This is an API/ABI break. --- examples/utils.c | 4 +-- librabbitmq/amqp.h | 5 ++- librabbitmq/amqp_api.c | 92 ++++++++++++++++++++++++++++++++++++++------------ tools/common.c | 24 ++++++------- tools/common.h | 4 +-- 5 files changed, 86 insertions(+), 43 deletions(-) diff --git a/examples/utils.c b/examples/utils.c index 4b00470..5d4a1f9 100644 --- a/examples/utils.c +++ b/examples/utils.c @@ -59,9 +59,7 @@ void die(const char *fmt, ...) void die_on_error(int x, char const *context) { if (x < 0) { - char *errstr = amqp_error_string(-x); - fprintf(stderr, "%s: %s\n", context, errstr); - free(errstr); + fprintf(stderr, "%s: %s\n", context, amqp_error_string(x)); exit(1); } } diff --git a/librabbitmq/amqp.h b/librabbitmq/amqp.h index 0388bd1..2a0bf19 100644 --- a/librabbitmq/amqp.h +++ b/librabbitmq/amqp.h @@ -588,11 +588,10 @@ AMQP_CALL amqp_data_in_buffer(amqp_connection_state_t state); /* * Get the error string for the given error code. * - * The returned string resides on the heap; the caller is responsible - * for freeing it. + * Error string is statically allocated. (API changed in v0.4.0) */ AMQP_PUBLIC_FUNCTION -char * +const char * AMQP_CALL amqp_error_string(int err); AMQP_PUBLIC_FUNCTION diff --git a/librabbitmq/amqp_api.c b/librabbitmq/amqp_api.c index cab0f4b..9f65c4c 100644 --- a/librabbitmq/amqp_api.c +++ b/librabbitmq/amqp_api.c @@ -46,34 +46,84 @@ #include #include -static const char *client_error_strings[] = { - "operation completed successfully", /* AMQP_STATUS_OK */ - "could not allocate memory", /* AMQP_STATUS_NO_MEMORY */ - "received bad AMQP data", /* AMQP_STATUS_BAD_AQMP_DATA */ - "unknown AMQP class id", /* AMQP_STATUS_UNKNOWN_CLASS */ - "unknown AMQP method id", /* AMQP_STATUS_UNKNOWN_METHOD */ - "hostname lookup failed", /* AMQP_STATUS_GETHOSTBYNAME_FAILED */ - "incompatible AMQP version", /* AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION */ - "connection closed unexpectedly", /* AMQP_STATUS_CONNECTION_CLOSED */ - "could not parse AMQP URL", /* AMQP_STATUS_BAD_AMQP_URL */ - "a socket error occurred", /* AMQP_STATUS_SOCKET_ERROR */ - "a SSL error occurred" /* AMQP_STATUS_SSL_ERROR */ +#define ERROR_MASK (0x00FF) +#define ERROR_CATEGORY_MASK (0xFF00) + +enum error_category_enum_ { + EC_base = 0, + EC_tcp = 1, + EC_ssl = 2 +}; + +static const char *base_error_strings[] = { + "operation completed successfully", /* AMQP_STATUS_OK 0x0 */ + "could not allocate memory", /* AMQP_STATUS_NO_MEMORY -0x0001 */ + "invalid AMQP data", /* AMQP_STATUS_BAD_AQMP_DATA -0x0002 */ + "unknown AMQP class id", /* AMQP_STATUS_UNKNOWN_CLASS -0x0003 */ + "unknown AMQP method id", /* AMQP_STATUS_UNKNOWN_METHOD -0x0004 */ + "hostname lookup failed", /* AMQP_STATUS_HOSTNAME_RESOLUTION_FAILED -0x0005 */ + "incompatible AMQP version", /* AMQP_STATUS_INCOMPATIBLE_AMQP_VERSION -0x0006 */ + "connection closed unexpectedly", /* AMQP_STATUS_CONNECTION_CLOSED -0x0007 */ + "could not parse AMQP URL", /* AMQP_STATUS_BAD_AMQP_URL -0x0008 */ + "a socket error occurred", /* AMQP_STATUS_SOCKET_ERROR -0x0009 */ + "invalid parameter", /* AMQP_STATUS_INVALID_PARAMETER -0x000A */ + "table too large for buffer", /* AMQP_STATUS_TABLE_TOO_BIG -0x000B */ + "unexpected method received" /* AMQP_STATUS_WRONG_METHOD -0x000C */ +}; + +static const char *tcp_error_strings[] = { + "a socket error occurred", /* AMQP_STATUS_TCP_ERROR -0x0100 */ + "socket library initialization failed" /* AMQP_STATUS_TCP_SOCKETLIB_INIT_ERROR -0x0101 */ +}; + +static const char *ssl_error_strings[] = { + "a SSL error occurred", /* AMQP_STATUS_SSL_ERROR -0x0200 */ + "SSL hostname verification failed", /* AMQP_STATUS_SSL_HOSTNAME_VERIFY_FAILED -0x0201 */ + "SSL peer cert verification failed", /* AMQP_STATUS_SSL_PEER_VERIFY_FAILED -0x0202 */ + "SSL handshake failed" /* AMQP_STATUS_SSL_CONNECTION_FAILED -0x0203 */ }; -char *amqp_error_string(int err) +static const char *unknown_error_string = "(unknown error)"; + +const char *amqp_error_string(int code) { - const char *str; - const int max_error_index = sizeof(client_error_strings) / sizeof(char *); + const char *error_string; + size_t category = (((-code) & ERROR_CATEGORY_MASK) >> 16); + size_t error = (-code) & ERROR_MASK; + + switch (category) { + case EC_base: + if (error < (sizeof(base_error_strings) / sizeof(char *))) { + error_string = base_error_strings[error]; + } else { + error_string = unknown_error_string; + } + break; + + case EC_tcp: + if (error < (sizeof(tcp_error_strings) / sizeof(char *))) { + error_string = tcp_error_strings[error]; + } else { + error_string = unknown_error_string; + } + break; + + case EC_ssl: + if (error < (sizeof(ssl_error_strings) / sizeof(char *))) { + error_string = ssl_error_strings[error]; + } else { + error_string = unknown_error_string; + } - err = -err; + break; + + default: + error_string = unknown_error_string; + break; - if (err < 0 || err > max_error_index) { - str = "an unknown error occurred"; - } else { - str = client_error_strings[err]; } - return strdup(str); + return error_string; } void amqp_abort(const char *fmt, ...) diff --git a/tools/common.c b/tools/common.c index 0c61d16..b556988 100644 --- a/tools/common.c +++ b/tools/common.c @@ -83,7 +83,6 @@ void die_errno(int err, const char *fmt, ...) void die_amqp_error(int err, const char *fmt, ...) { va_list ap; - char *errstr; if (err >= 0) { return; @@ -92,21 +91,20 @@ void die_amqp_error(int err, const char *fmt, ...) va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, ": %s\n", errstr = amqp_error_string(-err)); - free(errstr); + fprintf(stderr, ": %s\n", amqp_error_string(err)); exit(1); } -char *amqp_server_exception_string(amqp_rpc_reply_t r) +const char *amqp_server_exception_string(amqp_rpc_reply_t r) { int res; - char *s; + static char s[512]; switch (r.reply.id) { case AMQP_CONNECTION_CLOSE_METHOD: { amqp_connection_close_t *m = (amqp_connection_close_t *)r.reply.decoded; - res = asprintf(&s, "server connection error %d, message: %.*s", + res = snprintf(s, sizeof(s), "server connection error %d, message: %.*s", m->reply_code, (int)m->reply_text.len, (char *)m->reply_text.bytes); @@ -116,7 +114,7 @@ char *amqp_server_exception_string(amqp_rpc_reply_t r) case AMQP_CHANNEL_CLOSE_METHOD: { amqp_channel_close_t *m = (amqp_channel_close_t *)r.reply.decoded; - res = asprintf(&s, "server channel error %d, message: %.*s", + res = snprintf(s, sizeof(s), "server channel error %d, message: %.*s", m->reply_code, (int)m->reply_text.len, (char *)m->reply_text.bytes); @@ -124,7 +122,7 @@ char *amqp_server_exception_string(amqp_rpc_reply_t r) } default: - res = asprintf(&s, "unknown server error, method id 0x%08X", + res = snprintf(s, sizeof(s), "unknown server error, method id 0x%08X", r.reply.id); break; } @@ -132,14 +130,14 @@ char *amqp_server_exception_string(amqp_rpc_reply_t r) return res >= 0 ? s : NULL; } -char *amqp_rpc_reply_string(amqp_rpc_reply_t r) +const char *amqp_rpc_reply_string(amqp_rpc_reply_t r) { switch (r.reply_type) { case AMQP_RESPONSE_NORMAL: - return strdup("normal response"); + return "normal response"; case AMQP_RESPONSE_NONE: - return strdup("missing RPC reply type"); + return "missing RPC reply type"; case AMQP_RESPONSE_LIBRARY_EXCEPTION: return amqp_error_string(r.library_error); @@ -155,7 +153,6 @@ char *amqp_rpc_reply_string(amqp_rpc_reply_t r) void die_rpc(amqp_rpc_reply_t r, const char *fmt, ...) { va_list ap; - char *errstr; if (r.reply_type == AMQP_RESPONSE_NORMAL) { return; @@ -164,8 +161,7 @@ void die_rpc(amqp_rpc_reply_t r, const char *fmt, ...) va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); - fprintf(stderr, ": %s\n", errstr = amqp_rpc_reply_string(r)); - free(errstr); + fprintf(stderr, ": %s\n", amqp_rpc_reply_string(r)); exit(1); } diff --git a/tools/common.h b/tools/common.h index cc186ec..7d01966 100644 --- a/tools/common.h +++ b/tools/common.h @@ -41,8 +41,8 @@ #include #include -extern char *amqp_server_exception_string(amqp_rpc_reply_t r); -extern char *amqp_rpc_reply_string(amqp_rpc_reply_t r); +extern const char *amqp_server_exception_string(amqp_rpc_reply_t r); +extern const char *amqp_rpc_reply_string(amqp_rpc_reply_t r); extern void die(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); -- cgit v1.2.1