From: Guus Sliepen Date: Wed, 30 Jul 2014 13:03:37 +0000 (+0200) Subject: Address Lars's comments on the API. X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=57b227500ff9daf865e70c95d5837bd3103d6be5;p=meshlink Address Lars's comments on the API. - Add meshlink_whitelist() as a counterpart to meshlink_blacklist(). - Change meshlink_get_all_nodes() to return memory allocated by MeshLink. - Specify when pointers are allowed to be NULL. - Specify when strings must be nul-terminated. - Clarify some corner cases. --- diff --git a/src/meshlink.c b/src/meshlink.c index f4e213c5..a49aa578 100644 --- a/src/meshlink.c +++ b/src/meshlink.c @@ -950,24 +950,30 @@ meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *name) { return (meshlink_node_t *)lookup_node(mesh, (char *)name); // TODO: make lookup_node() use const } -ssize_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t nmemb) { +meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb) { if(!mesh || (nmemb && !nodes)) - return -1; + return NULL; - size_t i = 0; + meshlink_node_t **result, **p; //lock mesh->nodes pthread_mutex_lock(&(mesh->nodes_mutex)); - for splay_each(node_t, n, mesh->nodes) { - if(i < nmemb) - nodes[i] = (meshlink_node_t *)n; - i++; + *nmemb = mesh->nodes->count; + result = realloc(nodes, *nmemb * sizeof *nodes); + + if(result) { + for splay_each(node_t, n, mesh->nodes) + *p++ = (meshlink_node_t *)n; + } else { + *nmemb = 0; + free(nodes); + meshlink_errno = MESHLINK_ENOMEM; } pthread_mutex_unlock(&(mesh->nodes_mutex)); - return i; + return result; } bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, void *signature, size_t *siglen) { @@ -1455,6 +1461,18 @@ void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node) { return; } +void meshlink_whitelist(meshlink_handle_t *mesh, meshlink_node_t *node) { + if(!mesh || !node) + return; + + node_t *n = (node_t *)node; + n->status.blacklisted = false; + + //TODO: remove blacklisted = yes from the config file + + return; +} + static void __attribute__((constructor)) meshlink_init(void) { crypto_init(); } diff --git a/src/meshlink.h b/src/meshlink.h index 7fd71fe8..ebd33036 100644 --- a/src/meshlink.h +++ b/src/meshlink.h @@ -49,6 +49,11 @@ typedef enum { } meshlink_errno_t; /// A variable holding the last encountered error from MeshLink. +/** This is a thread local variable that contains the error code of the most recent error + * encountered by a MeshLink API function called in the current thread. + * The variable is only updated when an error is encountered, and is not reset to MESHLINK_OK + * if a function returned succesfully. + */ extern __thread meshlink_errno_t meshlink_errno; #ifndef MESHLINK_INTERNAL_H @@ -57,8 +62,8 @@ struct meshlink_handle { }; struct meshlink_node { - const char *name; ///< Textual name of this node. - void *priv; ///< Private pointer which the application can set at will. + const char *name; ///< Textual name of this node. It is stored in a nul-terminated C string, which is allocated by MeshLink. + void *priv; ///< Private pointer which may be set freely by the application, and is never used or modified by MeshLink. }; struct meshlink_channel { @@ -72,6 +77,7 @@ struct meshlink_channel { * @param err An error code returned by MeshLink. * * @return A pointer to a string containing the description of the error code. + * The pointer is to static storage that is valid for the lifetime of the application. * This function will always return a valid pointer, even if an invalid error code has been passed. */ extern const char *meshlink_strerror(meshlink_errno_t err); @@ -106,9 +112,11 @@ extern meshlink_handle_t *meshlink_open(const char *confbase, const char *name); /** This function causes MeshLink to open network sockets, make outgoing connections, and * create a new thread, which will handle all network I/O. * + * It is allowed to call this function even if MeshLink is already started, in which case it will return true. + * * @param mesh A handle which represents an instance of MeshLink. * - * @return This function will return true if MeshLink has succesfully started its thread, false otherwise. + * @return This function will return true if MeshLink has succesfully started, false otherwise. */ extern bool meshlink_start(meshlink_handle_t *mesh); @@ -116,6 +124,8 @@ extern bool meshlink_start(meshlink_handle_t *mesh); /** This function causes MeshLink to disconnect from all other nodes, * close all sockets, and shut down its own thread. * + * This function always succeeds. It is allowed to call meshlink_stop() even if MeshLink is already stopped or has never been started. + * * @param mesh A handle which represents an instance of MeshLink. */ extern void meshlink_stop(meshlink_handle_t *mesh); @@ -125,6 +135,10 @@ extern void meshlink_stop(meshlink_handle_t *mesh); * and frees the struct meshlink_handle and all associacted memory allocated by MeshLink. * Afterwards, the handle and any pointers to a struct meshlink_node or struct meshlink_channel are invalid. * + * It is allowed to call this function at any time on a valid handle, except inside callback functions. + * If called at a proper time with a valid handle, this function always succeeds. + * If called within a callback or with an invalid handle, the result is undefined. + * * @param mesh A handle which represents an instance of MeshLink. */ extern void meshlink_close(meshlink_handle_t *mesh); @@ -132,10 +146,10 @@ extern void meshlink_close(meshlink_handle_t *mesh); /// A callback for receiving data from the mesh. /** @param mesh A handle which represents an instance of MeshLink. * @param source A pointer to a meshlink_node_t describing the source of the data. - * @param data A pointer to a buffer containing the data sent by the source. + * @param data A pointer to a buffer containing the data sent by the source, or NULL in case there is no data (an empty packet was received). * The pointer is only valid during the lifetime of the callback. * The callback should mempcy() the data if it needs to be available outside the callback. - * @param len The length of the received data. + * @param len The length of the received data, or 0 in case there is no data. */ typedef void (*meshlink_receive_cb_t)(meshlink_handle_t *mesh, meshlink_node_t *source, const void *data, size_t len); @@ -155,6 +169,7 @@ extern void meshlink_set_receive_cb(meshlink_handle_t *mesh, meshlink_receive_cb /// A callback reporting node status changes. /** @param mesh A handle which represents an instance of MeshLink. * @param node A pointer to a meshlink_node_t describing the node whose status changed. + * This pointer is valid until meshlink_close() is called. * @param reachable True if the node is reachable, false otherwise. */ typedef void (*meshlink_node_status_cb_t)(meshlink_handle_t *mesh, meshlink_node_t *node, bool reachable); @@ -184,8 +199,9 @@ typedef enum { /// A callback for receiving log messages generated by MeshLink. /** @param mesh A handle which represents an instance of MeshLink. * @param level An enum describing the severity level of the message. - * @param text A pointer to a string containing the textual log message. + * @param text A pointer to a nul-terminated C string containing the textual log message. * This pointer is only valid for the duration of the callback. + * The application must not free() this pointer. * The application should strdup() the text if it has to be available outside the callback. */ typedef void (*meshlink_log_cb_t)(meshlink_handle_t *mesh, meshlink_log_level_t level, const char *text); @@ -209,12 +225,15 @@ extern void meshlink_set_log_cb(meshlink_handle_t *mesh, meshlink_log_level_t le * The packet is sent using UDP semantics, which means that * the packet is sent as one unit and is received as one unit, * and that there is no guarantee that the packet will arrive at the destination. + * Packets that are too big to be sent over the network as one unit might be dropped, and this function may return an error if this situation can be detected beforehand. + * The application should not send packets that are larger than the path MTU, which can be queried with meshlink_get_pmtu(). * The application should take care of getting an acknowledgement and retransmission if necessary. * * @param mesh A handle which represents an instance of MeshLink. * @param destination A pointer to a meshlink_node_t describing the destination for the data. * @param data A pointer to a buffer containing the data to be sent to the source. * After meshlink_send() returns, the application is free to overwrite or free this buffer. + * It is valid to specify a NULL pointer, but only if @a len @a is also 0. * @param len The length of the data. * @return This function will return true if MeshLink has queued the message for transmission, and false otherwise. * A return value of true does not guarantee that the message will actually arrive at the destination. @@ -238,14 +257,20 @@ extern meshlink_node_t *meshlink_get_node(meshlink_handle_t *mesh, const char *n /** This function returns a list with handles for all known nodes. * * @param mesh A handle which represents an instance of MeshLink. - * @param nodes A pointer to an array of pointers to meshlink_node_t, which should be allocated by the application. - * The pointers are valid until meshlink_close() is called. - * @param nmemb The maximum number of pointers that can be stored in the nodes array. - * - * @return The number of known nodes, or -1 in case of an error. - * The returned number of nodes can be larger than nmemb, in which case not all nodes were stored in the nodes array. + * @param nodes A pointer to a previously allocated array of pointers to meshlink_node_t, or NULL in which case MeshLink will allocate a new array. + * The application can supply an array it allocated itself with malloc, or the return value from the previous call to this function (which is the preferred way). + * The application is allowed to call free() on the array whenever it wishes. + * The pointers in the array are valid until meshlink_close() is called. + * @param nmemb A pointer to a variable holding the number of nodes that are stored in the array. + * In case the @a nodes @a argument is not NULL, MeshLink might call realloc() on the array to change its size. + * The contents of this variable will be changed to reflect the new size of the array. + * + * @return A pointer to an array containing pointers to all known nodes, or NULL in case of an error. + * If the @a nodes @a argument was not NULL, then the return value can either be the same value or a different value. + * If it is a new value, the old value of @a nodes @a should not be used anymore. + * If the new value is NULL, then the old array will have been freed by MeshLink. */ -extern ssize_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t nmemb); +extern meshlink_node_t **meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t **nodes, size_t *nmemb); /// Sign data using the local node's MeshLink key. /** This function signs data using the local node's MeshLink key. @@ -256,6 +281,7 @@ extern ssize_t meshlink_get_all_nodes(meshlink_handle_t *mesh, meshlink_node_t * * @param len The length of the data to be signed. * @param signature A pointer to a buffer where the signature will be stored. * The buffer must be allocated by the application, and should be at least MESHLINK_SIGLEN bytes big. + * The signature is a binary blob, and is not nul-terminated. * @param siglen The size of the signature buffer. Will be changed after the call to match the size of the signature itself. * * @return This function returns true if the signature was correctly generated, false otherwise. @@ -269,7 +295,7 @@ extern bool meshlink_sign(meshlink_handle_t *mesh, const void *data, size_t len, * @param source A pointer to a meshlink_node_t describing the source of the signature. * @param data A pointer to a buffer containing the data to be verified. * @param len The length of the data to be verified. - * @param signature A pointer to a buffer where the signature will be stored. + * @param signature A pointer to a buffer where the signature is stored. * @param siglen A pointer to a variable holding the size of the signature buffer. * The contents of the variable will be changed by meshlink_sign() to reflect the actual size of the signature. * @@ -281,7 +307,7 @@ extern bool meshlink_verify(meshlink_handle_t *mesh, meshlink_node_t *source, co /** This function adds an Address for the local node, which will be used for invitation URLs. * * @param mesh A handle which represents an instance of MeshLink. - * @param address A string containing the address, which can be either in numeric format or a hostname. + * @param address A nul-terminated C string containing the address, which can be either in numeric format or a hostname. * * @return This function returns true if the address was added, false otherwise. */ @@ -294,10 +320,10 @@ extern bool meshlink_add_address(meshlink_handle_t *mesh, const char *address); * The URL can only be used once, after the user has joined the mesh the URL is no longer valid. * * @param mesh A handle which represents an instance of MeshLink. - * @param name The name that the invitee will use in the mesh. + * @param name A nul-terminated C string containing the name that the invitee will be allowed to use in the mesh. * After this function returns, the application is free to overwrite or free @a name @a. * - * @return This function returns a string that contains the invitation URL, or NULL in case of an error. + * @return This function returns a nul-terminated C string that contains the invitation URL, or NULL in case of an error. * The application should call free() after it has finished using the URL. */ extern char *meshlink_invite(meshlink_handle_t *mesh, const char *name); @@ -308,7 +334,7 @@ extern char *meshlink_invite(meshlink_handle_t *mesh, const char *name); * After a succesfully accepted invitation, the name of the local node may have changed. * * @param mesh A handle which represents an instance of MeshLink. - * @param invitation A string containing the invitation URL. + * @param invitation A nul-terminated C string containing the invitation URL. * After this function returns, the application is free to overwrite or free @a invitation @a. * * @return This function returns true if the local node joined the mesh it was invited to, false otherwise. @@ -319,10 +345,13 @@ extern bool meshlink_join(meshlink_handle_t *mesh, const char *invitation); /** This function generates a string that contains the local node's public key and one or more IP addresses. * The application can pass it in some way to another node, which can then import it, * granting the local node access to the other node's mesh. + * The exported data does not contain any secret keys, it is therefore safe to transmit this data unencrypted over public networks. + * + * Note that to create a working connection between two nodes, both must call meshink_export() and both must meshlink_import() each other's data. * * @param mesh A handle which represents an instance of MeshLink. * - * @return This function returns a string that contains the exported key and addresses, or NULL in case of an error. + * @return This function returns a nul-terminated C string that contains the exported key and addresses, or NULL in case of an error. * The application should call free() after it has finished using this string. */ extern char *meshlink_export(meshlink_handle_t *mesh); @@ -330,9 +359,12 @@ extern char *meshlink_export(meshlink_handle_t *mesh); /// Import another node's key and addresses. /** This function accepts a string containing the exported public key and addresses of another node. * By importing this data, the local node grants the other node access to its mesh. + * The application should make sure that the data it imports is really coming from the node it wants to import, + * + * Note that to create a working connection between two nodes, both must call meshink_export() and both must meshlink_import() each other's data. * * @param mesh A handle which represents an instance of MeshLink. - * @param data A string containing the other node's exported key and addresses. + * @param data A nul-terminated C string containing the other node's exported key and addresses. * After this function returns, the application is free to overwrite or free @a data @a. * * @return This function returns true if the data was valid and the other node has been granted access to the mesh, false otherwise. @@ -349,10 +381,24 @@ extern bool meshlink_import(meshlink_handle_t *mesh, const char *data); */ extern void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node); +/// Whitelist a node on the mesh. +/** This function causes the local node to whitelist a previously blacklisted node. + * The local node will allow connections to and from that node, + * and will send data to it and accept any data received from it. + * + * @param mesh A handle which represents an instance of MeshLink. + * @param node A pointer to a meshlink_node_t describing the node to be blacklisted. + */ +extern void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node); + /// A callback for accepting incoming channels. /** This function is called whenever a remote node wants to open a channel to the local node. * The application then has to decide whether to accept or reject this channel. * + * The callback is run in MeshLink's own thread. + * It is therefore important that the callback return quickly and uses apprioriate methods (queues, pipes, locking, etc.) + * to hand any data over to the application's thread. + * * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the incoming channel. * If the application accepts the incoming channel by returning true, @@ -363,10 +409,10 @@ extern void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node); * @param node The node from which this channel is being initiated. * The pointer is guaranteed to be valid until meshlink_close() is called. * @param port The port number the peer wishes to connect to. - * @param data A pointer to a buffer containing data already received. (Not yet used.) + * @param data A pointer to a buffer containing data already received, or NULL in case no data has been received yet. (Not yet used.) * The pointer is only valid during the lifetime of the callback. * The callback should mempcy() the data if it needs to be available outside the callback. - * @param len The length of the data. (Not yet used.) + * @param len The length of the data, or 0 in case no data has been received yet. (Not yet used.) * * @return This function should return true if the application accepts the incoming channel, false otherwise. * If returning false, the channel is invalid and may not be used anymore. @@ -374,15 +420,18 @@ extern void meshlink_blacklist(meshlink_handle_t *mesh, meshlink_node_t *node); typedef bool (*meshlink_channel_accept_cb_t)(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_node_t *node, uint16_t port, const void *data, size_t len); /// A callback for receiving data from a channel. -/** This function is called whenever a remote node wants to open a channel to the local node. - * The application then has to decide whether to accept or reject this channel. +/** This function is called whenever data is received from a remote node on a channel. + * + * This function is also called in case the channel has been closed by the remote node, or when the channel is terminated abnormally. + * In both cases, @a data @a will be NULL and @a len @a will be 0, and meshlink_errno will be set. + * In any case, the @a channel @a handle will still be valid until the application calls meshlink_close(). * * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the channel. - * @param data A pointer to a buffer containing data sent by the source. + * @param data A pointer to a buffer containing data sent by the source, or NULL in case of an error. * The pointer is only valid during the lifetime of the callback. * The callback should mempcy() the data if it needs to be available outside the callback. - * @param len The length of the data. + * @param len The length of the data, or 0 in case of an error. */ typedef void (*meshlink_channel_receive_cb_t)(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len); @@ -411,7 +460,7 @@ extern void meshlink_set_channel_accept_cb(meshlink_handle_t *mesh, meshlink_cha * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the channel. * @param cb A pointer to the function which will be called when another node sends data to the local node. - * If a NULL pointer is given, the callback will be disabled. + * If a NULL pointer is given, the callback will be disabled and incoming data is ignored. */ extern void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, meshlink_channel_receive_cb_t cb); @@ -427,9 +476,10 @@ extern void meshlink_set_channel_receive_cb(meshlink_handle_t *mesh, meshlink_ch * @param node The node to which this channel is being initiated. * @param port The port number the peer wishes to connect to. * @param cb A pointer to the function which will be called when the remote node sends data to the local node. - * @param data A pointer to a buffer containing data to already queue for sending. + * The pointer may be NULL, in which case incoming data is ignored. + * @param data A pointer to a buffer containing data to already queue for sending, or NULL if there is no data to send. * After meshlink_send() returns, the application is free to overwrite or free this buffer. - * @param len The length of the data. + * @param len The length of the data, or 0 if there is no data to send. * * @return A handle for the channel, or NULL in case of an error. * The handle is valid until meshlink_channel_close() is called. @@ -445,7 +495,7 @@ extern meshlink_channel_t *meshlink_channel_open(meshlink_handle_t *mesh, meshli * * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the channel. - * @param direction Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR. + * @param direction Must be one of SHUT_RD, SHUT_WR or SHUT_RDWR, otherwise this call will not have any affect. */ extern void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_t *channel, int direction); @@ -455,6 +505,9 @@ extern void meshlink_channel_shutdown(meshlink_handle_t *mesh, meshlink_channel_ * It will free the struct meshlink_channel and all associated resources. * Afterwards, the channel handle is invalid and must not be used any more. * + * It is allowed to call this function at any time on a valid handle, even inside callback functions. + * If called with a valid handle, this function always succeeds, otherwise the result is undefined. + * * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the channel. */ @@ -465,9 +518,9 @@ extern void meshlink_channel_close(meshlink_handle_t *mesh, meshlink_channel_t * * * @param mesh A handle which represents an instance of MeshLink. * @param channel A handle for the channel. - * @param data A pointer to a buffer containing data sent by the source. + * @param data A pointer to a buffer containing data sent by the source, or NULL if there is no data to send. * After meshlink_send() returns, the application is free to overwrite or free this buffer. - * @param len The length of the data. + * @param len The length of the data, or 0 if there is no data to send. * * @return The amount of data that was queued, which can be less than len, or a negative value in case of an error. */