Author: aconway
Date: Fri Jun 6 00:31:21 2014
New Revision: 1600797
URL: http://svn.apache.org/r1600797
Log:
NO-JIRA: Error handling mechanism for dispatch.
errno-like error handling mechanism for dispatch but thread safe and
includes printf-style string error message.
See comments in error.h for details.
Added error handling to qd_message_check and additional logging
in message.c and agent.c.
New code should use this mechanism where appropriate, old code
can be refactored as we go.
Added:
qpid/dispatch/trunk/src/error.c (with props)
qpid/dispatch/trunk/src/static_assert.h
- copied, changed from r1600796,
qpid/dispatch/trunk/include/qpid/dispatch/error.h
Modified:
qpid/dispatch/trunk/CMakeLists.txt
qpid/dispatch/trunk/include/qpid/dispatch/error.h
qpid/dispatch/trunk/src/agent.c
qpid/dispatch/trunk/src/dispatch.c
qpid/dispatch/trunk/src/message.c
Modified: qpid/dispatch/trunk/CMakeLists.txt
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/CMakeLists.txt?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/CMakeLists.txt (original)
+++ qpid/dispatch/trunk/CMakeLists.txt Fri Jun 6 00:31:21 2014
@@ -115,6 +115,7 @@ set(server_SOURCES
src/amqp.c
src/bitmask.c
src/buffer.c
+ src/error.c
src/compose.c
src/config.c
src/connection_manager.c
Modified: qpid/dispatch/trunk/include/qpid/dispatch/error.h
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/include/qpid/dispatch/error.h?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/include/qpid/dispatch/error.h (original)
+++ qpid/dispatch/trunk/include/qpid/dispatch/error.h Fri Jun 6 00:31:21 2014
@@ -8,9 +8,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,11 +19,52 @@
* under the License.
*/
+/** @file
+ * Thread-safe error handling mechansim for dispatch.
+ *
+ * Functions that detect an error should return qd_error_t.
+ *
+ * Implementation of such functions should first call qd_error_clear()
+ * to clear any previous error and on detecting an error do:
+ * return qd_error(code, "printf format", ...)
+ *
+ * The caller can check the error code and message with
+ * qd_error_code() and qd_error_message().
+ *
+ *
+ */
+// NOTE: If you modify this enum, you must update error_names in error.c
typedef enum {
QD_ERROR_NONE = 0,
QD_ERROR_NOT_FOUND,
QD_ERROR_ALREADY_EXISTS,
- QD_ERROR_ALLOC
+ QD_ERROR_ALLOC,
+ QD_ERROR_MESSAGE, ///< Error parsing a message.
+
+ QD_ERROR_COUNT ///< Not an error, marks the end of the enum
} qd_error_t;
+/**
+ * Store thread-local error code and message.
+ *@param code Error code. If 0 this is equivalent to calling qd_error_clear()
+ *@param fmt printf-stlye format.
+ *@return code
+ */
+qd_error_t qd_error(qd_error_t code, const char *fmt, ...);
+
+/**
+ * Clear thread-local error code and message.
+ */
+void qd_error_clear();
+
+/**
+ * @return Thread local error message. Includes text for error code.
+ */
+const char* qd_error_message();
+
+/**
+ *@return Thread local error code
+ */
+qd_error_t qd_error_code();
+
#endif
Modified: qpid/dispatch/trunk/src/agent.c
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/agent.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/agent.c (original)
+++ qpid/dispatch/trunk/src/agent.c Fri Jun 6 00:31:21 2014
@@ -82,6 +82,9 @@ typedef enum {
QD_DISCOVER_OPERATIONS
} qd_discover_t;
+// Convenience for logging, expects agent to be defined.
+#define LOG(LEVEL, MSG, ...) qd_log(agent->log_source, QD_LOG_##LEVEL, MSG,
##__VA_ARGS__)
+
static const char *AGENT_ADDRESS = "$management";
static const char *STATUS_CODE = "statusCode";
@@ -520,7 +523,7 @@ static void qd_agent_process_agent_query
const char *class_name = (const char*)
qd_hash_key_by_handle(cls->hash_handle);
//
- // If entityType was provided to restrict the result, check to see
if the
+ // If entityType was provided to restrict the result, check to see
if the
// class is in the restricted set.
//
if (etype && !qd_field_iterator_equal(qd_parse_raw(etype),
(unsigned char*) class_name))
@@ -592,23 +595,28 @@ static void qd_agent_process_request(qd_
//
// Parse the message through the body and exit if the message is not well
formed.
//
- if (!qd_message_check(msg, QD_DEPTH_BODY))
- return;
+ if (!qd_message_check(msg, QD_DEPTH_BODY)) {
+ LOG(ERROR, "Bad request: %s", qd_error_message());
+ return;
+ }
//
// Get an iterator for the application-properties. Exit if the message
has none.
//
qd_field_iterator_t *ap = qd_message_field_iterator(msg,
QD_FIELD_APPLICATION_PROPERTIES);
- if (ap == 0)
- return;
+ if (ap == 0) {
+ LOG(ERROR, "Bad request: no application-properties");
+ return;
+ }
//
// Get an iterator for the reply-to. Exit if not found.
//
qd_field_iterator_t *reply_to = qd_message_field_iterator(msg,
QD_FIELD_REPLY_TO);
- if (reply_to == 0)
+ if (reply_to == 0) {
+ LOG(ERROR, "Bad request: no reply-to");
return;
-
+ }
//
// Try to get a map-view of the application-properties.
//
@@ -616,6 +624,7 @@ static void qd_agent_process_request(qd_
if (map == 0) {
qd_field_iterator_free(ap);
qd_field_iterator_free(reply_to);
+ LOG(ERROR, "Bad request: application-properties not a map");
return;
}
@@ -626,6 +635,7 @@ static void qd_agent_process_request(qd_
qd_field_iterator_free(ap);
qd_field_iterator_free(reply_to);
qd_parse_free(map);
+ LOG(ERROR, "Bad request: application-properties not a map");
return;
}
@@ -885,4 +895,3 @@ void *qd_agent_raise_event(qd_dispatch_t
{
return 0;
}
-
Modified: qpid/dispatch/trunk/src/dispatch.c
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/dispatch.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/dispatch.c (original)
+++ qpid/dispatch/trunk/src/dispatch.c Fri Jun 6 00:31:21 2014
@@ -42,7 +42,7 @@ void qd_router_setup_late(qd_
void qd_router_free(qd_router_t *router);
qd_agent_t *qd_agent(qd_dispatch_t *qd);
void qd_agent_free(qd_agent_t *agent);
-
+void qd_error_initialize();
static const char *CONF_CONTAINER = "container";
static const char *CONF_ROUTER = "router";
@@ -56,7 +56,8 @@ qd_dispatch_t *qd_dispatch(const char *p
// alloc and log has to be initialized before any module.
qd_alloc_initialize();
- qd_log_initialize();
+ qd_log_initialize();
+ qd_error_initialize();
qd->router_area = strdup("0");
qd->router_id = strdup("0");
Added: qpid/dispatch/trunk/src/error.c
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/error.c?rev=1600797&view=auto
==============================================================================
--- qpid/dispatch/trunk/src/error.c (added)
+++ qpid/dispatch/trunk/src/error.c Fri Jun 6 00:31:21 2014
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <qpid/dispatch/error.h>
+#include <qpid/dispatch/log.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include "static_assert.h"
+
+static const char *error_names[] = {
+ "No Error",
+ "Not found",
+ "Already exists",
+ "Allocation",
+ "Invalid message"
+};
+
+STATIC_ASSERT(sizeof(error_names)/sizeof(error_names[0]) == QD_ERROR_COUNT,
error_names_wrong_size);
+
+#define ERROR_MAX 512
+
+static __thread char error_message[ERROR_MAX];
+static __thread qd_error_t error_code = 0;
+static qd_log_source_t* log_source = 0;
+
+void qd_error_initialize() {
+ log_source = qd_log_source("ERROR");
+}
+
+qd_error_t qd_error(qd_error_t code, const char *fmt, ...) {
+ error_code = code;
+ if (code) {
+ int i = 0;
+ if (code < QD_ERROR_COUNT)
+ i = snprintf(error_message, ERROR_MAX,"%s: ", error_names[code]);
+ else
+ i = snprintf(error_message, ERROR_MAX, "%d: ", code);
+ va_list arglist;
+ va_start(arglist, fmt);
+ vsnprintf(error_message+i, ERROR_MAX-i, fmt, arglist);
+ va_end(arglist);
+ qd_log(log_source, QD_LOG_TRACE, "%s", qd_error_message());
+ return code;
+ }
+ else
+ qd_error_clear();
+ return 0;
+}
+
+void qd_error_clear() {
+ error_code = 0;
+ error_message[0] = '\0';
+}
+
+const char* qd_error_message() {
+ return error_message;
+}
+
+qd_error_t qd_error_code() {
+ return error_code;
+}
Propchange: qpid/dispatch/trunk/src/error.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: qpid/dispatch/trunk/src/error.c
------------------------------------------------------------------------------
svn:keywords = Rev Date
Modified: qpid/dispatch/trunk/src/message.c
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/message.c?rev=1600797&r1=1600796&r2=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/src/message.c (original)
+++ qpid/dispatch/trunk/src/message.c Fri Jun 6 00:31:21 2014
@@ -18,6 +18,7 @@
*/
#include <qpid/dispatch/ctools.h>
+#include <qpid/dispatch/error.h>
#include <qpid/dispatch/amqp.h>
#include <qpid/dispatch/threading.h>
#include <qpid/dispatch/iterator.h>
@@ -27,6 +28,7 @@
#include <string.h>
#include <ctype.h>
#include <stdio.h>
+#include <limits.h>
static const unsigned char * const MSG_HDR_LONG = (unsigned
char*) "\x00\x80\x00\x00\x00\x00\x00\x00\x00\x70";
static const unsigned char * const MSG_HDR_SHORT = (unsigned
char*) "\x00\x53\x70";
@@ -64,6 +66,7 @@ void qd_message_initialize() {
int qd_message_repr_len() { return qd_log_max_len(); }
+// Quote non-printable characters suitable for log messages. Output in buffer.
static int quote(char* bytes, int n, char* buffer, int len) {
int i = 0;
for (char* p = bytes; p < bytes+n && i < len; ++p) {
@@ -78,29 +81,36 @@ static int quote(char* bytes, int n, cha
return i;
}
-/* TODO aconway 2014-05-13: more detailed message representation. */
-char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len) {
- qd_message_check(msg, QD_DEPTH_BODY);
+/** Copy a message field for use in log messages. Output in buffer. */
+static int copy_field(qd_message_t *msg, int field, int max, char *pre, char
*post, char *buffer, size_t len) {
+ qd_field_iterator_t* iter = qd_message_field_iterator(msg, field);
int i = 0;
- --len; /* Save space for final '\0' */
- i += snprintf(buffer+i, len-i, "Message(%p){to=", msg);
- qd_field_iterator_t* iter = 0;
- iter = qd_message_field_iterator(msg, QD_FIELD_TO);
if (iter) {
- i += qd_field_iterator_ncopy(iter, (unsigned char*)buffer+i, len-i);
- qd_field_iterator_free(iter);
- }
- iter = qd_message_field_iterator(msg, QD_FIELD_BODY);
- if (iter) {
- i += snprintf(buffer+i, len-i, " body='");
- char body[8]; /* Initial bytes of body */
- int bytes = qd_field_iterator_ncopy(iter, (unsigned char*)body,
sizeof(body));
- i += quote(body, bytes, buffer+i, len-i);
- i += snprintf(buffer+i, len-i, "'");
+ i += snprintf(buffer+i, len-i, "%s", pre);
+ qd_field_iterator_reset(iter);
+ for (int j = 0; !qd_field_iterator_end(iter) && i < len && j < max;
++j) {
+ char byte = qd_field_iterator_octet(iter);
+ i += quote(&byte, 1, buffer+i, len-i);
+ }
+ i += snprintf(buffer+i, len-i, "%s", post);
}
- i += snprintf(buffer+i, len-i, "}");
+ return i;
+}
+
+static const char REPR_END[] = "}\0";
+
+/* TODO aconway 2014-05-13: more detailed message representation. */
+char* qd_message_repr(qd_message_t *msg, char* buffer, size_t len) {
+ int i = 0;
+ len -= sizeof(REPR_END); /* Save space for ending */
+ i += snprintf(buffer+i, len-i, "Message(%p){", msg);
+ if (!qd_message_check(msg, QD_DEPTH_BODY))
+ i += snprintf(buffer+i, len-i, "<%s>", qd_error_message());
+ i += copy_field(msg, QD_FIELD_TO, INT_MAX, " to='", "'", buffer+i, len-i);
+ i += copy_field(msg, QD_FIELD_REPLY_TO, INT_MAX, " reply-to='", "'",
buffer+i, len-i);
+ i += copy_field(msg, QD_FIELD_BODY, 16, " body='", "'", buffer+i, len-i);
assert(i <= len);
- buffer[i] = '\0';
+ strcat(buffer, REPR_END); /* We saved space at the beginning. */
return buffer;
}
@@ -705,8 +715,10 @@ void qd_message_send(qd_message_t *in_ms
// Start by making sure that we've parsed the message sections through
// the message annotations
//
- if (!qd_message_check(in_msg, QD_DEPTH_MESSAGE_ANNOTATIONS))
+ if (!qd_message_check(in_msg, QD_DEPTH_MESSAGE_ANNOTATIONS)) {
+ qd_log(log_source, QD_LOG_ERROR, "Cannot send: %s",
qd_error_message);
return;
+ }
//
// Send header if present
@@ -777,15 +789,18 @@ static int qd_check_field_LH(qd_message_
}
-static int qd_message_check_LH(qd_message_content_t *content,
qd_message_depth_t depth)
+static bool qd_message_check_LH(qd_message_content_t *content,
qd_message_depth_t depth)
{
+ qd_error_clear();
qd_buffer_t *buffer = DEQ_HEAD(content->buffers);
- if (!buffer)
- return 0; // Invalid - No data in the message
+ if (!buffer) {
+ qd_error(QD_ERROR_MESSAGE, "No data");
+ return false;
+ }
if (depth <= content->parse_depth)
- return 1; // We've already parsed at least this deep
+ return true; // We've already parsed at least this deep
if (content->parse_buffer == 0) {
content->parse_buffer = buffer;
@@ -793,52 +808,62 @@ static int qd_message_check_LH(qd_messag
}
if (depth == QD_DEPTH_NONE)
- return 1;
+ return true;
//
// MESSAGE HEADER
//
if (0 == qd_check_field_LH(content, QD_DEPTH_HEADER,
- MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST,
&content->section_message_header, 0))
- return 0;
+ MSG_HDR_LONG, MSG_HDR_SHORT, TAGS_LIST,
&content->section_message_header, 0)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid header");
+ return false;
+ }
if (depth == QD_DEPTH_HEADER)
- return 1;
+ return true;
//
// DELIVERY ANNOTATION
//
if (0 == qd_check_field_LH(content, QD_DEPTH_DELIVERY_ANNOTATIONS,
- DELIVERY_ANNOTATION_LONG,
DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0))
- return 0;
+ DELIVERY_ANNOTATION_LONG,
DELIVERY_ANNOTATION_SHORT, TAGS_MAP, &content->section_delivery_annotation, 0))
{
+ qd_error(QD_ERROR_MESSAGE, "Invalid delivery-annotations");
+ return false;
+ }
if (depth == QD_DEPTH_DELIVERY_ANNOTATIONS)
- return 1;
+ return true;
//
// MESSAGE ANNOTATION
//
if (0 == qd_check_field_LH(content, QD_DEPTH_MESSAGE_ANNOTATIONS,
- MESSAGE_ANNOTATION_LONG,
MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0))
- return 0;
+ MESSAGE_ANNOTATION_LONG,
MESSAGE_ANNOTATION_SHORT, TAGS_MAP, &content->section_message_annotation, 0)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid annotations");
+ return false;
+ }
if (depth == QD_DEPTH_MESSAGE_ANNOTATIONS)
- return 1;
+ return true;
//
// PROPERTIES
//
if (0 == qd_check_field_LH(content, QD_DEPTH_PROPERTIES,
- PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST,
&content->section_message_properties, 0))
- return 0;
+ PROPERTIES_LONG, PROPERTIES_SHORT, TAGS_LIST,
&content->section_message_properties, 0)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid message properties");
+ return false;
+ }
if (depth == QD_DEPTH_PROPERTIES)
- return 1;
+ return true;
//
// APPLICATION PROPERTIES
//
if (0 == qd_check_field_LH(content, QD_DEPTH_APPLICATION_PROPERTIES,
- APPLICATION_PROPERTIES_LONG,
APPLICATION_PROPERTIES_SHORT, TAGS_MAP,
&content->section_application_properties, 0))
- return 0;
+ APPLICATION_PROPERTIES_LONG,
APPLICATION_PROPERTIES_SHORT, TAGS_MAP,
&content->section_application_properties, 0)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid application-properties");
+ return false;
+ }
if (depth == QD_DEPTH_APPLICATION_PROPERTIES)
- return 1;
+ return true;
//
// BODY
@@ -847,25 +872,34 @@ static int qd_message_check_LH(qd_messag
// be parsed to BODY-depth.
//
if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY,
&content->section_body, 1))
- return 0;
+ BODY_DATA_LONG, BODY_DATA_SHORT, TAGS_BINARY,
&content->section_body, 1)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid body data");
+ return false;
+ }
if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT,
TAGS_LIST, &content->section_body, 1))
- return 0;
+ BODY_SEQUENCE_LONG, BODY_SEQUENCE_SHORT,
TAGS_LIST, &content->section_body, 1)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid body sequence");
+ return false;
+ }
if (0 == qd_check_field_LH(content, QD_DEPTH_BODY,
- BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY,
&content->section_body, 0))
- return 0;
+ BODY_VALUE_LONG, BODY_VALUE_SHORT, TAGS_ANY,
&content->section_body, 0)) {
+ qd_error(QD_ERROR_MESSAGE, "Invalid body value");
+ return false;
+ }
if (depth == QD_DEPTH_BODY)
- return 1;
+ return true;
//
// FOOTER
//
if (0 == qd_check_field_LH(content, QD_DEPTH_ALL,
- FOOTER_LONG, FOOTER_SHORT, TAGS_MAP,
&content->section_footer, 0))
- return 0;
+ FOOTER_LONG, FOOTER_SHORT, TAGS_MAP,
&content->section_footer, 0)) {
- return 1;
+ qd_error(QD_ERROR_MESSAGE, "Invalid footer");
+ return false;
+ }
+
+ return true;
}
Copied: qpid/dispatch/trunk/src/static_assert.h (from r1600796,
qpid/dispatch/trunk/include/qpid/dispatch/error.h)
URL:
http://svn.apache.org/viewvc/qpid/dispatch/trunk/src/static_assert.h?p2=qpid/dispatch/trunk/src/static_assert.h&p1=qpid/dispatch/trunk/include/qpid/dispatch/error.h&r1=1600796&r2=1600797&rev=1600797&view=diff
==============================================================================
--- qpid/dispatch/trunk/include/qpid/dispatch/error.h (original)
+++ qpid/dispatch/trunk/src/static_assert.h Fri Jun 6 00:31:21 2014
@@ -1,5 +1,6 @@
-#ifndef __dispatch_error_h__
-#define __dispatch_error_h__ 1
+#ifndef STATIC_ASSERT_H
+#define STATIC_ASSERT_H
+
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -8,9 +9,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -19,11 +20,20 @@
* under the License.
*/
-typedef enum {
- QD_ERROR_NONE = 0,
- QD_ERROR_NOT_FOUND,
- QD_ERROR_ALREADY_EXISTS,
- QD_ERROR_ALLOC
-} qd_error_t;
+/** @file
+ STATIC_ASSERT allows you to do compile time assertions at file scope
+ or in a funciton.
+ */
+
+#ifdef __GNUC__
+#define STATIC_ASSERT_HELPER(expr, msg) \
+ (!!sizeof(struct { unsigned int STATIC_ASSERTION__##msg: (expr) ? 1 : -1;
}))
+#define STATIC_ASSERT(expr, msg) \
+ extern int (*assert_function__(void)) [STATIC_ASSERT_HELPER(expr, msg)]
+#else
+ #define STATIC_ASSERT(expr, msg) \
+ extern char STATIC_ASSERTION__##msg[1]; \
+ extern char STATIC_ASSERTION__##msg[(expr)?1:2]
+#endif /* #ifdef __GNUC__ */
-#endif
+#endif // STATIC_ASSERT_H
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]