From c6a8d235b103195d3a2ccde17168d05409d7b485 Mon Sep 17 00:00:00 2001 From: Lars Date: Mon, 4 Aug 2014 01:25:12 +0200 Subject: [PATCH] object-oriented interface 1st durchstich, incl. chat program adopted. :-) --- examples/chatpp.cc | 51 +++++++++++----------- src/meshlink++.h | 103 +++++++++++++++++++++++++-------------------- src/meshlink.c | 8 +++- src/meshlink.h | 3 ++ 4 files changed, 93 insertions(+), 72 deletions(-) diff --git a/examples/chatpp.cc b/examples/chatpp.cc index f21e96de..7625f657 100644 --- a/examples/chatpp.cc +++ b/examples/chatpp.cc @@ -4,28 +4,32 @@ #include #include "../src/meshlink++.h" -static void log_message(meshlink::mesh *mesh, meshlink::log_level_t level, const char *text) { - const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}; - fprintf(stderr, "%s: %s\n", levelstr[level], text); -} - -static void receive(meshlink::mesh *mesh, meshlink::node *source, const void *data, size_t len) { - const char *msg = (const char *)data; +class ChatMesh : public meshlink::mesh +{ +public: + void log(meshlink::log_level_t level, const char *text) { + const char *levelstr[] = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}; + fprintf(stderr, "%s: %s\n", levelstr[level], text); + } - if(!len || msg[len - 1]) { - fprintf(stderr, "Received invalid data from %s\n", source->name); - return; + void receive(meshlink::node *source, const void *data, size_t len) { + const char *msg = (const char *)data; + + if(!len || msg[len - 1]) { + fprintf(stderr, "Received invalid data from %s\n", source->name); + return; + } + + printf("%s says: %s\n", source->name, msg); } - printf("%s says: %s\n", source->name, msg); -} - -static void node_status(meshlink::mesh *mesh, meshlink::node *node, bool reachable) { - if(reachable) - printf("%s joined.\n", node->name); - else - printf("%s left.\n", node->name); -} + void node_status(meshlink::node *node, bool reachable) { + if(reachable) + printf("%s joined.\n", node->name); + else + printf("%s left.\n", node->name); + } +}; static meshlink::node **nodes; static size_t nnodes; @@ -82,7 +86,7 @@ static void parse_command(meshlink::mesh *mesh, char *buf) { if(!nodes) { fprintf(stderr, "Could not get list of nodes: %s\n", meshlink::strerror()); } else { - printf("%d known nodes:", nnodes); + printf("%zu known nodes:", nnodes); for(size_t i = 0; i < nnodes; i++) printf(" %s", nodes[i]->name); printf("\n"); @@ -171,6 +175,7 @@ static void parse_input(meshlink::mesh *mesh, char *buf) { printf("Message sent to '%s'.\n", destination->name); } + int main(int argc, char *argv[]) { const char *confbase = ".chat"; const char *nick = NULL; @@ -182,16 +187,12 @@ int main(int argc, char *argv[]) { if(argc > 2) nick = argv[2]; - meshlink::mesh *mesh = meshlink::open(confbase, nick); + ChatMesh* mesh = meshlink::open(confbase, nick); if(!mesh) { fprintf(stderr, "Could not open MeshLink: %s\n", meshlink::strerror()); return 1; } - mesh->set_receive_cb(receive); - mesh->set_node_status_cb(node_status); - mesh->set_log_cb(MESHLINK_INFO, log_message); - if(!mesh->start()) { fprintf(stderr, "Could not start MeshLink: %s\n", meshlink::strerror()); return 1; diff --git a/src/meshlink++.h b/src/meshlink++.h index 1d6c9861..8f852d9f 100644 --- a/src/meshlink++.h +++ b/src/meshlink++.h @@ -21,6 +21,7 @@ #define MESHLINKPP_H #include +#include // for 'placement new' namespace meshlink { class mesh; @@ -86,9 +87,30 @@ namespace meshlink { /// A class describing a MeshLink mesh. class mesh: public meshlink_handle_t { - public: - // TODO: delete constructor, add a destructor. - + public: + mesh() {} + + virtual ~mesh() { + meshlink_close(this); + } + + /** instead of registerin callbacks you derive your own class and overwrite the following abstract member functions. + * These functions are run in MeshLink's own thread. + * It is therefore important that these functions use apprioriate methods (queues, pipes, locking, etc.) + * to hand the data over to the application's thread. + * These functions should also not block itself and return as quickly as possible. + * The default member functions are no-ops, so you are not required to overwrite all these member functions + */ + + /// This function is called whenever another node sends data to the local node. + virtual void receive(node* source, const void* data, size_t length) { /* do nothing */ } + + /// This functions is called whenever another node's status changed. + virtual void node_status(node* peer, bool reachable) { /* do nothing */ } + + /// This functions is called whenever MeshLink has some information to log. + virtual void log(log_level_t level, const char* message) { /* do nothing */ } + /// Start MeshLink. /** This function causes MeshLink to open network sockets, make outgoing connections, and * create a new thread, which will handle all network I/O. @@ -96,6 +118,9 @@ namespace meshlink { * @return This function will return true if MeshLink has succesfully started its thread, false otherwise. */ bool start() { + meshlink_set_receive_cb (this, &receive_trampoline); + meshlink_set_node_status_cb(this, &node_status_trampoline); + meshlink_set_log_cb (this, MESHLINK_DEBUG, &log_trampoline); return meshlink_start(this); } @@ -107,46 +132,6 @@ namespace meshlink { meshlink_stop(this); } - /// Set the receive callback. - /** This functions sets the callback that is called whenever another node sends data to the local node. - * The callback is run in MeshLink's own thread. - * It is therefore 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. - * - * @param cb A pointer to the function which will be called when another node sends data to the local node. - */ - void set_receive_cb(receive_cb_t cb) { - meshlink_set_receive_cb(this, (meshlink_receive_cb_t)cb); - } - - /// Set the node status callback. - /** This functions sets the callback that is called whenever another node's status changed. - * The callback is run in MeshLink's own thread. - * It is therefore 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. - * - * @param cb A pointer to the function which will be called when another node's status changes. - */ - void set_node_status_cb(node_status_cb_t cb) { - meshlink_set_node_status_cb(this, (meshlink_node_status_cb_t)cb); - } - - /// Set the log callback. - /** This functions sets the callback that is called whenever MeshLink has some information to log. - * 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. - * - * @param level An enum describing the minimum severity level. Debugging information with a lower level will not trigger the callback. - * @param cb A pointer to the function which will be called when another node sends data to the local node. - */ - void set_log_cb(meshlink_log_level_t level, log_cb_t cb) { - meshlink_set_log_cb(this, level, (meshlink_log_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 @@ -359,6 +344,29 @@ namespace meshlink { return meshlink_channel_send(this, channel, data, len); } + private: + // non-copyable: + mesh(const mesh&) /* TODO: C++11: = delete */; + void operator=(const mesh&) /* TODO: C++11: = delete */ ; + + /// static callback trampolines: + static void receive_trampoline(meshlink_handle_t* handle, meshlink_node_t* source, const void* data, size_t length) + { + mesh* that = static_cast(handle); + that->receive(static_cast(source), data, length); + } + + static void node_status_trampoline(meshlink_handle_t* handle, meshlink_node_t* peer, bool reachable) + { + mesh* that = static_cast(handle); + that->node_status(static_cast(peer), reachable); + } + + static void log_trampoline(meshlink_handle_t* handle, log_level_t level, const char* message) + { + mesh* that = static_cast(handle); + that->log(level, message); + } }; /// Initialize MeshLink's configuration directory. @@ -376,8 +384,10 @@ namespace meshlink { * * @return This function will return a pointer to a meshlink::mesh if MeshLink has succesfully set up its configuration files, NULL otherwise. */ - static mesh *open(const char *confbase, const char *name) { - return (mesh *)meshlink_open(confbase, name); + template + static MESH* open(const char *confbase, const char *name) { + void* mp = (void *)meshlink_open_with_size(confbase, name, sizeof(MESH)); + return new (mp) MESH; } /// Close the MeshLink handle. @@ -392,6 +402,7 @@ namespace meshlink { static const char *strerror(errno_t err = meshlink_errno) { return meshlink_strerror(err); } -}; + +} #endif // MESHLINKPP_H diff --git a/src/meshlink.c b/src/meshlink.c index 9fc80153..3def13fd 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -740,7 +740,13 @@ static bool meshlink_setup(meshlink_handle_t *mesh) { return true; } + meshlink_handle_t *meshlink_open(const char *confbase, const char *name) { + return meshlink_open_with_size(confbase, name, sizeof(meshlink_handle_t) ); +} + + +meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, size_t size) { // Validate arguments provided by the application bool usingname = false; @@ -763,7 +769,7 @@ meshlink_handle_t *meshlink_open(const char *confbase, const char *name) { } else { usingname = true;} } - meshlink_handle_t *mesh = xzalloc(sizeof *mesh); + meshlink_handle_t *mesh = xzalloc(size); mesh->confbase = xstrdup(confbase); if (usingname) mesh->name = xstrdup(name); pthread_mutex_init ( &(mesh->outpacketqueue_mutex), NULL); diff --git a/src/meshlink.h b/src/meshlink.h index ee2c3f0a..603dbbd2 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -117,6 +117,9 @@ extern const char *meshlink_strerror(meshlink_errno_t err); */ extern meshlink_handle_t *meshlink_open(const char *confbase, const char *name); +/// is used by the C++ wrapper to allocate more memory behind the handle +extern meshlink_handle_t *meshlink_open_with_size(const char *confbase, const char *name, size_t size); + /// Start MeshLink. /** This function causes MeshLink to open network sockets, make outgoing connections, and * create a new thread, which will handle all network I/O. -- 2.39.2