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