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_TOTEM_CONFCHG_CALLBACK".
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 (&current_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:
CID (unavailable; MK=98c41fd7f84238dd1145dc0e61608484) (#4 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]
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  		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