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));
|
(1) Event path: |
Condition "error != CS_OK", taking false branch. |
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 */
|
(2) Event path: |
Condition "dispatch_types == CS_DISPATCH_ALL", taking true branch. |
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);
|
(3) Event path: |
Condition "error == CS_ERR_BAD_HANDLE", taking false branch. |
414 if (error == CS_ERR_BAD_HANDLE) {
415 error = CS_OK;
416 goto error_put;
417 }
|
(4) Event path: |
Condition "error == CS_ERR_TRY_AGAIN", taking false branch. |
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 }
|
(5) Event path: |
Condition "error != CS_OK", taking false branch. |
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));
|
(6) Event inferred_valid_union_field: |
The union field "model_data" of "cpg_inst_copy" is assumed to be valid. |
|
(7) Event path: |
Switch case value "CPG_MODEL_V1". |
| Also see events: |
[inconsistent_union_field_access] |
442 switch (cpg_inst_copy.model_data.model) {
443 case CPG_MODEL_V1:
444 /*
445 * Dispatch incoming message
446 */
|
(8) Event path: |
Switch case value "MESSAGE_RES_CPG_DELIVER_CALLBACK". |
447 switch (dispatch_data->id) {
448 case MESSAGE_RES_CPG_DELIVER_CALLBACK:
|
CID (unavailable; MK=98c41fd7f84238dd1145dc0e61608484) (#1 of 4): Inconsistent C union access (INCONSISTENT_UNION_ACCESS): |
|
(9) Event inconsistent_union_field_access: |
In "cpg_inst_copy.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] |
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
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));
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
667 switch (cpg_inst->model_data.model) {
668 case CPG_MODEL_V1:
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
895 iov[0].iov_base = msg;
896 iov[0].iov_len = msg_len;
897
898 return cpg_mcast_joined(handle, guarantee, iov, 1);
899 }
900
901 static cs_error_t send_fragments (
902 struct cpg_inst *cpg_inst,
903 cpg_guarantee_t guarantee,
904 size_t msg_len,
905 const struct iovec *iovec,
906 unsigned int iov_len)
907 {
908 int i;
909 cs_error_t error = CS_OK;
910 struct iovec iov[2];
911 struct req_lib_cpg_partial_mcast req_lib_cpg_mcast;
912 struct res_lib_cpg_partial_send res_lib_cpg_partial_send;
913 size_t sent = 0;
914 size_t iov_sent = 0;
915 int retry_count;
916
917 req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_PARTIAL_MCAST;
918 req_lib_cpg_mcast.guarantee = guarantee;
919 req_lib_cpg_mcast.msglen = msg_len;
920
921 iov[0].iov_base = (void *)&req_lib_cpg_mcast;
922 iov[0].iov_len = sizeof (struct req_lib_cpg_partial_mcast);
923
924 i=0;
925 iov_sent = 0 ;
926 qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
927
928 while (error == CS_OK && sent < msg_len) {
929
930 retry_count = 0;
931 if ( (iovec[i].iov_len - iov_sent) > cpg_inst->max_msg_size) {
932 iov[1].iov_len = cpg_inst->max_msg_size;
933 }
934 else {
935 iov[1].iov_len = iovec[i].iov_len - iov_sent;
936 }
937
938 if (sent == 0) {
939 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_FIRST;
940 }
941 else if ((sent + iov[1].iov_len) == msg_len) {
942 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_LAST;
943 }
944 else {
945 req_lib_cpg_mcast.type = LIBCPG_PARTIAL_CONTINUED;
946 }
947
948 req_lib_cpg_mcast.fraglen = iov[1].iov_len;
949 req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_partial_mcast) + iov[1].iov_len;
950 iov[1].iov_base = (char *)iovec[i].iov_base + iov_sent;
951
952 resend:
953 error = coroipcc_msg_send_reply_receive (cpg_inst->c, iov, 2,
954 &res_lib_cpg_partial_send,
955 sizeof (res_lib_cpg_partial_send));
956
957 if (error == CS_ERR_TRY_AGAIN) {
958 fprintf(stderr, "sleep. counter=%d\n", retry_count);
959 if (++retry_count > MAX_RETRIES) {
960 goto error_exit;
961 }
962 usleep(10000);
963 goto resend;
964 }
965
966 iov_sent += iov[1].iov_len;
967 sent += iov[1].iov_len;
968
969 /* Next iovec */
970 if (iov_sent >= iovec[i].iov_len) {
971 i++;
972 iov_sent = 0;
973 }
974 error = res_lib_cpg_partial_send.header.error;
975 }
976 error_exit:
977 qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
978
979 return error;
980 }
981
982
983 cs_error_t cpg_mcast_joined (
984 cpg_handle_t handle,
985 cpg_guarantee_t guarantee,
986 const struct iovec *iovec,
987 unsigned int iov_len)
988 {
989 int i;
990 cs_error_t error;
991 struct cpg_inst *cpg_inst;
992 struct iovec iov[64];
993 struct req_lib_cpg_mcast req_lib_cpg_mcast;
994 size_t msg_len = 0;
995
996 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
997 if (error != CS_OK) {
998 return (error);
999 }
1000
1001 for (i = 0; i < iov_len; i++ ) {
1002 msg_len += iovec[i].iov_len;
1003 }
1004
1005 if (msg_len > cpg_inst->max_msg_size) {
1006 error = send_fragments(cpg_inst, guarantee, msg_len, iovec, iov_len);
1007 goto error_exit;
1008 }
1009
1010 req_lib_cpg_mcast.header.size = sizeof (struct req_lib_cpg_mcast) +
1011 msg_len;
1012
1013 req_lib_cpg_mcast.header.id = MESSAGE_REQ_CPG_MCAST;
1014 req_lib_cpg_mcast.guarantee = guarantee;
1015 req_lib_cpg_mcast.msglen = msg_len;
1016
1017 iov[0].iov_base = (void *)&req_lib_cpg_mcast;
1018 iov[0].iov_len = sizeof (struct req_lib_cpg_mcast);
1019 memcpy (&iov[1], iovec, iov_len * sizeof (struct iovec));
1020
1021 qb_ipcc_fc_enable_max_set(cpg_inst->c, 2);
1022 error = qb_to_cs_error(qb_ipcc_sendv(cpg_inst->c, iov, iov_len + 1));
1023 qb_ipcc_fc_enable_max_set(cpg_inst->c, 1);
1024
1025 error_exit:
1026 hdb_handle_put (&cpg_handle_t_db, handle);
1027
1028 return (error);
1029 }
1030
1031 cs_error_t cpg_iteration_initialize(
1032 cpg_handle_t handle,
1033 cpg_iteration_type_t iteration_type,
1034 const struct cpg_name *group,
1035 cpg_iteration_handle_t *cpg_iteration_handle)
1036 {
1037 cs_error_t error;
1038 struct iovec iov;
1039 struct cpg_inst *cpg_inst;
1040 struct cpg_iteration_instance_t *cpg_iteration_instance;
1041 struct req_lib_cpg_iterationinitialize req_lib_cpg_iterationinitialize;
1042 struct res_lib_cpg_iterationinitialize res_lib_cpg_iterationinitialize;
1043
1044 if (group && group->length > CPG_MAX_NAME_LENGTH) {
1045 return (CS_ERR_NAME_TOO_LONG);
1046 }
1047 if (cpg_iteration_handle == NULL) {
1048 return (CS_ERR_INVALID_PARAM);
1049 }
1050
1051 if ((iteration_type == CPG_ITERATION_ONE_GROUP && group == NULL) ||
1052 (iteration_type != CPG_ITERATION_ONE_GROUP && group != NULL)) {
1053 return (CS_ERR_INVALID_PARAM);
1054 }
1055
1056 if (iteration_type != CPG_ITERATION_NAME_ONLY && iteration_type != CPG_ITERATION_ONE_GROUP &&
1057 iteration_type != CPG_ITERATION_ALL) {
1058
1059 return (CS_ERR_INVALID_PARAM);
1060 }
1061
1062 error = hdb_error_to_cs (hdb_handle_get (&cpg_handle_t_db, handle, (void *)&cpg_inst));
1063 if (error != CS_OK) {
1064 return (error);
1065 }
1066
1067 error = hdb_error_to_cs (hdb_handle_create (&cpg_iteration_handle_t_db,
1068 sizeof (struct cpg_iteration_instance_t), cpg_iteration_handle));
1069 if (error != CS_OK) {
1070 goto error_put_cpg_db;
1071 }
1072
1073 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, *cpg_iteration_handle,
1074 (void *)&cpg_iteration_instance));
1075 if (error != CS_OK) {
1076 goto error_destroy;
1077 }
1078
1079 cpg_iteration_instance->conn = cpg_inst->c;
1080
1081 qb_list_init (&cpg_iteration_instance->list);
1082
1083 req_lib_cpg_iterationinitialize.header.size = sizeof (struct req_lib_cpg_iterationinitialize);
1084 req_lib_cpg_iterationinitialize.header.id = MESSAGE_REQ_CPG_ITERATIONINITIALIZE;
1085 req_lib_cpg_iterationinitialize.iteration_type = iteration_type;
1086 if (group) {
1087 marshall_to_mar_cpg_name_t (&req_lib_cpg_iterationinitialize.group_name, group);
1088 }
1089
1090 iov.iov_base = (void *)&req_lib_cpg_iterationinitialize;
1091 iov.iov_len = sizeof (struct req_lib_cpg_iterationinitialize);
1092
1093 error = coroipcc_msg_send_reply_receive (cpg_inst->c,
1094 &iov,
1095 1,
1096 &res_lib_cpg_iterationinitialize,
1097 sizeof (struct res_lib_cpg_iterationinitialize));
1098
1099 if (error != CS_OK) {
1100 goto error_put_destroy;
1101 }
1102
1103 cpg_iteration_instance->executive_iteration_handle =
1104 res_lib_cpg_iterationinitialize.iteration_handle;
1105 cpg_iteration_instance->cpg_iteration_handle = *cpg_iteration_handle;
1106
1107 qb_list_add (&cpg_iteration_instance->list, &cpg_inst->iteration_list_head);
1108
1109 hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1110 hdb_handle_put (&cpg_handle_t_db, handle);
1111
1112 return (res_lib_cpg_iterationinitialize.header.error);
1113
1114 error_put_destroy:
1115 hdb_handle_put (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1116 error_destroy:
1117 hdb_handle_destroy (&cpg_iteration_handle_t_db, *cpg_iteration_handle);
1118 error_put_cpg_db:
1119 hdb_handle_put (&cpg_handle_t_db, handle);
1120
1121 return (error);
1122 }
1123
1124 cs_error_t cpg_iteration_next(
1125 cpg_iteration_handle_t handle,
1126 struct cpg_iteration_description_t *description)
1127 {
1128 cs_error_t error;
1129 struct cpg_iteration_instance_t *cpg_iteration_instance;
1130 struct req_lib_cpg_iterationnext req_lib_cpg_iterationnext;
1131 struct res_lib_cpg_iterationnext res_lib_cpg_iterationnext;
1132
1133 if (description == NULL) {
1134 return CS_ERR_INVALID_PARAM;
1135 }
1136
1137 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
1138 (void *)&cpg_iteration_instance));
1139 if (error != CS_OK) {
1140 goto error_exit;
1141 }
1142
1143 req_lib_cpg_iterationnext.header.size = sizeof (struct req_lib_cpg_iterationnext);
1144 req_lib_cpg_iterationnext.header.id = MESSAGE_REQ_CPG_ITERATIONNEXT;
1145 req_lib_cpg_iterationnext.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
1146
1147 error = qb_to_cs_error (qb_ipcc_send (cpg_iteration_instance->conn,
1148 &req_lib_cpg_iterationnext,
1149 req_lib_cpg_iterationnext.header.size));
1150 if (error != CS_OK) {
1151 goto error_put;
1152 }
1153
1154 error = qb_to_cs_error (qb_ipcc_recv (cpg_iteration_instance->conn,
1155 &res_lib_cpg_iterationnext,
1156 sizeof(struct res_lib_cpg_iterationnext), -1));
1157 if (error != CS_OK) {
1158 goto error_put;
1159 }
1160
1161 marshall_from_mar_cpg_iteration_description_t(
1162 description,
1163 &res_lib_cpg_iterationnext.description);
1164
1165 error = res_lib_cpg_iterationnext.header.error;
1166
1167 error_put:
1168 hdb_handle_put (&cpg_iteration_handle_t_db, handle);
1169
1170 error_exit:
1171 return (error);
1172 }
1173
1174 cs_error_t cpg_iteration_finalize (
1175 cpg_iteration_handle_t handle)
1176 {
1177 cs_error_t error;
1178 struct iovec iov;
1179 struct cpg_iteration_instance_t *cpg_iteration_instance;
1180 struct req_lib_cpg_iterationfinalize req_lib_cpg_iterationfinalize;
1181 struct res_lib_cpg_iterationfinalize res_lib_cpg_iterationfinalize;
1182
1183 error = hdb_error_to_cs (hdb_handle_get (&cpg_iteration_handle_t_db, handle,
1184 (void *)&cpg_iteration_instance));
1185 if (error != CS_OK) {
1186 goto error_exit;
1187 }
1188
1189 req_lib_cpg_iterationfinalize.header.size = sizeof (struct req_lib_cpg_iterationfinalize);
1190 req_lib_cpg_iterationfinalize.header.id = MESSAGE_REQ_CPG_ITERATIONFINALIZE;
1191 req_lib_cpg_iterationfinalize.iteration_handle = cpg_iteration_instance->executive_iteration_handle;
1192
1193 iov.iov_base = (void *)&req_lib_cpg_iterationfinalize;
1194 iov.iov_len = sizeof (struct req_lib_cpg_iterationfinalize);
1195
1196 error = coroipcc_msg_send_reply_receive (cpg_iteration_instance->conn,
1197 &iov,
1198 1,
1199 &res_lib_cpg_iterationfinalize,
1200 sizeof (struct req_lib_cpg_iterationfinalize));
1201
1202 if (error != CS_OK) {
1203 goto error_put;
1204 }
1205
1206 cpg_iteration_instance_finalize (cpg_iteration_instance);
1207 hdb_handle_put (&cpg_iteration_handle_t_db, cpg_iteration_instance->cpg_iteration_handle);
1208
1209 return (res_lib_cpg_iterationfinalize.header.error);
1210
1211 error_put:
1212 hdb_handle_put (&cpg_iteration_handle_t_db, handle);
1213 error_exit:
1214 return (error);
1215 }
1216
1217 /** @} */
1218