]> git.meshlink.io Git - meshlink/commitdiff
Add an error callback.
authorGuus Sliepen <guus@meshlink.io>
Mon, 7 Oct 2019 19:00:01 +0000 (21:00 +0200)
committerGuus Sliepen <guus@meshlink.io>
Mon, 7 Oct 2019 19:00:01 +0000 (21:00 +0200)
Normally, API functions report potential errors. However, it might happen
that the background thread runs into a serious error that prevents
MeshLink from operating as expected. Add a callback that is called in those
cases.

Currently, the only time it is called is when it can not create or modify
config files in the background thread.

src/meshlink++.h
src/meshlink.c
src/meshlink.h
src/meshlink.sym
src/meshlink_internal.h
src/net_setup.c

index b88746e39a548ba356c88a470a93849674c21168..e39ef81cde7bc4fd34c7de747da5ec5d46fc2a5c 100644 (file)
@@ -259,6 +259,12 @@ public:
                (void)message;
        }
 
+       /// This functions is called whenever MeshLink has encountered a serious error.
+       virtual void error(meshlink_errno_t meshlink_errno) {
+               /* do nothing */
+               (void)meshlink_errno;
+       }
+
        /// This functions is called whenever MeshLink a meta-connection attempt is made.
        virtual void connection_try(node *peer) {
                /* do nothing */
@@ -339,6 +345,7 @@ public:
                meshlink_set_node_pmtu_cb(handle, &node_pmtu_trampoline);
                meshlink_set_node_duplicate_cb(handle, &node_duplicate_trampoline);
                meshlink_set_log_cb(handle, MESHLINK_DEBUG, &log_trampoline);
+               meshlink_set_error_cb(handle, &error_trampoline);
                meshlink_set_channel_accept_cb(handle, &channel_accept_trampoline);
                meshlink_set_connection_try_cb(handle, &connection_try_trampoline);
                return meshlink_start(handle);
@@ -952,6 +959,15 @@ private:
                that->log(level, message);
        }
 
+       static void error_trampoline(meshlink_handle_t *handle, meshlink_errno_t meshlink_errno) {
+               if(!(handle->priv)) {
+                       return;
+               }
+
+               meshlink::mesh *that = static_cast<mesh *>(handle->priv);
+               that->error(meshlink_errno);
+       }
+
        static void connection_try_trampoline(meshlink_handle_t *handle, meshlink_node_t *peer) {
                if(!(handle->priv)) {
                        return;
index 227df29ff3b102f36ce6aef7ec65d48509dde6fe..4162b36e7c7f569b01be95f675546868ccc16d1c 100644 (file)
@@ -1718,6 +1718,17 @@ void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t level, me
        }
 }
 
+void meshlink_set_error_cb(struct meshlink_handle *mesh, meshlink_error_cb_t cb) {
+       if(!mesh) {
+               meshlink_errno = MESHLINK_EINVAL;
+               return;
+       }
+
+       pthread_mutex_lock(&(mesh->mesh_mutex));
+       mesh->error_cb = cb;
+       pthread_mutex_unlock(&(mesh->mesh_mutex));
+}
+
 bool meshlink_send(meshlink_handle_t *mesh, meshlink_node_t *destination, const void *data, size_t len) {
        meshlink_packethdr_t *hdr;
 
@@ -3524,6 +3535,22 @@ void handle_network_change(meshlink_handle_t *mesh, bool online) {
        retry(mesh);
 }
 
+void call_error_cb(meshlink_handle_t *mesh) {
+       // We should only call the callback function if we are in the background thread.
+       if(!mesh->error_cb) {
+               return;
+       }
+
+       if(!mesh->threadstarted) {
+               return;
+       }
+
+       if(mesh->thread == pthread_self()) {
+               mesh->error_cb(mesh, meshlink_errno);
+       }
+}
+
+
 static void __attribute__((constructor)) meshlink_init(void) {
        crypto_init();
 }
index da5cc131e33b8d3917b3cc4d4dd52464b304f489..00aa19b26849413b664d3fc2c0331ab3730399ef 100644 (file)
@@ -511,6 +511,38 @@ typedef void (*meshlink_log_cb_t)(struct meshlink_handle *mesh, meshlink_log_lev
  */
 extern void meshlink_set_log_cb(struct meshlink_handle *mesh, meshlink_log_level_t level, meshlink_log_cb_t cb);
 
+/// A callback for receiving error conditions encountered by the MeshLink thread.
+/** @param mesh      A handle which represents an instance of MeshLink, or NULL.
+ *  @param errno     The error code describing what kind of error occured.
+ */
+typedef void (*meshlink_error_cb_t)(struct meshlink_handle *mesh, meshlink_errno_t meshlink_errno);
+
+/// Set the error callback.
+/** This functions sets the callback that is called whenever the MeshLink thread encounters a serious error.
+ *
+ *  While most API functions report an error directly to the caller in case something went wrong,
+ *  MeshLink also runs a background thread which can encounter error conditions.
+ *  Most of them will be dealt with automatically, however there can be errors that will prevent MeshLink from
+ *  working correctly. When the callback is called, it means that MeshLink is no longer functioning
+ *  as expected. The application should then present an error message and shut down, or perform any other
+ *  action it deems appropriate.
+ *
+ *  The callback is run in MeshLink's own thread.
+ *  It is important that the callback uses apprioriate methods (queues, pipes, locking, etc.)
+ *  to hand the data over to the application's thread.
+ *  The callback should also not block itself and return as quickly as possible.
+ *
+ *  Even though the callback signals a serious error inside MeshLink, all open handles are still valid,
+ *  and the application should close handles in exactly the same it would have to do if the callback
+ *  was not called. This must not be done inside the callback itself.
+ *
+ *  \memberof meshlink_handle
+ *  @param mesh      A handle which represents an instance of MeshLink, or NULL.
+ *  @param cb        A pointer to the function which will be called when a serious error is encountered.
+ *                   If a NULL pointer is given, the callback will be disabled.
+ */
+extern void meshlink_set_error_cb(struct meshlink_handle *mesh, meshlink_error_cb_t cb);
+
 /// Send data to another node.
 /** This functions sends one packet of data to another node in the mesh.
  *  The packet is sent using UDP semantics, which means that
index 207da7c47113b83d4586c2fd2deeefa0cf21af99..d94947c04271352e9eec365db944f83faa782062 100644 (file)
@@ -63,6 +63,7 @@ meshlink_set_channel_sndbuf
 meshlink_set_connection_try_cb
 meshlink_set_default_blacklist
 meshlink_set_dev_class_timeouts
+meshlink_set_error_cb
 meshlink_set_invitation_timeout
 meshlink_set_log_cb
 meshlink_set_node_duplicate_cb
index cbb98c6fd07048994f0bf7cae1df7ca52e951690..ba7f7d155c4893cb28e6d6a5ccdc2a9a286a1333 100644 (file)
@@ -143,6 +143,7 @@ struct meshlink_handle {
        meshlink_channel_accept_cb_t channel_accept_cb;
        meshlink_node_duplicate_cb_t node_duplicate_cb;
        meshlink_connection_try_cb_t connection_try_cb;
+       meshlink_error_cb_t error_cb;
 
        // Mesh parameters
        char *appname;
@@ -257,6 +258,7 @@ extern meshlink_log_level_t global_log_level;
 extern meshlink_log_cb_t global_log_cb;
 extern void handle_duplicate_node(meshlink_handle_t *mesh, struct node_t *n);
 extern void handle_network_change(meshlink_handle_t *mesh, bool online);
+extern void call_error_cb(meshlink_handle_t *mesh);
 
 /// Per-instance PRNG
 static inline int prng(meshlink_handle_t *mesh, uint64_t max) {
index 367ccd293857f98162b50ba4a8a4afda5f3be217..b4a16c7e17fd782341db34bd256c9754c1c7fd8b 100644 (file)
@@ -270,7 +270,13 @@ bool node_write_config(meshlink_handle_t *mesh, node_t *n) {
        }
 
        config_t config = {buf, packmsg_output_size(&out, buf)};
-       return config_write(mesh, "current", n->name, &config, mesh->config_key);
+
+       if(!config_write(mesh, "current", n->name, &config, mesh->config_key)) {
+               call_error_cb(mesh);
+               return false;
+       }
+
+       return true;
 }
 
 static bool load_node(meshlink_handle_t *mesh, const char *name, void *priv) {