/src/mosquitto/lib/util_mosq.c
Line | Count | Source |
1 | | /* |
2 | | Copyright (c) 2009-2021 Roger Light <roger@atchoo.org> |
3 | | |
4 | | All rights reserved. This program and the accompanying materials |
5 | | are made available under the terms of the Eclipse Public License 2.0 |
6 | | and Eclipse Distribution License v1.0 which accompany this distribution. |
7 | | |
8 | | The Eclipse Public License is available at |
9 | | https://www.eclipse.org/legal/epl-2.0/ |
10 | | and the Eclipse Distribution License is available at |
11 | | http://www.eclipse.org/org/documents/edl-v10.php. |
12 | | |
13 | | SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
14 | | |
15 | | Contributors: |
16 | | Roger Light - initial implementation and documentation. |
17 | | */ |
18 | | |
19 | | #include "config.h" |
20 | | |
21 | | #include <assert.h> |
22 | | #include <ctype.h> |
23 | | #include <string.h> |
24 | | |
25 | | #ifdef WIN32 |
26 | | # include <winsock2.h> |
27 | | # include <aclapi.h> |
28 | | # include <io.h> |
29 | | # include <lmcons.h> |
30 | | #else |
31 | | # include <sys/stat.h> |
32 | | #endif |
33 | | |
34 | | #ifdef WITH_TLS |
35 | | # include <openssl/bn.h> |
36 | | #endif |
37 | | |
38 | | #ifdef WITH_BROKER |
39 | | #include "mosquitto_broker_internal.h" |
40 | | #else |
41 | | # include "callbacks.h" |
42 | | #endif |
43 | | |
44 | | #include "mosquitto.h" |
45 | | #include "net_mosq.h" |
46 | | #include "send_mosq.h" |
47 | | #include "tls_mosq.h" |
48 | | #include "util_mosq.h" |
49 | | |
50 | | #if defined(WITH_WEBSOCKETS) && WITH_WEBSOCKETS == WS_IS_LWS |
51 | | #include <libwebsockets.h> |
52 | | #endif |
53 | | |
54 | | |
55 | | int mosquitto__check_keepalive(struct mosquitto *mosq) |
56 | 0 | { |
57 | 0 | time_t next_msg_out; |
58 | 0 | time_t last_msg_in; |
59 | 0 | time_t now; |
60 | | #ifndef WITH_BROKER |
61 | | int rc; |
62 | | #endif |
63 | 0 | enum mosquitto_client_state state; |
64 | |
|
65 | 0 | assert(mosq); |
66 | 0 | #ifdef WITH_BROKER |
67 | 0 | now = db.now_s; |
68 | | #else |
69 | | now = mosquitto_time(); |
70 | | #endif |
71 | |
|
72 | 0 | #if defined(WITH_BROKER) && defined(WITH_BRIDGE) |
73 | | /* Check if a lazy bridge should be timed out due to idle. */ |
74 | 0 | if(mosq->bridge && mosq->bridge->start_type == bst_lazy |
75 | 0 | && net__is_connected(mosq) |
76 | 0 | && now - mosq->next_msg_out - mosq->keepalive >= mosq->bridge->idle_timeout){ |
77 | |
|
78 | 0 | log__printf(mosq, MOSQ_LOG_NOTICE, "Bridge connection %s has exceeded idle timeout, disconnecting.", mosq->id); |
79 | 0 | net__socket_close(mosq); |
80 | 0 | return MOSQ_ERR_SUCCESS; |
81 | 0 | } |
82 | 0 | #endif |
83 | 0 | COMPAT_pthread_mutex_lock(&mosq->msgtime_mutex); |
84 | 0 | next_msg_out = mosq->next_msg_out; |
85 | 0 | last_msg_in = mosq->last_msg_in; |
86 | 0 | COMPAT_pthread_mutex_unlock(&mosq->msgtime_mutex); |
87 | 0 | if(mosq->keepalive && net__is_connected(mosq) && |
88 | 0 | (now >= next_msg_out || now - last_msg_in >= mosq->keepalive)){ |
89 | |
|
90 | 0 | state = mosquitto__get_state(mosq); |
91 | 0 | if(state == mosq_cs_active && mosq->ping_t == 0){ |
92 | 0 | send__pingreq(mosq); |
93 | | /* Reset last msg times to give the server time to send a pingresp */ |
94 | 0 | COMPAT_pthread_mutex_lock(&mosq->msgtime_mutex); |
95 | 0 | mosq->last_msg_in = now; |
96 | 0 | mosq->next_msg_out = now + mosq->keepalive; |
97 | 0 | COMPAT_pthread_mutex_unlock(&mosq->msgtime_mutex); |
98 | 0 | }else{ |
99 | 0 | #ifdef WITH_BROKER |
100 | 0 | # ifdef WITH_BRIDGE |
101 | 0 | if(mosq->bridge){ |
102 | 0 | context__send_will(mosq); |
103 | 0 | } |
104 | 0 | # endif |
105 | 0 | net__socket_close(mosq); |
106 | | #else |
107 | | net__socket_close(mosq); |
108 | | state = mosquitto__get_state(mosq); |
109 | | if(state == mosq_cs_disconnecting){ |
110 | | rc = MOSQ_ERR_SUCCESS; |
111 | | }else{ |
112 | | rc = MOSQ_ERR_KEEPALIVE; |
113 | | } |
114 | | callback__on_disconnect(mosq, rc, NULL); |
115 | | |
116 | | return rc; |
117 | | #endif |
118 | 0 | } |
119 | 0 | } |
120 | 0 | return MOSQ_ERR_SUCCESS; |
121 | 0 | } |
122 | | |
123 | | |
124 | | uint16_t mosquitto__mid_generate(struct mosquitto *mosq) |
125 | 0 | { |
126 | | /* FIXME - this would be better with atomic increment, but this is safer |
127 | | * for now for a bug fix release. |
128 | | * |
129 | | * If this is changed to use atomic increment, callers of this function |
130 | | * will have to be aware that they may receive a 0 result, which may not be |
131 | | * used as a mid. |
132 | | */ |
133 | 0 | uint16_t mid; |
134 | 0 | assert(mosq); |
135 | |
|
136 | 0 | COMPAT_pthread_mutex_lock(&mosq->mid_mutex); |
137 | 0 | mosq->last_mid++; |
138 | 0 | if(mosq->last_mid == 0){ |
139 | 0 | mosq->last_mid++; |
140 | 0 | } |
141 | 0 | mid = mosq->last_mid; |
142 | 0 | COMPAT_pthread_mutex_unlock(&mosq->mid_mutex); |
143 | |
|
144 | 0 | return mid; |
145 | 0 | } |
146 | | |
147 | | |
148 | | #ifdef WITH_TLS |
149 | | |
150 | | |
151 | | int mosquitto__hex2bin_sha1(const char *hex, unsigned char **bin) |
152 | 0 | { |
153 | 0 | unsigned char *sha, tmp[SHA_DIGEST_LENGTH]; |
154 | |
|
155 | 0 | if(mosquitto__hex2bin(hex, tmp, SHA_DIGEST_LENGTH) != SHA_DIGEST_LENGTH){ |
156 | 0 | return MOSQ_ERR_INVAL; |
157 | 0 | } |
158 | | |
159 | 0 | sha = mosquitto_malloc(SHA_DIGEST_LENGTH); |
160 | 0 | if(!sha){ |
161 | 0 | return MOSQ_ERR_NOMEM; |
162 | 0 | } |
163 | 0 | memcpy(sha, tmp, SHA_DIGEST_LENGTH); |
164 | 0 | *bin = sha; |
165 | 0 | return MOSQ_ERR_SUCCESS; |
166 | 0 | } |
167 | | |
168 | | |
169 | | int mosquitto__hex2bin(const char *hex, unsigned char *bin, int bin_max_len) |
170 | 0 | { |
171 | 0 | BIGNUM *bn = NULL; |
172 | 0 | int len; |
173 | 0 | int leading_zero = 0; |
174 | 0 | size_t i = 0; |
175 | | |
176 | | /* Count the number of leading zero */ |
177 | 0 | for(i=0; i<strlen(hex); i=i+2){ |
178 | 0 | if(strncmp(hex + i, "00", 2) == 0){ |
179 | 0 | if(leading_zero >= bin_max_len){ |
180 | 0 | return 0; |
181 | 0 | } |
182 | | /* output leading zero to bin */ |
183 | 0 | bin[leading_zero] = 0; |
184 | 0 | leading_zero++; |
185 | 0 | }else{ |
186 | 0 | break; |
187 | 0 | } |
188 | 0 | } |
189 | | |
190 | 0 | if(BN_hex2bn(&bn, hex) == 0){ |
191 | 0 | if(bn){ |
192 | 0 | BN_free(bn); |
193 | 0 | } |
194 | 0 | return 0; |
195 | 0 | } |
196 | 0 | if(BN_num_bytes(bn) + leading_zero > bin_max_len){ |
197 | 0 | BN_free(bn); |
198 | 0 | return 0; |
199 | 0 | } |
200 | | |
201 | 0 | len = BN_bn2bin(bn, bin + leading_zero); |
202 | 0 | BN_free(bn); |
203 | 0 | return len + leading_zero; |
204 | 0 | } |
205 | | #endif |
206 | | |
207 | | |
208 | | void util__increment_receive_quota(struct mosquitto *mosq) |
209 | 21 | { |
210 | 21 | if(mosq->msgs_in.inflight_quota < mosq->msgs_in.inflight_maximum){ |
211 | 0 | mosq->msgs_in.inflight_quota++; |
212 | 0 | } |
213 | 21 | } |
214 | | |
215 | | |
216 | | void util__increment_send_quota(struct mosquitto *mosq) |
217 | 24 | { |
218 | 24 | if(mosq->msgs_out.inflight_quota < mosq->msgs_out.inflight_maximum){ |
219 | 0 | mosq->msgs_out.inflight_quota++; |
220 | 0 | } |
221 | 24 | } |
222 | | |
223 | | |
224 | | void util__decrement_receive_quota(struct mosquitto *mosq) |
225 | 0 | { |
226 | 0 | if(mosq->msgs_in.inflight_quota > 0){ |
227 | 0 | mosq->msgs_in.inflight_quota--; |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | | |
232 | | void util__decrement_send_quota(struct mosquitto *mosq) |
233 | 0 | { |
234 | 0 | if(mosq->msgs_out.inflight_quota > 0){ |
235 | 0 | mosq->msgs_out.inflight_quota--; |
236 | 0 | } |
237 | 0 | } |
238 | | |
239 | | |
240 | | int mosquitto__set_state(struct mosquitto *mosq, enum mosquitto_client_state state) |
241 | 7.75k | { |
242 | 7.75k | COMPAT_pthread_mutex_lock(&mosq->state_mutex); |
243 | 7.75k | #ifdef WITH_BROKER |
244 | 7.75k | if(mosq->state != mosq_cs_disused) |
245 | 7.75k | #endif |
246 | 7.75k | { |
247 | 7.75k | mosq->state = state; |
248 | 7.75k | } |
249 | 7.75k | COMPAT_pthread_mutex_unlock(&mosq->state_mutex); |
250 | | |
251 | 7.75k | return MOSQ_ERR_SUCCESS; |
252 | 7.75k | } |
253 | | |
254 | | enum mosquitto_client_state mosquitto__get_state(struct mosquitto *mosq) |
255 | 162 | { |
256 | 162 | enum mosquitto_client_state state; |
257 | | |
258 | 162 | COMPAT_pthread_mutex_lock(&mosq->state_mutex); |
259 | 162 | state = mosq->state; |
260 | 162 | COMPAT_pthread_mutex_unlock(&mosq->state_mutex); |
261 | | |
262 | 162 | return state; |
263 | 162 | } |
264 | | |
265 | | #ifndef WITH_BROKER |
266 | | |
267 | | |
268 | | void mosquitto__set_request_disconnect(struct mosquitto *mosq, bool request_disconnect) |
269 | | { |
270 | | COMPAT_pthread_mutex_lock(&mosq->state_mutex); |
271 | | mosq->request_disconnect = request_disconnect; |
272 | | COMPAT_pthread_mutex_unlock(&mosq->state_mutex); |
273 | | } |
274 | | |
275 | | |
276 | | bool mosquitto__get_request_disconnect(struct mosquitto *mosq) |
277 | | { |
278 | | bool request_disconnect; |
279 | | |
280 | | COMPAT_pthread_mutex_lock(&mosq->state_mutex); |
281 | | request_disconnect = mosq->request_disconnect; |
282 | | COMPAT_pthread_mutex_unlock(&mosq->state_mutex); |
283 | | |
284 | | return request_disconnect; |
285 | | } |
286 | | #endif |