]> git.proxmox.com Git - mirror_corosync-qdevice.git/blame - qdevices/qdevice-net-msg-received.c
qdevice: Merge msg_decode_error functions
[mirror_corosync-qdevice.git] / qdevices / qdevice-net-msg-received.c
CommitLineData
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 */
52static int
53qdevice_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
87static int
88qdevice_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
100static int
101qdevice_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
108static int
109qdevice_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
116static int
117qdevice_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
131static int
132qdevice_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
217static int
218qdevice_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
402static int
403qdevice_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
410static int
411qdevice_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
430static int
431qdevice_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
438static int
439qdevice_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
465static int
466qdevice_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
473static int
474qdevice_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
503static int
504qdevice_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
511static int
512qdevice_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
630static int
631qdevice_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
638static int
639qdevice_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
694static int
695qdevice_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
773static int
774qdevice_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
781static int
782qdevice_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
789static int
790qdevice_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
847int
848qdevice_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}