1 /*
2 * vi: set autoindent tabstop=4 shiftwidth=4 :
3 *
4 * Copyright (c) 2006-2015 Red Hat, Inc.
5 *
6 * All rights reserved.
7 *
8 * Author: Christine Caulfield (ccaulfi@redhat.com)
9 * Author: Jan Friesse (jfriesse@redhat.com)
10 *
11 * This software licensed under BSD license, the text of which follows:
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions are met:
15 *
16 * - Redistributions of source code must retain the above copyright notice,
17 * this list of conditions and the following disclaimer.
18 * - Redistributions in binary form must reproduce the above copyright notice,
19 * this list of conditions and the following disclaimer in the documentation
20 * and/or other materials provided with the distribution.
21 * - Neither the name of the MontaVista Software, Inc. nor the names of its
22 * contributors may be used to endorse or promote products derived from this
23 * software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 /*
38 * Provides a closed process group API using the coroipcc executive
39 */
40
41 #include <config.h>
42
43 #include <stdlib.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <unistd.h>
47 #include <sys/types.h>
48 #include <sys/socket.h>
49 #include <sys/mman.h>
50 #include <sys/uio.h>
51 #include <sys/stat.h>
52 #include <errno.h>
53 #include <limits.h>
54
55 #include <qb/qblist.h>
56 #include <qb/qbdefs.h>
57 #include <qb/qbipcc.h>
58 #include <qb/qblog.h>
59
60 #include <corosync/hdb.h>
61 #include <corosync/corotypes.h>
62 #include <corosync/corodefs.h>
63 #include <corosync/cpg.h>
64 #include <corosync/ipc_cpg.h>
65
66 #include "util.h"
67
68 #ifndef MAP_ANONYMOUS
69 #define MAP_ANONYMOUS MAP_ANON
70 #endif
71
72 /*
73 * Maximum number of times to retry a send when transmitting
74 * a large message fragment
75 */
76 #define MAX_RETRIES 100
77
78 struct cpg_assembly_data
79 {
80 struct qb_list_head list;
81 uint32_t nodeid;
82 uint32_t pid;
83 char *assembly_buf;
84 uint32_t assembly_buf_ptr;
85 };
86
87 struct cpg_inst {
88 qb_ipcc_connection_t *c;
89 int finalize;
90 void *context;
91 union {
92 cpg_model_data_t model_data;
93 cpg_model_v1_data_t model_v1_data;
94 };
95 struct qb_list_head iteration_list_head;
96 uint32_t max_msg_size;
97 struct qb_list_head assembly_list_head;
98 };
99 static void cpg_inst_free (void *inst);
100
101 DECLARE_HDB_DATABASE(cpg_handle_t_db, cpg_inst_free);
102
103 struct cpg_iteration_instance_t {
104 cpg_iteration_handle_t cpg_iteration_handle;
105 qb_ipcc_connection_t *conn;
106 hdb_handle_t executive_iteration_handle;
107 struct qb_list_head list;
108 };
109
110 DECLARE_HDB_DATABASE(cpg_iteration_handle_t_db,NULL);
111
112
113 /*
114 * Internal (not visible by API) functions
115 */
116
117 static cs_error_t
118 coroipcc_msg_send_reply_receive (
119 qb_ipcc_connection_t *c,
120 const struct iovec *iov,
121 unsigned int iov_len,
122 void *res_msg,
123 size_t res_len)
124 {
125 return qb_to_cs_error(qb_ipcc_sendv_recv(c, iov, iov_len, res_msg, res_len,
126 CS_IPC_TIMEOUT_MS));
127 }
128
129 static void cpg_iteration_instance_finalize (struct cpg_iteration_instance_t *cpg_iteration_instance)
130 {
131 qb_list_del (&cpg_iteration_instance->list);
132 hdb_handle_destroy (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
133 }
134
135 static void cpg_inst_free (void *inst)
136 {
137 struct cpg_inst *cpg_inst = (struct cpg_inst *)inst;
138 qb_ipcc_disconnect(cpg_inst->c);
139 }
140
141 static void cpg_inst_finalize (struct cpg_inst *cpg_inst, hdb_handle_t handle)
142 {
143 struct qb_list_head *iter, *tmp_iter;
144 struct cpg_iteration_instance_t *cpg_iteration_instance;
145
146 /*
147 * Traverse thru iteration instances and delete them
148 */
149 qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->iteration_list_head)) {
150 cpg_iteration_instance = qb_list_entry (iter, struct cpg_iteration_instance_t, list);
151
152 cpg_iteration_instance_finalize (cpg_iteration_instance);
153 }
154 hdb_handle_destroy (&cpg_handle_t_db, handle);
155 }
156
157 /**
158 * @defgroup cpg_coroipcc The closed process group API
159 * @ingroup coroipcc
160 *
161 * @{
162 */
163
164 cs_error_t cpg_initialize (
165 cpg_handle_t *handle,
166 cpg_callbacks_t *callbacks)
167 {
168 cpg_model_v1_data_t model_v1_data;
169
170 memset (&model_v1_data, 0, sizeof (cpg_model_v1_data_t));
171
172 if (callbacks) {
173 model_v1_data.cpg_deliver_fn = callbacks->cpg_deliver_fn;
174 model_v1_data.cpg_confchg_fn = callbacks->cpg_confchg_fn;
175 }
176
177 return (cpg_model_initialize (handle, CPG_MODEL_V1, (cpg_model_data_t *)&model_v1_data, NULL));
178 }
179
180 cs_error_t cpg_model_initialize (
181 cpg_handle_t *handle,
182 cpg_model_t model,
183 cpg_model_data_t *model_data,
184 void *context)
185 {
186 cs_error_t error;
187 struct cpg_inst *cpg_inst;
188
189 if (model != CPG_MODEL_V1) {
190 error = CS_ERR_INVALID_PARAM;
191 goto error_no_destroy;
192 }
193
194 error = hdb_error_to_cs (hdb_handle_create (&cpg_handle_t_db, sizeof (struct cpg_inst), handle));
195 if (error != CS_OK) {
196 goto error_no_destroy;
197 }
198
199 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, *handle, (void *)&cpg_inst));
200 if (error != CS_OK) {
201 goto error_destroy;
202 }
203
204 cpg_inst->c = qb_ipcc_connect ("cpg", IPC_REQUEST_SIZE);
205 if (cpg_inst->c == NULL) {
206 error = qb_to_cs_error(-errno);
207 goto error_put_destroy;
208 }
209
210 if (model_data != NULL) {
211 switch (model) {
212 case CPG_MODEL_V1:
213 memcpy (&cpg_inst->model_v1_data, model_data, sizeof (cpg_model_v1_data_t));
214 if ((cpg_inst->model_v1_data.flags & ~(CPG_MODEL_V1_DELIVER_INITIAL_TOTEM_CONF)) != 0) {
215 error = CS_ERR_INVALID_PARAM;
216
217 goto error_destroy;
218 }
219 break;
220 }
221 }
222
223 /* Allow space for corosync internal headers */
224 cpg_inst->max_msg_size = IPC_REQUEST_SIZE - 1024;
225 cpg_inst->model_data.model = model;
226 cpg_inst->context = context;
227
228 qb_list_init(&cpg_inst->iteration_list_head);
229
230 qb_list_init(&cpg_inst->assembly_list_head);
231
232 hdb_handle_put (&cpg_handle_t_db, *handle);
233
234 return (CS_OK);
235
236 error_put_destroy:
237 hdb_handle_put (&cpg_handle_t_db, *handle);
238 error_destroy:
239 hdb_handle_destroy (&cpg_handle_t_db, *handle);
240 error_no_destroy:
241 return (error);
242 }
243
244 cs_error_t cpg_finalize (
245 cpg_handle_t handle)
246 {
247 struct cpg_inst *cpg_inst;
248 struct iovec iov;
249 struct req_lib_cpg_finalize req_lib_cpg_finalize;
250 struct res_lib_cpg_finalize res_lib_cpg_finalize;
251 cs_error_t error;
252
253 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
254 if (error != CS_OK) {
255 return (error);
256 }
257
258 /*
259 * Another thread has already started finalizing
260 */
261 if (cpg_inst->finalize) {
262 hdb_handle_put (&cpg_handle_t_db, handle);
263 return (CS_ERR_BAD_HANDLE);
264 }
265
266 cpg_inst->finalize = 1;
267
268 /*
269 * Send service request
270 */
271 req_lib_cpg_finalize.header.size = sizeof (struct req_lib_cpg_finalize);
272 req_lib_cpg_finalize.header.id = MESSAGE_REQ_CPG_FINALIZE;
273
274 iov.iov_base = (void *)&req_lib_cpg_finalize;
275 iov.iov_len = sizeof (struct req_lib_cpg_finalize);
276
277 error = coroipcc_msg_send_reply_receive (cpg_inst->c,
278 &iov,
279 1,
280 &res_lib_cpg_finalize,
281 sizeof (struct res_lib_cpg_finalize));
282
283 cpg_inst_finalize (cpg_inst, handle);
284 hdb_handle_put (&cpg_handle_t_db, handle);
285
286 return (error);
287 }
288
289 cs_error_t cpg_fd_get (
290 cpg_handle_t handle,
291 int *fd)
292 {
293 cs_error_t error;
294 struct cpg_inst *cpg_inst;
295
296 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
297 if (error != CS_OK) {
298 return (error);
299 }
300
301 error = qb_to_cs_error (qb_ipcc_fd_get (cpg_inst->c, fd));
302
303 hdb_handle_put (&cpg_handle_t_db, handle);
304
305 return (error);
306 }
307
308 cs_error_t cpg_max_atomic_msgsize_get (
309 cpg_handle_t handle,
310 uint32_t *size)
311 {
312 cs_error_t error;
313 struct cpg_inst *cpg_inst;
314
315 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
316 if (error != CS_OK) {
317 return (error);
318 }
319
320 *size = cpg_inst->max_msg_size;
321
322 hdb_handle_put (&cpg_handle_t_db, handle);
323
324 return (error);
325 }
326
327 cs_error_t cpg_context_get (
328 cpg_handle_t handle,
329 void **context)
330 {
331 cs_error_t error;
332 struct cpg_inst *cpg_inst;
333
334 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
335 if (error != CS_OK) {
336 return (error);
337 }
338
339 *context = cpg_inst->context;
340
341 hdb_handle_put (&cpg_handle_t_db, handle);
342
343 return (CS_OK);
344 }
345
346 cs_error_t cpg_context_set (
347 cpg_handle_t handle,
348 void *context)
349 {
350 cs_error_t error;
351 struct cpg_inst *cpg_inst;
352
353 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
354 if (error != CS_OK) {
355 return (error);
356 }
357
358 cpg_inst->context = context;
359
360 hdb_handle_put (&cpg_handle_t_db, handle);
361
362 return (CS_OK);
363 }
364
365 cs_error_t cpg_dispatch (
366 cpg_handle_t handle,
367 cs_dispatch_flags_t dispatch_types)
368 {
369 int timeout = -1;
370 cs_error_t error;
371 int cont = 1; /* always continue do loop except when set to 0 */
372 struct cpg_inst *cpg_inst;
373 struct res_lib_cpg_confchg_callback *res_cpg_confchg_callback;
374 struct res_lib_cpg_deliver_callback *res_cpg_deliver_callback;
375 struct res_lib_cpg_partial_deliver_callback *res_cpg_partial_deliver_callback;
376 struct res_lib_cpg_totem_confchg_callback *res_cpg_totem_confchg_callback;
377 struct cpg_inst cpg_inst_copy;
378 struct qb_ipc_response_header *dispatch_data;
379 struct cpg_address member_list[CPG_MEMBERS_MAX];
380 struct cpg_address left_list[CPG_MEMBERS_MAX];
381 struct cpg_address joined_list[CPG_MEMBERS_MAX];
382 struct cpg_name group_name;
383 struct cpg_assembly_data *assembly_data;
384 struct qb_list_head *iter, *tmp_iter;
385 mar_cpg_address_t *left_list_start;
386 mar_cpg_address_t *joined_list_start;
387 unsigned int i;
388 struct cpg_ring_id ring_id;
389 uint32_t totem_member_list[CPG_MEMBERS_MAX];
390 int32_t errno_res;
391 char dispatch_buf[IPC_DISPATCH_SIZE];
392
393 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
394 if (error != CS_OK) {
395 return (error);
396 }
397
398 /*
399 * Timeout instantly for CS_DISPATCH_ONE_NONBLOCKING or CS_DISPATCH_ALL and
400 * wait indefinitely for CS_DISPATCH_ONE or CS_DISPATCH_BLOCKING
401 */
402 if (dispatch_types == CS_DISPATCH_ALL || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
403 timeout = 0;
404 }
405
406 dispatch_data = (struct qb_ipc_response_header *)dispatch_buf;
407 do {
408 errno_res = qb_ipcc_event_recv (
409 cpg_inst->c,
410 dispatch_buf,
411 IPC_DISPATCH_SIZE,
412 timeout);
413 error = qb_to_cs_error (errno_res);
414 if (error == CS_ERR_BAD_HANDLE) {
415 error = CS_OK;
416 goto error_put;
417 }
418 if (error == CS_ERR_TRY_AGAIN) {
419 if (dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
420 /*
421 * Don't mask error
422 */
423 goto error_put;
424 }
425 error = CS_OK;
426 if (dispatch_types == CS_DISPATCH_ALL) {
427 break; /* exit do while cont is 1 loop */
428 } else {
429 continue; /* next poll */
430 }
431 }
432 if (error != CS_OK) {
433 goto error_put;
434 }
435
436 /*
437 * Make copy of callbacks, message data, unlock instance, and call callback
438 * A risk of this dispatch method is that the callback routines may
439 * operate at the same time that cpgFinalize has been called.
440 */
441 memcpy (&cpg_inst_copy, cpg_inst, sizeof (struct cpg_inst));
442 switch (cpg_inst_copy.model_data.model) {
443 case CPG_MODEL_V1:
444 /*
445 * Dispatch incoming message
446 */
447 switch (dispatch_data->id) {
448 case MESSAGE_RES_CPG_DELIVER_CALLBACK:
449 if (cpg_inst_copy.model_v1_data.cpg_deliver_fn == NULL) {
450 break;
451 }
452
453 res_cpg_deliver_callback = (struct res_lib_cpg_deliver_callback *)dispatch_data;
454
455 marshall_from_mar_cpg_name_t (
456 &group_name,
457 &res_cpg_deliver_callback->group_name);
458
459 cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle,
460 &group_name,
461 res_cpg_deliver_callback->nodeid,
462 res_cpg_deliver_callback->pid,
463 &res_cpg_deliver_callback->message,
464 res_cpg_deliver_callback->msglen);
465 break;
466
467 case MESSAGE_RES_CPG_PARTIAL_DELIVER_CALLBACK:
468 res_cpg_partial_deliver_callback = (struct res_lib_cpg_partial_deliver_callback *)dispatch_data;
469
470 marshall_from_mar_cpg_name_t (
471 &group_name,
472 &res_cpg_partial_deliver_callback->group_name);
473
474 /*
475 * Search for assembly data for current messages (nodeid, pid) pair in list of assemblies
476 */
477 assembly_data = NULL;
478 qb_list_for_each(iter, &(cpg_inst->assembly_list_head)) {
479 struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list);
480 if (current_assembly_data->nodeid == res_cpg_partial_deliver_callback->nodeid && current_assembly_data->pid == res_cpg_partial_deliver_callback->pid) {
481 assembly_data = current_assembly_data;
482 break;
483 }
484 }
485
486 if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_FIRST) {
487
488 /*
489 * As this is LIBCPG_PARTIAL_FIRST packet, check that there is no ongoing assembly.
490 * Otherwise the sending of packet must have been interrupted and error should have
491 * been reported to sending client. Therefore here last assembly will be dropped.
492 */
493 if (assembly_data) {
494 qb_list_del (&assembly_data->list);
495 free(assembly_data->assembly_buf);
496 free(assembly_data);
497 // coverity[UNUSED_VALUE:SUPPRESS] defensive programming
498 assembly_data = NULL;
499 }
500
501 assembly_data = malloc(sizeof(struct cpg_assembly_data));
502 if (!assembly_data) {
503 error = CS_ERR_NO_MEMORY;
504 goto error_put;
505 }
506
507 assembly_data->nodeid = res_cpg_partial_deliver_callback->nodeid;
508 assembly_data->pid = res_cpg_partial_deliver_callback->pid;
509 assembly_data->assembly_buf = malloc(res_cpg_partial_deliver_callback->msglen);
510 if (!assembly_data->assembly_buf) {
511 free(assembly_data);
512 error = CS_ERR_NO_MEMORY;
513 goto error_put;
514 }
515 assembly_data->assembly_buf_ptr = 0;
516 qb_list_init (&assembly_data->list);
517
518 qb_list_add (&assembly_data->list, &cpg_inst->assembly_list_head);
519 }
520 if (assembly_data) {
521 memcpy(assembly_data->assembly_buf + assembly_data->assembly_buf_ptr,
522 res_cpg_partial_deliver_callback->message, res_cpg_partial_deliver_callback->fraglen);
523 assembly_data->assembly_buf_ptr += res_cpg_partial_deliver_callback->fraglen;
524
525 if (res_cpg_partial_deliver_callback->type == LIBCPG_PARTIAL_LAST) {
526 if (cpg_inst_copy.model_v1_data.cpg_deliver_fn != NULL) {
527 cpg_inst_copy.model_v1_data.cpg_deliver_fn (handle,
528 &group_name,
529 res_cpg_partial_deliver_callback->nodeid,
530 res_cpg_partial_deliver_callback->pid,
531 assembly_data->assembly_buf,
532 res_cpg_partial_deliver_callback->msglen);
533 }
534
535 qb_list_del (&assembly_data->list);
536 free(assembly_data->assembly_buf);
537 free(assembly_data);
538 }
539 }
540 break;
541
542 case MESSAGE_RES_CPG_CONFCHG_CALLBACK:
543 if (cpg_inst_copy.model_v1_data.cpg_confchg_fn == NULL) {
544 break;
545 }
546
547 res_cpg_confchg_callback = (struct res_lib_cpg_confchg_callback *)dispatch_data;
548
549 for (i = 0; i < res_cpg_confchg_callback->member_list_entries; i++) {
550 marshall_from_mar_cpg_address_t (&member_list[i],
551 &res_cpg_confchg_callback->member_list[i]);
552 }
553 left_list_start = res_cpg_confchg_callback->member_list +
554 res_cpg_confchg_callback->member_list_entries;
555 for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) {
556 marshall_from_mar_cpg_address_t (&left_list[i],
557 &left_list_start[i]);
558 }
559 joined_list_start = res_cpg_confchg_callback->member_list +
560 res_cpg_confchg_callback->member_list_entries +
561 res_cpg_confchg_callback->left_list_entries;
562 for (i = 0; i < res_cpg_confchg_callback->joined_list_entries; i++) {
563 marshall_from_mar_cpg_address_t (&joined_list[i],
564 &joined_list_start[i]);
565 }
566 marshall_from_mar_cpg_name_t (
567 &group_name,
568 &res_cpg_confchg_callback->group_name);
569
570 cpg_inst_copy.model_v1_data.cpg_confchg_fn (handle,
571 &group_name,
572 member_list,
573 res_cpg_confchg_callback->member_list_entries,
574 left_list,
575 res_cpg_confchg_callback->left_list_entries,
576 joined_list,
577 res_cpg_confchg_callback->joined_list_entries);
578
579 /*
580 * If member left while his partial packet was being assembled, assembly data must be removed from list
581 */
582 for (i = 0; i < res_cpg_confchg_callback->left_list_entries; i++) {
583 qb_list_for_each_safe(iter, tmp_iter, &(cpg_inst->assembly_list_head)) {
584 struct cpg_assembly_data *current_assembly_data = qb_list_entry (iter, struct cpg_assembly_data, list);
585 if (current_assembly_data->nodeid != left_list[i].nodeid || current_assembly_data->pid != left_list[i].pid)
586 continue;
587
588 qb_list_del (¤t_assembly_data->list);
589 free(current_assembly_data->assembly_buf);
590 free(current_assembly_data);
591 }
592 }
593
594 break;
595 case MESSAGE_RES_CPG_TOTEM_CONFCHG_CALLBACK:
596 if (cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn == NULL) {
597 break;
598 }
599
600 res_cpg_totem_confchg_callback = (struct res_lib_cpg_totem_confchg_callback *)dispatch_data;
601
602 marshall_from_mar_cpg_ring_id_t (&ring_id, &res_cpg_totem_confchg_callback->ring_id);
603 for (i = 0; i < res_cpg_totem_confchg_callback->member_list_entries; i++) {
604 totem_member_list[i] = res_cpg_totem_confchg_callback->member_list[i];
605 }
606
607 cpg_inst_copy.model_v1_data.cpg_totem_confchg_fn (handle,
608 ring_id,
609 res_cpg_totem_confchg_callback->member_list_entries,
610 totem_member_list);
611 break;
612 default:
613 error = CS_ERR_LIBRARY;
614 goto error_put;
615 break;
616 } /* - switch (dispatch_data->id) */
617 break; /* case CPG_MODEL_V1 */
618 } /* - switch (cpg_inst_copy.model_data.model) */
619
620 if (cpg_inst_copy.finalize || cpg_inst->finalize) {
621 /*
622 * If the finalize has been called then get out of the dispatch.
623 */
624 cpg_inst->finalize = 1;
625 error = CS_ERR_BAD_HANDLE;
626 goto error_put;
627 }
628
629 /*
630 * Determine if more messages should be processed
631 */
632 if (dispatch_types == CS_DISPATCH_ONE || dispatch_types == CS_DISPATCH_ONE_NONBLOCKING) {
633 cont = 0;
634 }
635 } while (cont);
636
637 error_put:
638 hdb_handle_put (&cpg_handle_t_db, handle);
639 return (error);
640 }
641
642 cs_error_t cpg_join (
643 cpg_handle_t handle,
644 const struct cpg_name *group)
645 {
646 cs_error_t error;
647 struct cpg_inst *cpg_inst;
648 struct iovec iov[2];
649 struct req_lib_cpg_join req_lib_cpg_join;
650 struct res_lib_cpg_join response;
651
|
(1) Event path: |
Condition "group->length > 128", taking false branch. |
652 if (group->length > CPG_MAX_NAME_LENGTH) {
653 return (CS_ERR_NAME_TOO_LONG);
654 }
655
656 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
|
(2) Event path: |
Condition "error != CS_OK", taking false branch. |
657 if (error != CS_OK) {
658 return (error);
659 }
660
661 /* Now join */
662 req_lib_cpg_join.header.size = sizeof (struct req_lib_cpg_join);
663 req_lib_cpg_join.header.id = MESSAGE_REQ_CPG_JOIN;
664 req_lib_cpg_join.pid = getpid();
665 req_lib_cpg_join.flags = 0;
666
|
(3) Event inferred_valid_union_field: |
The union field "model_data" of "(*cpg_inst)" is assumed to be valid. |
|
(4) Event path: |
Switch case value "CPG_MODEL_V1". |
| Also see events: |
[inconsistent_union_field_access] |
667 switch (cpg_inst->model_data.model) {
668 case CPG_MODEL_V1:
|
CID (unavailable; MK=3938d5d30be2f95bc2a2c7b8dc4cb53a) (#1 of 1): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(5) Event inconsistent_union_field_access: |
In "(*cpg_inst).model_v1_data", the union field used: "model_v1_data" is inconsistent with the field most recently stored: "model_data". |
| Also see events: |
[inferred_valid_union_field] |
669 req_lib_cpg_join.flags = cpg_inst->model_v1_data.flags;
670 break;
671 }
672
673 marshall_to_mar_cpg_name_t (&req_lib_cpg_join.group_name,
674 group);
675
676 iov[0].iov_base = (void *)&req_lib_cpg_join;
677 iov[0].iov_len = sizeof (struct req_lib_cpg_join);
678
679 do {
680 error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1,
681 &response, sizeof (struct res_lib_cpg_join));
682
683 if (error != CS_OK) {
684 goto error_exit;
685 }
686 } while (response.header.error == CS_ERR_BUSY);
687
688 error = response.header.error;
689
690 error_exit:
691 hdb_handle_put (&cpg_handle_t_db, handle);
692
693 return (error);
694 }
695
696 cs_error_t cpg_leave (
697 cpg_handle_t handle,
698 const struct cpg_name *group)
699 {
700 cs_error_t error;
701 struct cpg_inst *cpg_inst;
702 struct iovec iov[2];
703 struct req_lib_cpg_leave req_lib_cpg_leave;
704 struct res_lib_cpg_leave res_lib_cpg_leave;
705
706 if (group->length > CPG_MAX_NAME_LENGTH) {
707 return (CS_ERR_NAME_TOO_LONG);
708 }
709
710 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
711 if (error != CS_OK) {
712 return (error);
713 }
714
715 req_lib_cpg_leave.header.size = sizeof (struct req_lib_cpg_leave);
716 req_lib_cpg_leave.header.id = MESSAGE_REQ_CPG_LEAVE;
717 req_lib_cpg_leave.pid = getpid();
718 marshall_to_mar_cpg_name_t (&req_lib_cpg_leave.group_name,
719 group);
720
721 iov[0].iov_base = (void *)&req_lib_cpg_leave;
722 iov[0].iov_len = sizeof (struct req_lib_cpg_leave);
723
724 do {
725 error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 1,
726 &res_lib_cpg_leave, sizeof (struct res_lib_cpg_leave));
727
728 if (error != CS_OK) {
729 goto error_exit;
730 }
731 } while (res_lib_cpg_leave.header.error == CS_ERR_BUSY);
732
733 error = res_lib_cpg_leave.header.error;
734
735 error_exit:
736 hdb_handle_put (&cpg_handle_t_db, handle);
737
738 return (error);
739 }
740
741 cs_error_t cpg_membership_get (
742 cpg_handle_t handle,
743 struct cpg_name *group_name,
744 struct cpg_address *member_list,
745 int *member_list_entries)
746 {
747 cs_error_t error;
748 struct cpg_inst *cpg_inst;
749 struct iovec iov;
750 struct req_lib_cpg_membership_get req_lib_cpg_membership_get;
751 struct res_lib_cpg_membership_get res_lib_cpg_membership_get;
752 unsigned int i;
753
754 if (group_name->length > CPG_MAX_NAME_LENGTH) {
755 return (CS_ERR_NAME_TOO_LONG);
756 }
757 if (member_list == NULL) {
758 return (CS_ERR_INVALID_PARAM);
759 }
760 if (member_list_entries == NULL) {
761 return (CS_ERR_INVALID_PARAM);
762 }
763
764 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
765 if (error != CS_OK) {
766 return (error);
767 }
768
769 req_lib_cpg_membership_get.header.size = sizeof (struct req_lib_cpg_membership_get);
770 req_lib_cpg_membership_get.header.id = MESSAGE_REQ_CPG_MEMBERSHIP;
771
772 marshall_to_mar_cpg_name_t (&req_lib_cpg_membership_get.group_name,
773 group_name);
774
775 iov.iov_base = (void *)&req_lib_cpg_membership_get;
776 iov.iov_len = sizeof (struct req_lib_cpg_membership_get);
777
778 error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1,
779 &res_lib_cpg_membership_get, sizeof (res_lib_cpg_membership_get));
780
781 if (error != CS_OK) {
782 goto error_exit;
783 }
784
785 error = res_lib_cpg_membership_get.header.error;
786
787 /*
788 * Copy results to caller
789 */
790 *member_list_entries = res_lib_cpg_membership_get.member_count;
791 if (member_list) {
792 for (i = 0; i < res_lib_cpg_membership_get.member_count; i++) {
793 marshall_from_mar_cpg_address_t (&member_list[i],
794 &res_lib_cpg_membership_get.member_list[i]);
795 }
796 }
797
798 error_exit:
799 hdb_handle_put (&cpg_handle_t_db, handle);
800
801 return (error);
802 }
803
804 cs_error_t cpg_local_get (
805 cpg_handle_t handle,
806 unsigned int *local_nodeid)
807 {
808 cs_error_t error;
809 struct cpg_inst *cpg_inst;
810 struct iovec iov;
811 struct req_lib_cpg_local_get req_lib_cpg_local_get;
812 struct res_lib_cpg_local_get res_lib_cpg_local_get;
813
814 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
815 if (error != CS_OK) {
816 return (error);
817 }
818
819 req_lib_cpg_local_get.header.size = sizeof (struct qb_ipc_request_header);
820 req_lib_cpg_local_get.header.id = MESSAGE_REQ_CPG_LOCAL_GET;
821
822 iov.iov_base = (void *)&req_lib_cpg_local_get;
823 iov.iov_len = sizeof (struct req_lib_cpg_local_get);
824
825 error = coroipcc_msg_send_reply_receive (cpg_inst->c, &iov, 1,
826 &res_lib_cpg_local_get, sizeof (res_lib_cpg_local_get));
827
828 if (error != CS_OK) {
829 goto error_exit;
830 }
831
832 error = res_lib_cpg_local_get.header.error;
833
834 *local_nodeid = res_lib_cpg_local_get.local_nodeid;
835
836 error_exit:
837 hdb_handle_put (&cpg_handle_t_db, handle);
838
839 return (error);
840 }
841
842 cs_error_t cpg_flow_control_state_get (
843 cpg_handle_t handle,
844 cpg_flow_control_state_t *flow_control_state)
845 {
846 cs_error_t error;
847 struct cpg_inst *cpg_inst;
848
849 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
850 if (error != CS_OK) {
851 return (error);
852 }
853 *flow_control_state = CPG_FLOW_CONTROL_DISABLED;
854 error = CS_OK;
855
856 hdb_handle_put (&cpg_handle_t_db, handle);
857
858 return (error);
859 }
860
861 /*
862 * Dummy-ish function that just allocates some memory for the user
863 */
864 cs_error_t cpg_zcb_alloc (
865 cpg_handle_t handle,
866 size_t size,
867 void **buffer)
868 {
869 int error = CS_OK;
870
871 *buffer = malloc(size);
872 if (*buffer == NULL) {
873 error = CS_ERR_NO_MEMORY;
874 }
875
876 return (error);
877 }
878
879 cs_error_t cpg_zcb_free (
880 cpg_handle_t handle,
881 void *buffer)
882 {
883 free(buffer);
884 return (CS_OK);
885 }
886
887 cs_error_t cpg_zcb_mcast_joined (
888 cpg_handle_t handle,
889 cpg_guarantee_t guarantee,
890 void *msg,
891 size_t msg_len)
892 {
893 struct iovec iov[1];
894 iov[0].iov_base = msg;
895 iov[0].iov_len = msg_len;
896
897 return cpg_mcast_joined(handle, guarantee, iov, 1);
898 }
899
900 static cs_error_t send_fragments (
901 struct cpg_inst *cpg_inst,
902 cpg_guarantee_t guarantee,
903 size_t msg_len,
904 const struct iovec *iovec,
905 unsigned int iov_len)
906 {
907 int i;
908 cs_error_t error = CS_OK;
909 struct iovec iov[2];
910 struct req_lib_cpg_partial_mcast req_lib_cpg_mcast;
911 struct res_lib_cpg_partial_send res_lib_cpg_partial_send;
912 size_t sent = 0;
913 size_t iov_sent = 0;
914 int retry_count;
915
916 req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_PARTIAL_MCAST;
917 req_lib_cpg_mcast.guarantee = guarantee;
918 req_lib_cpg_mcast.msglen = msg_len;
919
920 iov[0].iov_base = (void *)&req_lib_cpg_mcast;
921 iov[0].iov_len = sizeof (struct req_lib_cpg_partial_mcast);
922
923 i=0;
924 iov_sent = 0 ;
925 qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
926
927 while (error == CS_OK && sent < msg_len) {
928
929 retry_count = 0;
930 if ( (iovec[i].iov_len - iov_sent) > cpg_inst->max_msg_size) {
931 iov[1].iov_len = cpg_inst->max_msg_size;
932 }
933 else {
934 iov[1].iov_len = iovec[i].iov_len - iov_sent;
935 }
936
937 if (sent == 0) {
938 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_FIRST;
939 }
940 else if ((sent + iov[1].iov_len) == msg_len) {
941 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_LAST;
942 }
943 else {
944 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_CONTINUED;
945 }
946
947 req_lib_cpg_mcast.fraglen = iov[1].iov_len;
948 req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_partial_mcast) + iov[1].iov_len;
949 iov[1].iov_base = (char *)iovec[i].iov_base + iov_sent;
950
951 resend:
952 error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 2,
953 &res_lib_cpg_partial_send,
954 sizeof (res_lib_cpg_partial_send));
955
956 if (error == CS_ERR_TRY_AGAIN) {
957 fprintf(stderr, "sleep. counter=%d\n", retry_count);
958 if (++retry_count > MAX_RETRIES) {
959 goto error_exit;
960 }
961 usleep(10000);
962 goto resend;
963 }
964
965 iov_sent += iov[1].iov_len;
966 sent += iov[1].iov_len;
967
968 /* Next iovec */
969 if (iov_sent >= iovec[i].iov_len) {
970 i++;
971 iov_sent = 0;
972 }
973 error = res_lib_cpg_partial_send.header.error;
974 }
975 error_exit:
976 qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
977
978 return error;
979 }
980
981
982 cs_error_t cpg_mcast_joined (
983 cpg_handle_t handle,
984 cpg_guarantee_t guarantee,
985 const struct iovec *iovec,
986 unsigned int iov_len)
987 {
988 int i;
989 cs_error_t error;
990 struct cpg_inst *cpg_inst;
991 struct iovec iov[64];
992 struct req_lib_cpg_mcast req_lib_cpg_mcast;
993 size_t msg_len = 0;
994
995 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
996 if (error != CS_OK) {
997 return (error);
998 }
999
1000 for (i = 0; i < iov_len; i++ ) {
1001 msg_len += iovec[i].iov_len;
1002 }
1003
1004 if (msg_len > cpg_inst->max_msg_size) {
1005 error = send_fragments(cpg_inst, guarantee, msg_len, iovec, iov_len);
1006 goto error_exit;
1007 }
1008
1009 req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_mcast) +
1010 msg_len;
1011
1012 req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_MCAST;
1013 req_lib_cpg_mcast.guarantee = guarantee;
1014 req_lib_cpg_mcast.msglen = msg_len;
1015
1016 iov[0].iov_base = (void *)&req_lib_cpg_mcast;
1017 iov[0].iov_len = sizeof (struct req_lib_cpg_mcast);
1018 memcpy (&iov[1], iovec, iov_len * sizeof (struct iovec));
1019
1020 qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
1021 error = qb_to_cs_error(qb_ipcc_sendv(cpg_inst->c, iov, iov_len + 1));
1022 qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
1023
1024 error_exit:
1025 hdb_handle_put (&cpg_handle_t_db, handle);
1026
1027 return (error);
1028 }
1029
1030 cs_error_t cpg_iteration_initialize(
1031 cpg_handle_t handle,
1032 cpg_iteration_type_t iteration_type,
1033 const struct cpg_name *group,
1034 cpg_iteration_handle_t *cpg_iteration_handle)
1035 {
1036 cs_error_t error;
1037 struct iovec iov;
1038 struct cpg_inst *cpg_inst;
1039 struct cpg_iteration_instance_t *cpg_iteration_instance;
1040 struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize;
1041 struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize;
1042
1043 if (group && group->length > CPG_MAX_NAME_LENGTH) {
1044 return (CS_ERR_NAME_TOO_LONG);
1045 }
1046 if (cpg_iteration_handle == NULL) {
1047 return (CS_ERR_INVALID_PARAM);
1048 }
1049
1050 if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) ||
1051 (iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) {
1052 return (CS_ERR_INVALID_PARAM);
1053 }
1054
1055 if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP &&
1056 iteration_type != CPG_ITERATION_ALL) {
1057
1058 return (CS_ERR_INVALID_PARAM);
1059 }
1060
1061 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
1062 if (error != CS_OK) {
1063 return (error);
1064 }
1065
1066 error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db,
1067 sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle));
1068 if (error != CS_OK) {
1069 goto error_put_cpg_db;
1070 }
1071
1072 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle,
1073 (void *)&cpg_iteration_instance));
1074 if (error != CS_OK) {
1075 goto error_destroy;
1076 }
1077
1078 cpg_iteration_instance->conn = cpg_inst->c;
1079
1080 qb_list_init (&cpg_iteration_instance->list);
1081
1082 req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize);
1083 req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE;
1084 req_lib_cpg_iterationinitialize.iteration_type = iteration_type;
1085 if (group) {
1086 marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group);
1087 }
1088
1089 iov.iov_base = (void *)&req_lib_cpg_iterationinitialize;
1090 iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize);
1091
1092 error = coroipcc_msg_send_reply_receive (cpg_inst->c,
1093 &iov,
1094 1,
1095 &res_lib_cpg_iterationinitialize,
1096 sizeof (struct res_lib_cpg_iterationinitialize));
1097
1098 if (error != CS_OK) {
1099 goto error_put_destroy;
1100 }
1101
1102 cpg_iteration_instance->executive_iteration_handle =
1103 res_lib_cpg_iterationinitialize.iteration_handle;
1104 cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle;
1105
1106 qb_list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head);
1107
1108 hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1109 hdb_handle_put (&cpg_handle_t_db, handle);
1110
1111 return (res_lib_cpg_iterationinitialize.header.error);
1112
1113 error_put_destroy:
1114 hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1115 error_destroy:
1116 hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1117 error_put_cpg_db:
1118 hdb_handle_put (&cpg_handle_t_db, handle);
1119
1120 return (error);
1121 }
1122
1123 cs_error_t cpg_iteration_next(
1124 cpg_iteration_handle_t handle,
1125 struct cpg_iteration_description_t *description)
1126 {
1127 cs_error_t error;
1128 struct cpg_iteration_instance_t *cpg_iteration_instance;
1129 struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext;
1130 struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext;
1131
1132 if (description == NULL) {
1133 return CS_ERR_INVALID_PARAM;
1134 }
1135
1136 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
1137 (void *)&cpg_iteration_instance));
1138 if (error != CS_OK) {
1139 goto error_exit;
1140 }
1141
1142 req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext);
1143 req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT;
1144 req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
1145
1146 error = qb_to_cs_error (qb_ipcc_send (cpg_iteration_instance->conn,
1147 &req_lib_cpg_iterationnext,
1148 req_lib_cpg_iterationnext.header.size));
1149 if (error != CS_OK) {
1150 goto error_put;
1151 }
1152
1153 error = qb_to_cs_error (qb_ipcc_recv (cpg_iteration_instance->conn,
1154 &res_lib_cpg_iterationnext,
1155 sizeof(struct res_lib_cpg_iterationnext), -1));
1156 if (error != CS_OK) {
1157 goto error_put;
1158 }
1159
1160 marshall_from_mar_cpg_iteration_description_t(
1161 description,
1162 &res_lib_cpg_iterationnext.description);
1163
1164 error = res_lib_cpg_iterationnext.header.error;
1165
1166 error_put:
1167 hdb_handle_put (&cpg_iteration_handle_t_db, handle);
1168
1169 error_exit:
1170 return (error);
1171 }
1172
1173 cs_error_t cpg_iteration_finalize (
1174 cpg_iteration_handle_t handle)
1175 {
1176 cs_error_t error;
1177 struct iovec iov;
1178 struct cpg_iteration_instance_t *cpg_iteration_instance;
1179 struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize;
1180 struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize;
1181
1182 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
1183 (void *)&cpg_iteration_instance));
1184 if (error != CS_OK) {
1185 goto error_exit;
1186 }
1187
1188 req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize);
1189 req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE;
1190 req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
1191
1192 iov.iov_base = (void *)&req_lib_cpg_iterationfinalize;
1193 iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize);
1194
1195 error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn,
1196 &iov,
1197 1,
1198 &res_lib_cpg_iterationfinalize,
1199 sizeof (struct req_lib_cpg_iterationfinalize));
1200
1201 if (error != CS_OK) {
1202 goto error_put;
1203 }
1204
1205 cpg_iteration_instance_finalize (cpg_iteration_instance);
1206 hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
1207
1208 return (res_lib_cpg_iterationfinalize.header.error);
1209
1210 error_put:
1211 hdb_handle_put (&cpg_iteration_handle_t_db, handle);
1212 error_exit:
1213 return (error);
1214 }
1215
1216 /** @} */
1217