]>
Commit | Line | Data |
---|---|---|
9a1955a7 | 1 | /* |
c8d19612 | 2 | * Copyright (c) 2015-2019 Red Hat, Inc. |
9a1955a7 JF |
3 | * |
4 | * All rights reserved. | |
5 | * | |
6 | * Author: Jan Friesse (jfriesse@redhat.com) | |
7 | * | |
8 | * This software licensed under BSD license, the text of which follows: | |
9 | * | |
10 | * Redistribution and use in source and binary forms, with or without | |
11 | * modification, are permitted provided that the following conditions are met: | |
12 | * | |
13 | * - Redistributions of source code must retain the above copyright notice, | |
14 | * this list of conditions and the following disclaimer. | |
15 | * - Redistributions in binary form must reproduce the above copyright notice, | |
16 | * this list of conditions and the following disclaimer in the documentation | |
17 | * and/or other materials provided with the distribution. | |
18 | * - Neither the name of the Red Hat, Inc. nor the names of its | |
19 | * contributors may be used to endorse or promote products derived from this | |
20 | * software without specific prior written permission. | |
21 | * | |
22 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
23 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
24 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
25 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
26 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
27 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
28 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
29 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
30 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
31 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
32 | * THE POSSIBILITY OF SUCH DAMAGE. | |
33 | */ | |
34 | ||
313d42d1 | 35 | #include "log.h" |
fed67019 | 36 | #include "log-common.h" |
9a1955a7 JF |
37 | #include "qdevice-net-algorithm.h" |
38 | #include "qdevice-net-cast-vote-timer.h" | |
39 | #include "qdevice-net-heuristics.h" | |
40 | #include "qdevice-net-msg-received.h" | |
41 | #include "qdevice-net-send.h" | |
42 | #include "qdevice-net-votequorum.h" | |
43 | #include "qdevice-net-echo-request-timer.h" | |
44 | #include "msg.h" | |
45 | #include "utils.h" | |
46 | ||
47 | /* | |
48 | * -1 - Incompatible tls combination | |
49 | * 0 - Don't use TLS | |
50 | * 1 - Use TLS | |
51 | */ | |
52 | static int | |
53 | qdevice_net_msg_received_check_tls_compatibility(enum tlv_tls_supported server_tls, | |
54 | enum tlv_tls_supported client_tls) | |
55 | { | |
56 | int res; | |
57 | ||
58 | res = -1; | |
59 | ||
60 | switch (server_tls) { | |
61 | case TLV_TLS_UNSUPPORTED: | |
62 | switch (client_tls) { | |
63 | case TLV_TLS_UNSUPPORTED: res = 0; break; | |
64 | case TLV_TLS_SUPPORTED: res = 0; break; | |
65 | case TLV_TLS_REQUIRED: res = -1; break; | |
66 | } | |
67 | break; | |
68 | case TLV_TLS_SUPPORTED: | |
69 | switch (client_tls) { | |
70 | case TLV_TLS_UNSUPPORTED: res = 0; break; | |
71 | case TLV_TLS_SUPPORTED: res = 1; break; | |
72 | case TLV_TLS_REQUIRED: res = 1; break; | |
73 | } | |
74 | break; | |
75 | case TLV_TLS_REQUIRED: | |
76 | switch (client_tls) { | |
77 | case TLV_TLS_UNSUPPORTED: res = -1; break; | |
78 | case TLV_TLS_SUPPORTED: res = 1; break; | |
79 | case TLV_TLS_REQUIRED: res = 1; break; | |
80 | } | |
81 | break; | |
82 | } | |
83 | ||
84 | return (res); | |
85 | } | |
86 | ||
9a1955a7 JF |
87 | static int |
88 | qdevice_net_msg_received_unexpected_msg(struct qdevice_net_instance *instance, | |
89 | const struct msg_decoded *msg, const char *msg_str) | |
90 | { | |
91 | ||
c8d19612 | 92 | log(LOG_ERR, "Received unexpected %s message. Disconnecting from server", |
9a1955a7 JF |
93 | msg_str); |
94 | ||
95 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
96 | ||
97 | return (-1); | |
98 | } | |
99 | ||
100 | static int | |
101 | qdevice_net_msg_received_init(struct qdevice_net_instance *instance, | |
102 | const struct msg_decoded *msg) | |
103 | { | |
104 | ||
105 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "init")); | |
106 | } | |
107 | ||
108 | static int | |
109 | qdevice_net_msg_received_preinit(struct qdevice_net_instance *instance, | |
110 | const struct msg_decoded *msg) | |
111 | { | |
112 | ||
113 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "preinit")); | |
114 | } | |
115 | ||
116 | static int | |
117 | qdevice_net_msg_check_seq_number(struct qdevice_net_instance *instance, | |
118 | const struct msg_decoded *msg) | |
119 | { | |
120 | ||
121 | if (!msg->seq_number_set || msg->seq_number != instance->last_msg_seq_num) { | |
c8d19612 | 122 | log(LOG_ERR, "Received message doesn't contain seq_number or " |
9a1955a7 JF |
123 | "it's not expected one."); |
124 | ||
125 | return (-1); | |
126 | } | |
127 | ||
128 | return (0); | |
129 | } | |
130 | ||
131 | static int | |
132 | qdevice_net_msg_received_preinit_reply(struct qdevice_net_instance *instance, | |
133 | const struct msg_decoded *msg) | |
134 | { | |
135 | int res; | |
136 | struct send_buffer_list_entry *send_buffer; | |
137 | ||
c8d19612 | 138 | log(LOG_DEBUG, "Received preinit reply msg"); |
9a1955a7 JF |
139 | |
140 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_PREINIT_REPLY) { | |
c8d19612 | 141 | log(LOG_ERR, "Received unexpected preinit reply message. " |
9a1955a7 JF |
142 | "Disconnecting from server"); |
143 | ||
144 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
145 | ||
146 | return (-1); | |
147 | } | |
148 | ||
149 | if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { | |
150 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
151 | ||
152 | return (-1); | |
153 | } | |
154 | ||
155 | /* | |
156 | * Check TLS support | |
157 | */ | |
158 | if (!msg->tls_supported_set || !msg->tls_client_cert_required_set) { | |
c8d19612 | 159 | log(LOG_ERR, "Required tls_supported or tls_client_cert_required " |
9a1955a7 JF |
160 | "option is unset"); |
161 | ||
162 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
163 | ||
164 | return (-1); | |
165 | } | |
166 | ||
167 | res = qdevice_net_msg_received_check_tls_compatibility(msg->tls_supported, instance->tls_supported); | |
168 | if (res == -1) { | |
c8d19612 | 169 | log(LOG_ERR, "Incompatible tls configuration (server %u client %u)", |
9a1955a7 JF |
170 | msg->tls_supported, instance->tls_supported); |
171 | ||
172 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_TLS; | |
173 | ||
174 | return (-1); | |
175 | } else if (res == 1) { | |
176 | /* | |
177 | * Start TLS | |
178 | */ | |
179 | send_buffer = send_buffer_list_get_new(&instance->send_buffer_list); | |
180 | if (send_buffer == NULL) { | |
c8d19612 | 181 | log(LOG_ERR, "Can't allocate send list buffer for " |
9a1955a7 JF |
182 | "starttls msg"); |
183 | ||
184 | instance->disconnect_reason = | |
185 | QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; | |
186 | ||
187 | return (-1); | |
188 | } | |
189 | ||
190 | instance->last_msg_seq_num++; | |
191 | if (msg_create_starttls(&send_buffer->buffer, 1, | |
192 | instance->last_msg_seq_num) == 0) { | |
c8d19612 | 193 | log(LOG_ERR, "Can't allocate send buffer for starttls msg"); |
9a1955a7 JF |
194 | |
195 | instance->disconnect_reason = | |
196 | QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; | |
197 | ||
198 | send_buffer_list_discard_new(&instance->send_buffer_list, send_buffer); | |
199 | return (-1); | |
200 | } | |
201 | ||
202 | send_buffer_list_put(&instance->send_buffer_list, send_buffer); | |
203 | ||
204 | instance->state = QDEVICE_NET_INSTANCE_STATE_WAITING_STARTTLS_BEING_SENT; | |
205 | } else if (res == 0) { | |
206 | if (qdevice_net_send_init(instance) != 0) { | |
207 | instance->disconnect_reason = | |
208 | QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; | |
209 | ||
210 | return (-1); | |
211 | } | |
212 | } | |
213 | ||
214 | return (0); | |
215 | } | |
216 | ||
217 | static int | |
218 | qdevice_net_msg_received_init_reply(struct qdevice_net_instance *instance, | |
219 | const struct msg_decoded *msg) | |
220 | { | |
221 | size_t zi; | |
222 | int res; | |
223 | enum qdevice_heuristics_mode active_heuristics_mode; | |
224 | ||
c8d19612 | 225 | log(LOG_DEBUG, "Received init reply msg"); |
9a1955a7 JF |
226 | |
227 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_INIT_REPLY) { | |
c8d19612 | 228 | log(LOG_ERR, "Received unexpected init reply message. " |
9a1955a7 JF |
229 | "Disconnecting from server"); |
230 | ||
231 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
232 | ||
233 | return (-1); | |
234 | } | |
235 | ||
236 | if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { | |
237 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
238 | ||
239 | return (-1); | |
240 | } | |
241 | ||
242 | if (!msg->reply_error_code_set) { | |
c8d19612 | 243 | log(LOG_ERR, "Received init reply message without error code." |
9a1955a7 JF |
244 | "Disconnecting from server"); |
245 | ||
246 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
247 | ||
248 | return (-1); | |
249 | } | |
250 | ||
251 | if (msg->reply_error_code != TLV_REPLY_ERROR_CODE_NO_ERROR) { | |
c8d19612 | 252 | log(LOG_ERR, "Received init reply message with error code %"PRIu16". " |
9a1955a7 JF |
253 | "Disconnecting from server", msg->reply_error_code); |
254 | ||
255 | if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_DUPLICATE_NODE_ID) { | |
c8d19612 | 256 | log(LOG_ERR, "Duplicate node id may be result of server not yet " |
9a1955a7 JF |
257 | "accepted this node disconnect. Retry again."); |
258 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_DUPLICATE_NODE_ID_ERROR; | |
259 | } else if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES) { | |
c8d19612 | 260 | log(LOG_ERR, "Configured tie-breaker differs in cluster. This may be " |
9a1955a7 JF |
261 | "result of server not yet accepted this node disconnect. Retry again."); |
262 | instance->disconnect_reason = | |
263 | QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_TIE_BREAKER_DIFFERS_FROM_OTHER_NODES_ERROR; | |
264 | } else if (msg->reply_error_code == TLV_REPLY_ERROR_CODE_ALGORITHM_DIFFERS_FROM_OTHER_NODES) { | |
c8d19612 | 265 | log(LOG_ERR, "Configured algorithm differs in cluster. This may be " |
9a1955a7 JF |
266 | "result of server not yet accepted this node disconnect. Retry again."); |
267 | instance->disconnect_reason = | |
268 | QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ALGORITHM_DIFFERS_FROM_OTHER_NODES_ERROR; | |
269 | } else { | |
270 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ERROR; | |
271 | } | |
272 | ||
273 | return (-1); | |
274 | } | |
275 | ||
276 | if (!msg->server_maximum_request_size_set || !msg->server_maximum_reply_size_set) { | |
c8d19612 | 277 | log(LOG_ERR, "Required maximum_request_size or maximum_reply_size " |
9a1955a7 JF |
278 | "option is unset"); |
279 | ||
280 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
281 | ||
282 | return (-1); | |
283 | } | |
284 | ||
285 | if (msg->supported_messages == NULL || msg->supported_options == NULL) { | |
c8d19612 | 286 | log(LOG_ERR, "Required supported messages or supported options " |
9a1955a7 JF |
287 | "option is unset"); |
288 | ||
289 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
290 | ||
291 | return (-1); | |
292 | } | |
293 | ||
294 | if (msg->supported_decision_algorithms == NULL) { | |
c8d19612 | 295 | log(LOG_ERR, "Required supported decision algorithms option is unset"); |
9a1955a7 JF |
296 | |
297 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
298 | ||
299 | return (-1); | |
300 | } | |
301 | ||
302 | if (msg->server_maximum_request_size < instance->advanced_settings->net_min_msg_send_size) { | |
c8d19612 | 303 | log(LOG_ERR, |
9a1955a7 JF |
304 | "Server accepts maximum %zu bytes message but this client minimum " |
305 | "is %zu bytes.", msg->server_maximum_request_size, | |
306 | instance->advanced_settings->net_min_msg_send_size); | |
307 | ||
308 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; | |
309 | return (-1); | |
310 | } | |
311 | ||
312 | if (msg->server_maximum_reply_size > instance->advanced_settings->net_max_msg_receive_size) { | |
c8d19612 | 313 | log(LOG_ERR, |
9a1955a7 JF |
314 | "Server may send message up to %zu bytes message but this client maximum " |
315 | "is %zu bytes.", msg->server_maximum_reply_size, | |
316 | instance->advanced_settings->net_max_msg_receive_size); | |
317 | ||
318 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_INCOMPATIBLE_MSG_SIZE; | |
319 | return (-1); | |
320 | } | |
321 | ||
322 | /* | |
323 | * Change buffer sizes | |
324 | */ | |
325 | dynar_set_max_size(&instance->receive_buffer, msg->server_maximum_reply_size); | |
326 | send_buffer_list_set_max_buffer_size(&instance->send_buffer_list, | |
327 | msg->server_maximum_request_size); | |
328 | ||
329 | ||
330 | /* | |
331 | * Check if server supports decision algorithm we need | |
332 | */ | |
333 | res = 0; | |
334 | ||
335 | for (zi = 0; zi < msg->no_supported_decision_algorithms && !res; zi++) { | |
336 | if (msg->supported_decision_algorithms[zi] == instance->decision_algorithm) { | |
337 | res = 1; | |
338 | } | |
339 | } | |
340 | ||
341 | if (!res) { | |
c8d19612 | 342 | log(LOG_ERR, "Server doesn't support required decision algorithm"); |
9a1955a7 JF |
343 | |
344 | instance->disconnect_reason = | |
345 | QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_ALGORITHM; | |
346 | ||
347 | return (-1); | |
348 | } | |
349 | ||
350 | /* | |
351 | * Check if server supports heuristics | |
352 | */ | |
353 | res = 0; | |
354 | for (zi = 0; zi < msg->no_supported_options; zi++) { | |
355 | if (msg->supported_options[zi] == TLV_OPT_HEURISTICS) { | |
356 | res = 1; | |
357 | } | |
358 | } | |
359 | ||
360 | instance->server_supports_heuristics = res; | |
361 | ||
362 | if (!res) { | |
363 | active_heuristics_mode = instance->qdevice_instance_ptr->heuristics_instance.mode; | |
364 | ||
365 | if (active_heuristics_mode == QDEVICE_HEURISTICS_MODE_ENABLED || | |
366 | active_heuristics_mode == QDEVICE_HEURISTICS_MODE_SYNC) { | |
c8d19612 | 367 | log(LOG_ERR, "Heuristics are enabled but not supported by server"); |
9a1955a7 JF |
368 | |
369 | instance->disconnect_reason = | |
370 | QDEVICE_NET_DISCONNECT_REASON_SERVER_DOESNT_SUPPORT_REQUIRED_OPT; | |
371 | ||
372 | return (-1); | |
373 | } | |
374 | } | |
375 | ||
376 | /* | |
377 | * Finally fully connected so it's possible to remove connection timer | |
378 | */ | |
379 | if (instance->connect_timer != NULL) { | |
380 | timer_list_delete(&instance->main_timer_list, instance->connect_timer); | |
381 | instance->connect_timer = NULL; | |
382 | } | |
383 | ||
384 | /* | |
385 | * Server accepted heartbeat interval -> schedule regular sending of echo request | |
386 | */ | |
387 | if (qdevice_net_echo_request_timer_schedule(instance) != 0) { | |
388 | return (-1); | |
389 | } | |
390 | ||
391 | /* | |
392 | * Run heuristics (even when it is disabled, undefined result is ok, rest of sending | |
393 | * is handled by qdevice_net_connect_heuristics_exec_result_callback | |
394 | */ | |
395 | if (qdevice_net_heuristics_exec_after_connect(instance) != 0) { | |
396 | return (-1); | |
397 | } | |
398 | ||
399 | return (0); | |
400 | } | |
401 | ||
402 | static int | |
403 | qdevice_net_msg_received_starttls(struct qdevice_net_instance *instance, | |
404 | const struct msg_decoded *msg) | |
405 | { | |
406 | ||
407 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "starttls")); | |
408 | } | |
409 | ||
410 | static int | |
411 | qdevice_net_msg_received_server_error(struct qdevice_net_instance *instance, | |
412 | const struct msg_decoded *msg) | |
413 | { | |
414 | ||
415 | if (!msg->reply_error_code_set) { | |
c8d19612 | 416 | log(LOG_ERR, "Received server error without error code set. " |
9a1955a7 JF |
417 | "Disconnecting from server"); |
418 | ||
419 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
420 | } else { | |
c8d19612 | 421 | log(LOG_ERR, "Received server error %"PRIu16". " |
9a1955a7 JF |
422 | "Disconnecting from server", msg->reply_error_code); |
423 | ||
424 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_SENT_ERROR; | |
425 | } | |
426 | ||
427 | return (-1); | |
428 | } | |
429 | ||
430 | static int | |
431 | qdevice_net_msg_received_set_option(struct qdevice_net_instance *instance, | |
432 | const struct msg_decoded *msg) | |
433 | { | |
434 | ||
435 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "set option")); | |
436 | } | |
437 | ||
438 | static int | |
439 | qdevice_net_msg_received_set_option_reply(struct qdevice_net_instance *instance, | |
440 | const struct msg_decoded *msg) | |
441 | { | |
442 | ||
443 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { | |
c8d19612 | 444 | log(LOG_ERR, "Received unexpected set option reply message. " |
9a1955a7 JF |
445 | "Disconnecting from server"); |
446 | ||
447 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
448 | ||
449 | return (-1); | |
450 | } | |
451 | ||
452 | if (qdevice_net_msg_check_seq_number(instance, msg) != 0) { | |
453 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
454 | ||
455 | return (-1); | |
456 | } | |
457 | ||
458 | if (qdevice_net_echo_request_timer_schedule(instance) != 0) { | |
459 | return (-1); | |
460 | } | |
461 | ||
462 | return (0); | |
463 | } | |
464 | ||
465 | static int | |
466 | qdevice_net_msg_received_echo_request(struct qdevice_net_instance *instance, | |
467 | const struct msg_decoded *msg) | |
468 | { | |
469 | ||
470 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "echo request")); | |
471 | } | |
472 | ||
473 | static int | |
474 | qdevice_net_msg_received_echo_reply(struct qdevice_net_instance *instance, | |
475 | const struct msg_decoded *msg) | |
476 | { | |
477 | ||
478 | if (!msg->seq_number_set) { | |
c8d19612 | 479 | log(LOG_ERR, "Received echo reply message doesn't contain seq_number."); |
9a1955a7 JF |
480 | |
481 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
482 | return (-1); | |
483 | } | |
484 | ||
485 | if (msg->seq_number != instance->echo_request_expected_msg_seq_num) { | |
c8d19612 | 486 | log(LOG_WARNING, "Received echo reply message seq_number is not expected one."); |
9a1955a7 JF |
487 | } |
488 | ||
489 | if (qdevice_net_algorithm_echo_reply_received(instance, msg->seq_number, | |
490 | msg->seq_number == instance->echo_request_expected_msg_seq_num) != 0) { | |
c8d19612 | 491 | log(LOG_DEBUG, "Algorithm returned error. Disconnecting"); |
9a1955a7 JF |
492 | |
493 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_ECHO_REPLY_RECEIVED_ERR; | |
494 | return (-1); | |
495 | } | |
496 | ||
497 | instance->echo_reply_received_msg_seq_num = msg->seq_number; | |
498 | instance->last_echo_reply_received_time = time(NULL); | |
499 | ||
500 | return (0); | |
501 | } | |
502 | ||
503 | static int | |
504 | qdevice_net_msg_received_node_list(struct qdevice_net_instance *instance, | |
505 | const struct msg_decoded *msg) | |
506 | { | |
507 | ||
508 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "node list")); | |
509 | } | |
510 | ||
511 | static int | |
512 | qdevice_net_msg_received_node_list_reply(struct qdevice_net_instance *instance, | |
513 | const struct msg_decoded *msg) | |
514 | { | |
515 | const char *str; | |
516 | enum tlv_vote result_vote; | |
517 | int res; | |
518 | int case_processed; | |
519 | int ring_id_is_valid; | |
520 | ||
521 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { | |
c8d19612 | 522 | log(LOG_ERR, "Received unexpected node list reply message. " |
9a1955a7 JF |
523 | "Disconnecting from server"); |
524 | ||
525 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
526 | return (-1); | |
527 | } | |
528 | ||
529 | if (!msg->vote_set || !msg->seq_number_set || !msg->node_list_type_set) { | |
c8d19612 | 530 | log(LOG_ERR, "Received node list reply message without " |
9a1955a7 JF |
531 | "required options. Disconnecting from server"); |
532 | ||
533 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
534 | return (-1); | |
535 | } | |
536 | ||
537 | if (!msg->ring_id_set) { | |
c8d19612 | 538 | log(LOG_ERR, "Received node list reply message " |
9a1955a7 JF |
539 | "without ring id set. Disconnecting from server"); |
540 | ||
541 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
542 | return (-1); | |
543 | } | |
544 | ||
545 | str = NULL; | |
546 | ||
547 | switch (msg->node_list_type) { | |
548 | case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: str = "initial config"; break; | |
549 | case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: str = "changed config"; break; | |
550 | case TLV_NODE_LIST_TYPE_MEMBERSHIP: str ="membership"; break; | |
551 | case TLV_NODE_LIST_TYPE_QUORUM: str ="quorum"; break; | |
552 | /* | |
553 | * Default is not defined intentionally. Compiler shows warning when new node list type | |
554 | * is added | |
555 | */ | |
556 | } | |
557 | ||
558 | if (str == NULL) { | |
c8d19612 | 559 | log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " |
9a1955a7 JF |
560 | "Unhandled node_list_type (debug output)"); |
561 | exit(1); | |
562 | } | |
563 | ||
c8d19612 JF |
564 | log(LOG_DEBUG, "Received %s node list reply", str); |
565 | log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); | |
566 | log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); | |
567 | log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", | |
9a1955a7 JF |
568 | msg->ring_id.node_id, msg->ring_id.seq); |
569 | ||
570 | /* | |
571 | * Call algorithm | |
572 | */ | |
573 | result_vote = msg->vote; | |
574 | ||
575 | if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { | |
576 | ring_id_is_valid = 0; | |
c8d19612 | 577 | log(LOG_DEBUG, "Received node list reply with old ring id."); |
9a1955a7 JF |
578 | } else { |
579 | ring_id_is_valid = 1; | |
580 | } | |
581 | ||
582 | case_processed = 0; | |
583 | switch (msg->node_list_type) { | |
584 | case TLV_NODE_LIST_TYPE_INITIAL_CONFIG: | |
585 | case TLV_NODE_LIST_TYPE_CHANGED_CONFIG: | |
586 | case_processed = 1; | |
587 | res = qdevice_net_algorithm_config_node_list_reply_received(instance, | |
588 | msg->seq_number, (msg->node_list_type == TLV_NODE_LIST_TYPE_INITIAL_CONFIG), | |
589 | &msg->ring_id, ring_id_is_valid, &result_vote); | |
590 | break; | |
591 | case TLV_NODE_LIST_TYPE_MEMBERSHIP: | |
592 | case_processed = 1; | |
593 | res = qdevice_net_algorithm_membership_node_list_reply_received(instance, | |
594 | msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote); | |
595 | break; | |
596 | case TLV_NODE_LIST_TYPE_QUORUM: | |
597 | case_processed = 1; | |
598 | res = qdevice_net_algorithm_quorum_node_list_reply_received(instance, | |
599 | msg->seq_number, &msg->ring_id, ring_id_is_valid, &result_vote); | |
600 | break; | |
601 | /* | |
602 | * Default is not defined intentionally. Compiler shows warning when new node list type | |
603 | * is added | |
604 | */ | |
605 | } | |
606 | ||
607 | if (!case_processed) { | |
c8d19612 | 608 | log(LOG_CRIT, "qdevice_net_msg_received_node_list_reply fatal error. " |
9a1955a7 JF |
609 | "Unhandled node_list_type (algorithm call)"); |
610 | exit(1); | |
611 | } | |
612 | ||
613 | if (res != 0) { | |
c8d19612 | 614 | log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); |
9a1955a7 JF |
615 | |
616 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_NODE_LIST_REPLY_ERR; | |
617 | return (-1); | |
618 | } else { | |
c8d19612 | 619 | log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); |
9a1955a7 JF |
620 | } |
621 | ||
622 | if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { | |
623 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; | |
624 | return (-1); | |
625 | } | |
626 | ||
627 | return (0); | |
628 | } | |
629 | ||
630 | static int | |
631 | qdevice_net_msg_received_ask_for_vote(struct qdevice_net_instance *instance, | |
632 | const struct msg_decoded *msg) | |
633 | { | |
634 | ||
635 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "ask for vote")); | |
636 | } | |
637 | ||
638 | static int | |
639 | qdevice_net_msg_received_ask_for_vote_reply(struct qdevice_net_instance *instance, | |
640 | const struct msg_decoded *msg) | |
641 | { | |
642 | enum tlv_vote result_vote; | |
643 | int ring_id_is_valid; | |
644 | ||
645 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { | |
c8d19612 | 646 | log(LOG_ERR, "Received unexpected ask for vote reply message. " |
9a1955a7 JF |
647 | "Disconnecting from server"); |
648 | ||
649 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
650 | return (-1); | |
651 | } | |
652 | ||
653 | if (!msg->vote_set || !msg->seq_number_set || !msg->ring_id_set) { | |
c8d19612 | 654 | log(LOG_ERR, "Received ask for vote reply message without " |
9a1955a7 JF |
655 | "required options. Disconnecting from server"); |
656 | ||
657 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
658 | return (-1); | |
659 | } | |
660 | ||
c8d19612 JF |
661 | log(LOG_DEBUG, "Received ask for vote reply"); |
662 | log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); | |
663 | log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); | |
664 | log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", | |
9a1955a7 JF |
665 | msg->ring_id.node_id, msg->ring_id.seq); |
666 | ||
667 | result_vote = msg->vote; | |
668 | ||
669 | if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { | |
670 | ring_id_is_valid = 0; | |
c8d19612 | 671 | log(LOG_DEBUG, "Received ask for vote reply with old ring id."); |
9a1955a7 JF |
672 | } else { |
673 | ring_id_is_valid = 1; | |
674 | } | |
675 | ||
676 | if (qdevice_net_algorithm_ask_for_vote_reply_received(instance, msg->seq_number, | |
677 | &msg->ring_id, ring_id_is_valid, &result_vote) != 0) { | |
c8d19612 | 678 | log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); |
9a1955a7 JF |
679 | |
680 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_ASK_FOR_VOTE_REPLY_ERR; | |
681 | return (-1); | |
682 | } else { | |
c8d19612 | 683 | log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); |
9a1955a7 JF |
684 | } |
685 | ||
686 | if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { | |
687 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; | |
688 | return (-1); | |
689 | } | |
690 | ||
691 | return (0); | |
692 | } | |
693 | ||
694 | static int | |
695 | qdevice_net_msg_received_vote_info(struct qdevice_net_instance *instance, | |
696 | const struct msg_decoded *msg) | |
697 | { | |
698 | struct send_buffer_list_entry *send_buffer; | |
699 | enum tlv_vote result_vote; | |
700 | int ring_id_is_valid; | |
701 | ||
702 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { | |
c8d19612 | 703 | log(LOG_ERR, "Received unexpected vote info message. " |
9a1955a7 JF |
704 | "Disconnecting from server"); |
705 | ||
706 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
707 | return (-1); | |
708 | } | |
709 | ||
710 | if (!msg->vote_set || !msg->seq_number_set || !msg->ring_id_set) { | |
c8d19612 | 711 | log(LOG_ERR, "Received node list reply message without " |
9a1955a7 JF |
712 | "required options. Disconnecting from server"); |
713 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
714 | return (-1); | |
715 | } | |
716 | ||
c8d19612 JF |
717 | log(LOG_DEBUG, "Received vote info"); |
718 | log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); | |
719 | log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); | |
720 | log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", | |
9a1955a7 JF |
721 | msg->ring_id.node_id, msg->ring_id.seq); |
722 | ||
723 | result_vote = msg->vote; | |
724 | ||
725 | if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { | |
726 | ring_id_is_valid = 0; | |
c8d19612 | 727 | log(LOG_DEBUG, "Received vote info with old ring id."); |
9a1955a7 JF |
728 | } else { |
729 | ring_id_is_valid = 1; | |
730 | } | |
731 | ||
732 | if (qdevice_net_algorithm_vote_info_received(instance, msg->seq_number, | |
733 | &msg->ring_id, ring_id_is_valid, &result_vote) != 0) { | |
c8d19612 | 734 | log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); |
9a1955a7 JF |
735 | |
736 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_VOTE_INFO_ERR; | |
737 | return (-1); | |
738 | } else { | |
c8d19612 | 739 | log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); |
9a1955a7 JF |
740 | } |
741 | ||
742 | if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { | |
743 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; | |
744 | return (-1); | |
745 | } | |
746 | ||
747 | /* | |
748 | * Create reply message | |
749 | */ | |
750 | send_buffer = send_buffer_list_get_new(&instance->send_buffer_list); | |
751 | if (send_buffer == NULL) { | |
c8d19612 | 752 | log(LOG_ERR, "Can't allocate send list buffer for " |
9a1955a7 JF |
753 | "vote info reply msg"); |
754 | ||
755 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; | |
756 | return (-1); | |
757 | } | |
758 | ||
759 | if (msg_create_vote_info_reply(&send_buffer->buffer, msg->seq_number) == 0) { | |
c8d19612 | 760 | log(LOG_ERR, "Can't allocate send buffer for " |
9a1955a7 JF |
761 | "vote info reply list msg"); |
762 | ||
763 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER; | |
764 | send_buffer_list_discard_new(&instance->send_buffer_list, send_buffer); | |
765 | return (-1); | |
766 | } | |
767 | ||
768 | send_buffer_list_put(&instance->send_buffer_list, send_buffer); | |
769 | ||
770 | return (0); | |
771 | } | |
772 | ||
773 | static int | |
774 | qdevice_net_msg_received_vote_info_reply(struct qdevice_net_instance *instance, | |
775 | const struct msg_decoded *msg) | |
776 | { | |
777 | ||
778 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "vote info reply")); | |
779 | } | |
780 | ||
781 | static int | |
782 | qdevice_net_msg_received_heuristics_change(struct qdevice_net_instance *instance, | |
783 | const struct msg_decoded *msg) | |
784 | { | |
785 | ||
786 | return (qdevice_net_msg_received_unexpected_msg(instance, msg, "heuristics change")); | |
787 | } | |
788 | ||
789 | static int | |
790 | qdevice_net_msg_received_heuristics_change_reply(struct qdevice_net_instance *instance, | |
791 | const struct msg_decoded *msg) | |
792 | { | |
793 | enum tlv_vote result_vote; | |
794 | int ring_id_is_valid; | |
795 | ||
796 | if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_VOTEQUORUM_CMAP_EVENTS) { | |
c8d19612 | 797 | log(LOG_ERR, "Received unexpected heuristics change reply message. " |
9a1955a7 JF |
798 | "Disconnecting from server"); |
799 | ||
800 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
801 | return (-1); | |
802 | } | |
803 | ||
804 | if (!msg->vote_set || !msg->seq_number_set || !msg->ring_id_set || | |
805 | msg->heuristics == TLV_HEURISTICS_UNDEFINED) { | |
c8d19612 | 806 | log(LOG_ERR, "Received heuristics change reply message without " |
9a1955a7 JF |
807 | "required options. Disconnecting from server"); |
808 | ||
809 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_REQUIRED_OPTION_MISSING; | |
810 | return (-1); | |
811 | } | |
812 | ||
c8d19612 JF |
813 | log(LOG_DEBUG, "Received heuristics change reply"); |
814 | log(LOG_DEBUG, " seq = "UTILS_PRI_MSG_SEQ, msg->seq_number); | |
815 | log(LOG_DEBUG, " vote = %s", tlv_vote_to_str(msg->vote)); | |
816 | log(LOG_DEBUG, " ring id = ("UTILS_PRI_RING_ID")", | |
9a1955a7 | 817 | msg->ring_id.node_id, msg->ring_id.seq); |
c8d19612 | 818 | log(LOG_DEBUG, " heuristics = %s", tlv_heuristics_to_str(msg->heuristics)); |
9a1955a7 JF |
819 | |
820 | result_vote = msg->vote; | |
821 | ||
822 | if (!tlv_ring_id_eq(&msg->ring_id, &instance->last_sent_ring_id)) { | |
823 | ring_id_is_valid = 0; | |
c8d19612 | 824 | log(LOG_DEBUG, "Received heuristics change reply with old ring id."); |
9a1955a7 JF |
825 | } else { |
826 | ring_id_is_valid = 1; | |
827 | } | |
828 | ||
829 | if (qdevice_net_algorithm_heuristics_change_reply_received(instance, msg->seq_number, | |
830 | &msg->ring_id, ring_id_is_valid, msg->heuristics, &result_vote) != 0) { | |
c8d19612 | 831 | log(LOG_DEBUG, "Algorithm returned error. Disconnecting."); |
9a1955a7 JF |
832 | |
833 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_ALGO_HEURISTICS_CHANGE_REPLY_ERR; | |
834 | return (-1); | |
835 | } else { | |
c8d19612 | 836 | log(LOG_DEBUG, "Algorithm result vote is %s", tlv_vote_to_str(result_vote)); |
9a1955a7 JF |
837 | } |
838 | ||
839 | if (qdevice_net_cast_vote_timer_update(instance, result_vote) != 0) { | |
840 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_SCHEDULE_VOTING_TIMER; | |
841 | return (-1); | |
842 | } | |
843 | ||
844 | return (0); | |
845 | } | |
846 | ||
847 | int | |
848 | qdevice_net_msg_received(struct qdevice_net_instance *instance) | |
849 | { | |
850 | struct msg_decoded msg; | |
851 | int res; | |
852 | int ret_val; | |
853 | int msg_processed; | |
854 | ||
855 | msg_decoded_init(&msg); | |
856 | ||
857 | res = msg_decode(&instance->receive_buffer, &msg); | |
858 | if (res != 0) { | |
859 | /* | |
860 | * Error occurred. Disconnect. | |
861 | */ | |
fed67019 | 862 | log_common_msg_decode_error(res); |
c8d19612 | 863 | log(LOG_ERR, "Disconnecting from server"); |
9a1955a7 JF |
864 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_MSG_DECODE_ERROR; |
865 | ||
866 | return (-1); | |
867 | } | |
868 | ||
869 | ret_val = 0; | |
870 | ||
871 | msg_processed = 0; | |
872 | ||
873 | switch (msg.type) { | |
874 | case MSG_TYPE_INIT: | |
875 | msg_processed = 1; | |
876 | ret_val = qdevice_net_msg_received_init(instance, &msg); | |
877 | break; | |
878 | case MSG_TYPE_PREINIT: | |
879 | msg_processed = 1; | |
880 | ret_val = qdevice_net_msg_received_preinit(instance, &msg); | |
881 | break; | |
882 | case MSG_TYPE_PREINIT_REPLY: | |
883 | msg_processed = 1; | |
884 | ret_val = qdevice_net_msg_received_preinit_reply(instance, &msg); | |
885 | break; | |
886 | case MSG_TYPE_STARTTLS: | |
887 | msg_processed = 1; | |
888 | ret_val = qdevice_net_msg_received_starttls(instance, &msg); | |
889 | break; | |
890 | case MSG_TYPE_SERVER_ERROR: | |
891 | msg_processed = 1; | |
892 | ret_val = qdevice_net_msg_received_server_error(instance, &msg); | |
893 | break; | |
894 | case MSG_TYPE_INIT_REPLY: | |
895 | msg_processed = 1; | |
896 | ret_val = qdevice_net_msg_received_init_reply(instance, &msg); | |
897 | break; | |
898 | case MSG_TYPE_SET_OPTION: | |
899 | msg_processed = 1; | |
900 | ret_val = qdevice_net_msg_received_set_option(instance, &msg); | |
901 | break; | |
902 | case MSG_TYPE_SET_OPTION_REPLY: | |
903 | msg_processed = 1; | |
904 | ret_val = qdevice_net_msg_received_set_option_reply(instance, &msg); | |
905 | break; | |
906 | case MSG_TYPE_ECHO_REQUEST: | |
907 | msg_processed = 1; | |
908 | ret_val = qdevice_net_msg_received_echo_request(instance, &msg); | |
909 | break; | |
910 | case MSG_TYPE_ECHO_REPLY: | |
911 | msg_processed = 1; | |
912 | ret_val = qdevice_net_msg_received_echo_reply(instance, &msg); | |
913 | break; | |
914 | case MSG_TYPE_NODE_LIST: | |
915 | msg_processed = 1; | |
916 | ret_val = qdevice_net_msg_received_node_list(instance, &msg); | |
917 | break; | |
918 | case MSG_TYPE_NODE_LIST_REPLY: | |
919 | msg_processed = 1; | |
920 | ret_val = qdevice_net_msg_received_node_list_reply(instance, &msg); | |
921 | break; | |
922 | case MSG_TYPE_ASK_FOR_VOTE: | |
923 | msg_processed = 1; | |
924 | ret_val = qdevice_net_msg_received_ask_for_vote(instance, &msg); | |
925 | break; | |
926 | case MSG_TYPE_ASK_FOR_VOTE_REPLY: | |
927 | msg_processed = 1; | |
928 | ret_val = qdevice_net_msg_received_ask_for_vote_reply(instance, &msg); | |
929 | break; | |
930 | case MSG_TYPE_VOTE_INFO: | |
931 | msg_processed = 1; | |
932 | ret_val = qdevice_net_msg_received_vote_info(instance, &msg); | |
933 | break; | |
934 | case MSG_TYPE_VOTE_INFO_REPLY: | |
935 | msg_processed = 1; | |
936 | ret_val = qdevice_net_msg_received_vote_info_reply(instance, &msg); | |
937 | break; | |
938 | case MSG_TYPE_HEURISTICS_CHANGE: | |
939 | msg_processed = 1; | |
940 | ret_val = qdevice_net_msg_received_heuristics_change(instance, &msg); | |
941 | break; | |
942 | case MSG_TYPE_HEURISTICS_CHANGE_REPLY: | |
943 | msg_processed = 1; | |
944 | ret_val = qdevice_net_msg_received_heuristics_change_reply(instance, &msg); | |
945 | /* | |
946 | * Default is not defined intentionally. Compiler shows warning when msg type is added | |
947 | */ | |
948 | } | |
949 | ||
950 | if (!msg_processed) { | |
c8d19612 | 951 | log(LOG_ERR, "Received unsupported message %u. " |
9a1955a7 JF |
952 | "Disconnecting from server", msg.type); |
953 | instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_UNEXPECTED_MSG; | |
954 | ||
955 | ret_val = -1; | |
956 | } | |
957 | ||
958 | msg_decoded_destroy(&msg); | |
959 | ||
960 | return (ret_val); | |
961 | } |