added vsignal todo
[strongswan.git] / src / charon / bus / bus.h
index e1b4f55..6138c25 100644 (file)
 #ifndef BUS_H_
 #define BUS_H_
 
+typedef enum signal_t signal_t;
+typedef enum level_t level_t;
+typedef struct bus_listener_t bus_listener_t;
+typedef struct bus_t bus_t;
+
 #include <stdarg.h>
 
 #include <sa/ike_sa.h>
 #include <sa/child_sa.h>
 
 
-typedef enum signal_t signal_t;
-
 /**
  * @brief signals emitted by the daemon.
  *
  * Signaling is for different purporses. First, it allows debugging via
  * "debugging signal messages", sencondly, it allows to follow certain
- * mechanisms currently going on in the daemon. As we are multithreaded, 
- * and of multiple transactions are involved, it's not possible to follow
+ * mechanisms currently going on in the daemon. As we are multithreaded,
+ * and multiple transactions are involved, it's not possible to follow
  * one connection setup without further infrastructure. These infrastructure
  * is provided by the bus and the signals the daemon emits to the bus.
  *
  * There are different scenarios to follow these signals, but all have
  * the same scheme. First, a START signal is emitted to indicate the daemon
- * has started to 
+ * has started to do something. After a start signal, a SUCCESS or a FAILED
+ * signal of the same type follows. This allows to track the operation. Any
+ * Debug signal betwee a START and a SUCCESS/FAILED belongs to that operation
+ * if the IKE_SA is the same. The thread may change, as multiple threads
+ * may be involved in a complex scenario.
  *
  * @ingroup bus
  */
@@ -123,8 +130,6 @@ enum signal_t {
  */
 extern enum_name_t *signal_names;
 
-typedef enum level_t level_t;
-
 /**
  * Signal levels used to control output verbosity.
  */
@@ -145,15 +150,11 @@ enum level_t {
        LEVEL_PRIVATE = LEVEL_4,
 };
 
-/**
- * @brief Raise a signal for an occured event.
- *
- * @param sig          signal_t signal description
- * @param format       printf() style format string
- * @param ...          printf() style agument list
- */
-#define SIG(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_0, format, ##__VA_ARGS__)
+#ifndef DEBUG_LEVEL
+# define DEBUG_LEVEL 4
+#endif /* DEBUG_LEVEL */
 
+#if DEBUG_LEVEL >= 1
 /**
  * @brief Log a debug message via the signal bus.
  *
@@ -161,10 +162,39 @@ enum level_t {
  * @param format       printf() style format string
  * @param ...          printf() style agument list
  */
-#define DBG1(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_1, format, ##__VA_ARGS__)
+# define DBG1(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_1, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 2
 #define DBG2(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_2, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 3
 #define DBG3(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_3, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+#if DEBUG_LEVEL >= 4
 #define DBG4(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_4, format, ##__VA_ARGS__)
+#endif /* DEBUG_LEVEL */
+
+#ifndef DBG1
+# define DBG1(...) {}
+#endif /* DBG1 */
+#ifndef DBG2
+# define DBG2(...) {}
+#endif /* DBG2 */
+#ifndef DBG3
+# define DBG3(...) {}
+#endif /* DBG3 */
+#ifndef DBG4
+# define DBG4(...) {}
+#endif /* DBG4 */
+
+/**
+ * @brief Raise a signal for an occured event.
+ *
+ * @param sig          signal_t signal description
+ * @param format       printf() style format string
+ * @param ...          printf() style agument list
+ */
+#define SIG(sig, format, ...) charon->bus->signal(charon->bus, sig, LEVEL_0, format, ##__VA_ARGS__)
 
 /**
  * @brief Get the type of a signal.
@@ -179,8 +209,6 @@ enum level_t {
 #define SIG_TYPE(sig) (sig > DBG_MAX ? SIG_ANY : sig)
 
 
-typedef struct bus_listener_t bus_listener_t;
-
 /**
  * @brief Interface for registering at the signal bus.
  *
@@ -200,6 +228,8 @@ struct bus_listener_t {
         * an additional informational or error message with a printf() like
         * variable argument list. This is in the va_list form, as forwarding
         * a "..." parameters to functions is not (cleanly) possible.
+        * The implementing signal function returns TRUE to stay registered
+        * to the bus, or FALSE to unregister itself.
         *
         * @param this          listener
         * @param singal        kind of the signal (up, down, rekeyed, ...)
@@ -208,14 +238,12 @@ struct bus_listener_t {
         * @param ike_sa        IKE_SA associated to the event
         * @param format        printf() style format string
         * @param args          vprintf() style va_list argument list
+        " @return                      TRUE to stay registered, FALSE to unregister
         */
-       void (*signal) (bus_listener_t *this, signal_t signal, level_t level,
+       bool (*signal) (bus_listener_t *this, signal_t signal, level_t level,
                                        int thread, ike_sa_t *ike_sa, char* format, va_list args);
 };
 
-
-typedef struct bus_t bus_t;
-
 /**
  * @brief Signal bus which sends signals to registered listeners.
  *
@@ -223,7 +251,9 @@ typedef struct bus_t bus_t;
  * in receiving event signals registers at the bus. Any signals sent to
  * are delivered to all registered listeners.
  * To deliver signals to threads, the blocking listen() call may be used
- * to wait for a signal.
+ * to wait for a signal. However, passive listeners should be preferred,
+ * as listening actively requires some synchronization overhead as data
+ * must be passed from the raising thread to the listening thread.
  *
  * @ingroup bus
  */
@@ -242,6 +272,14 @@ struct bus_t {
        void (*add_listener) (bus_t *this, bus_listener_t *listener);
        
        /**
+        * @brief Unregister a listener from the bus.
+        *
+        * @param this          bus
+        * @param listener      listener to unregister.
+        */
+       void (*remove_listener) (bus_t *this, bus_listener_t *listener);
+       
+       /**
         * @brief Listen actively on the bus.
         *
         * As we are fully multithreaded, we must provide a mechanism
@@ -251,6 +289,9 @@ struct bus_t {
         * it processes a signal, registration is required. This is done through
         * the set_listen_state() method, see below.
         *
+        * The listen() function is (has) a thread cancellation point, so you might
+        * want to register cleanup handlers.
+        *
         * @param this          bus
         * @param level         verbosity level of the signal
         * @param thread        receives thread number emitted the signal
@@ -269,7 +310,7 @@ struct bus_t {
         * must register themself to the bus before starting to listen(). When
         * a signal occurs, the emitter waits until all threads with listen_state
         * TRUE are waiting in the listen() method to process the signal.
-        * It is important that a thread with liste_state TRUE calls listen()
+        * It is important that a thread with listen_state TRUE calls listen()
         * periodically, or sets it's listening state to FALSE; otherwise
         * all signal emitting threads get blocked on the bus.
         *
@@ -314,6 +355,10 @@ struct bus_t {
         *
         * Same as bus_t.signal(), but uses va_list argument list.
         *
+        * @todo Improve performace of vsignal implementation. This method is
+        * called extensively and therefore shouldn't allocate heap memory or
+        * do other expensive tasks!
+        *
         * @param this          bus
         * @param singal        kind of the signal (up, down, rekeyed, ...)
         * @param level         verbosity level of the signal