summaryrefslogtreecommitdiff
path: root/libs/libmosquitto/src/util_mosq.c
diff options
context:
space:
mode:
authorGeorge Hazan <ghazan@miranda.im>2019-12-23 13:53:27 +0300
committerGeorge Hazan <ghazan@miranda.im>2019-12-23 13:53:27 +0300
commita29c9194cf2d9f11839ea833872beab754e19527 (patch)
tree2a1ff6475dd77d41a1e6bf6acfb5be479c5543eb /libs/libmosquitto/src/util_mosq.c
parentc1358991022919836c77d630ee9a3719fff86ed0 (diff)
libmosquitto - a helper for MQTT clients
Diffstat (limited to 'libs/libmosquitto/src/util_mosq.c')
-rw-r--r--libs/libmosquitto/src/util_mosq.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/libs/libmosquitto/src/util_mosq.c b/libs/libmosquitto/src/util_mosq.c
new file mode 100644
index 0000000000..5e1065e7c4
--- /dev/null
+++ b/libs/libmosquitto/src/util_mosq.c
@@ -0,0 +1,354 @@
+/*
+Copyright (c) 2009-2019 Roger Light <roger@atchoo.org>
+
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v1.0
+and Eclipse Distribution License v1.0 which accompany this distribution.
+
+The Eclipse Public License is available at
+ http://www.eclipse.org/legal/epl-v10.html
+and the Eclipse Distribution License is available at
+ http://www.eclipse.org/org/documents/edl-v10.php.
+
+Contributors:
+ Roger Light - initial implementation and documentation.
+*/
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#ifdef WIN32
+# include <winsock2.h>
+# include <aclapi.h>
+# include <io.h>
+# include <lmcons.h>
+#else
+# include <sys/stat.h>
+#endif
+
+#if !defined(WITH_TLS) && defined(__linux__) && defined(__GLIBC__)
+# if __GLIBC_PREREQ(2, 25)
+# include <sys/random.h>
+# define HAVE_GETRANDOM 1
+# endif
+#endif
+
+#ifdef WITH_TLS
+# include <openssl/bn.h>
+# include <openssl/rand.h>
+#endif
+
+#ifdef WITH_BROKER
+#include "mosquitto_broker_internal.h"
+#endif
+
+#include "mosquitto.h"
+#include "memory_mosq.h"
+#include "net_mosq.h"
+#include "send_mosq.h"
+#include "time_mosq.h"
+#include "tls_mosq.h"
+#include "util_mosq.h"
+
+#ifdef WITH_WEBSOCKETS
+#include <libwebsockets.h>
+#endif
+
+#ifdef WITH_BROKER
+int mosquitto__check_keepalive(struct mosquitto_db *db, struct mosquitto *mosq)
+#else
+int mosquitto__check_keepalive(struct mosquitto *mosq)
+#endif
+{
+ time_t next_msg_out;
+ time_t last_msg_in;
+ time_t now = mosquitto_time();
+#ifndef WITH_BROKER
+ int rc;
+#endif
+
+ assert(mosq);
+#if defined(WITH_BROKER) && defined(WITH_BRIDGE)
+ /* Check if a lazy bridge should be timed out due to idle. */
+ if(mosq->bridge && mosq->bridge->start_type == bst_lazy
+ && mosq->sock != INVALID_SOCKET
+ && now - mosq->next_msg_out - mosq->keepalive >= mosq->bridge->idle_timeout){
+
+ log__printf(NULL, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id);
+ net__socket_close(db, mosq);
+ return MOSQ_ERR_SUCCESS;
+ }
+#endif
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ next_msg_out = mosq->next_msg_out;
+ last_msg_in = mosq->last_msg_in;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ if(mosq->keepalive && mosq->sock != INVALID_SOCKET &&
+ (now >= next_msg_out || now - last_msg_in >= mosq->keepalive)){
+
+ if(mosq->state == mosq_cs_connected && mosq->ping_t == 0){
+ send__pingreq(mosq);
+ /* Reset last msg times to give the server time to send a pingresp */
+ pthread_mutex_lock(&mosq->msgtime_mutex);
+ mosq->last_msg_in = now;
+ mosq->next_msg_out = now + mosq->keepalive;
+ pthread_mutex_unlock(&mosq->msgtime_mutex);
+ }else{
+#ifdef WITH_BROKER
+ net__socket_close(db, mosq);
+#else
+ net__socket_close(mosq);
+ pthread_mutex_lock(&mosq->state_mutex);
+ if(mosq->state == mosq_cs_disconnecting){
+ rc = MOSQ_ERR_SUCCESS;
+ }else{
+ rc = MOSQ_ERR_KEEPALIVE;
+ }
+ pthread_mutex_unlock(&mosq->state_mutex);
+ pthread_mutex_lock(&mosq->callback_mutex);
+ if(mosq->on_disconnect){
+ mosq->in_callback = true;
+ mosq->on_disconnect(mosq, mosq->userdata, rc);
+ mosq->in_callback = false;
+ }
+ if(mosq->on_disconnect_v5){
+ mosq->in_callback = true;
+ mosq->on_disconnect_v5(mosq, mosq->userdata, rc, NULL);
+ mosq->in_callback = false;
+ }
+ pthread_mutex_unlock(&mosq->callback_mutex);
+
+ return rc;
+#endif
+ }
+ }
+ return MOSQ_ERR_SUCCESS;
+}
+
+uint16_t mosquitto__mid_generate(struct mosquitto *mosq)
+{
+ /* FIXME - this would be better with atomic increment, but this is safer
+ * for now for a bug fix release.
+ *
+ * If this is changed to use atomic increment, callers of this function
+ * will have to be aware that they may receive a 0 result, which may not be
+ * used as a mid.
+ */
+ uint16_t mid;
+ assert(mosq);
+
+ pthread_mutex_lock(&mosq->mid_mutex);
+ mosq->last_mid++;
+ if(mosq->last_mid == 0) mosq->last_mid++;
+ mid = mosq->last_mid;
+ pthread_mutex_unlock(&mosq->mid_mutex);
+
+ return mid;
+}
+
+
+#ifdef WITH_TLS
+int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin)
+{
+ unsigned char *sha, tmp[SHA_DIGEST_LENGTH];
+
+ if(mosquitto__hex2bin(hex, tmp, SHA_DIGEST_LENGTH) != SHA_DIGEST_LENGTH){
+ return MOSQ_ERR_INVAL;
+ }
+
+ sha = mosquitto__malloc(SHA_DIGEST_LENGTH);
+ memcpy(sha, tmp, SHA_DIGEST_LENGTH);
+ *bin = sha;
+ return MOSQ_ERR_SUCCESS;
+}
+
+int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len)
+{
+ BIGNUM *bn = NULL;
+ int len;
+ int leading_zero = 0;
+ int start = 0;
+ size_t i = 0;
+
+ /* Count the number of leading zero */
+ for(i=0; i<strlen(hex); i=i+2) {
+ if(strncmp(hex + i, "00", 2) == 0) {
+ leading_zero++;
+ /* output leading zero to bin */
+ bin[start++] = 0;
+ }else{
+ break;
+ }
+ }
+
+ if(BN_hex2bn(&bn, hex) == 0){
+ if(bn) BN_free(bn);
+ return 0;
+ }
+ if(BN_num_bytes(bn) + leading_zero > bin_max_len){
+ BN_free(bn);
+ return 0;
+ }
+
+ len = BN_bn2bin(bn, bin + leading_zero);
+ BN_free(bn);
+ return len + leading_zero;
+}
+#endif
+
+FILE *mosquitto__fopen(const char *path, const char *mode, bool restrict_read)
+{
+#ifdef WIN32
+ char buf[4096];
+ int rc;
+ rc = ExpandEnvironmentStrings(path, buf, 4096);
+ if(rc == 0 || rc > 4096){
+ return NULL;
+ }else{
+ if (restrict_read) {
+ HANDLE hfile;
+ SECURITY_ATTRIBUTES sec;
+ EXPLICIT_ACCESS ea;
+ PACL pacl = NULL;
+ char username[UNLEN + 1];
+ int ulen = UNLEN;
+ SECURITY_DESCRIPTOR sd;
+ DWORD dwCreationDisposition;
+
+ switch(mode[0]){
+ case 'a':
+ dwCreationDisposition = OPEN_ALWAYS;
+ break;
+ case 'r':
+ dwCreationDisposition = OPEN_EXISTING;
+ break;
+ case 'w':
+ dwCreationDisposition = CREATE_ALWAYS;
+ break;
+ default:
+ return NULL;
+ }
+
+ GetUserName(username, &ulen);
+ if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
+ return NULL;
+ }
+ BuildExplicitAccessWithName(&ea, username, GENERIC_ALL, SET_ACCESS, NO_INHERITANCE);
+ if (SetEntriesInAcl(1, &ea, NULL, &pacl) != ERROR_SUCCESS) {
+ return NULL;
+ }
+ if (!SetSecurityDescriptorDacl(&sd, TRUE, pacl, FALSE)) {
+ LocalFree(pacl);
+ return NULL;
+ }
+
+ sec.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sec.bInheritHandle = FALSE;
+ sec.lpSecurityDescriptor = &sd;
+
+ hfile = CreateFile(buf, GENERIC_READ | GENERIC_WRITE, 0,
+ &sec,
+ dwCreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ LocalFree(pacl);
+
+ int fd = _open_osfhandle((intptr_t)hfile, 0);
+ if (fd < 0) {
+ return NULL;
+ }
+
+ FILE *fptr = _fdopen(fd, mode);
+ if (!fptr) {
+ _close(fd);
+ return NULL;
+ }
+ return fptr;
+
+ }else {
+ return fopen(buf, mode);
+ }
+ }
+#else
+ if (restrict_read) {
+ FILE *fptr;
+ mode_t old_mask;
+
+ old_mask = umask(0077);
+ fptr = fopen(path, mode);
+ umask(old_mask);
+
+ return fptr;
+ }else{
+ return fopen(path, mode);
+ }
+#endif
+}
+
+void util__increment_receive_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_in.inflight_quota < mosq->msgs_in.inflight_maximum){
+ mosq->msgs_in.inflight_quota++;
+ }
+}
+
+void util__increment_send_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_out.inflight_quota < mosq->msgs_out.inflight_maximum){
+ mosq->msgs_out.inflight_quota++;
+ }
+}
+
+
+void util__decrement_receive_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_in.inflight_quota > 0){
+ mosq->msgs_in.inflight_quota--;
+ }
+}
+
+void util__decrement_send_quota(struct mosquitto *mosq)
+{
+ if(mosq->msgs_out.inflight_quota > 0){
+ mosq->msgs_out.inflight_quota--;
+ }
+}
+
+
+int util__random_bytes(void *bytes, int count)
+{
+ int rc = MOSQ_ERR_UNKNOWN;
+
+#ifdef WITH_TLS
+ if(RAND_bytes(bytes, count) == 1){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+#elif defined(HAVE_GETRANDOM)
+ if(getrandom(bytes, count, 0) == count){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+#elif defined(WIN32)
+ HCRYPTPROV provider;
+
+ if(!CryptAcquireContext(&provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)){
+ return MOSQ_ERR_UNKNOWN;
+ }
+
+ if(CryptGenRandom(provider, count, bytes)){
+ rc = MOSQ_ERR_SUCCESS;
+ }
+
+ CryptReleaseContext(provider, 0);
+#else
+ int i;
+
+ for(i=0; i<count; i++){
+ ((uint8_t *)bytes)[i] = (uint8_t )(random()&0xFF);
+ }
+ rc = MOSQ_ERR_SUCCESS;
+#endif
+ return rc;
+}