1 /*
2  * $Header$
3  *
4  * Handles watchdog connection, and protocol communication with pgpool-II
5  *
6  * pgpool: a language independent connection pool server for PostgreSQL
7  * written by Tatsuo Ishii
8  *
9  * Copyright (c) 2003-2015	PgPool Global Development Group
10  *
11  * Permission to use, copy, modify, and distribute this software and
12  * its documentation for any purpose and without fee is hereby
13  * granted, provided that the above copyright notice appear in all
14  * copies and that both that copyright notice and this permission
15  * notice appear in supporting documentation, and that the name of the
16  * author not be used in advertising or publicity pertaining to
17  * distribution of the software without specific, written prior
18  * permission. The author makes no representations about the
19  * suitability of this software for any purpose.  It is provided "as
20  * is" without express or implied warranty.
21  *
22  */
23 #include <string.h>
24 #include <stdlib.h>
25 
26 #include "utils/elog.h"
27 #include "utils/json_writer.h"
28 #include "utils/json.h"
29 #include "pool_config.h"
30 #include "watchdog/watchdog.h"
31 #include "watchdog/wd_json_data.h"
32 #include "watchdog/wd_ipc_defines.h"
33 #include "pool.h"
34 
35 
get_pool_config_from_json(char * json_data,int data_len)36 POOL_CONFIG* get_pool_config_from_json(char* json_data, int data_len)
37 {
38 	int i;
39 	json_value *root = NULL;
40 	json_value *value = NULL;
41 	POOL_CONFIG *config = palloc0(sizeof(POOL_CONFIG));
42 	config->backend_desc = palloc0(sizeof(BackendDesc));
43 
44 	root = json_parse(json_data,data_len);
45 	/* The root node must be object */
46 	if (root == NULL || root->type != json_object)
47 		goto ERROR_EXIT;
48 
49 	if (json_get_int_value_for_key(root, "num_init_children", &config->num_init_children))
50 		goto ERROR_EXIT;
51 	if (json_get_int_value_for_key(root, "listen_backlog_multiplier", &config->listen_backlog_multiplier))
52 		goto ERROR_EXIT;
53 	if (json_get_int_value_for_key(root, "child_life_time", &config->child_life_time))
54 		goto ERROR_EXIT;
55 	if (json_get_int_value_for_key(root, "connection_life_time", &config->connection_life_time))
56 		goto ERROR_EXIT;
57 	if (json_get_int_value_for_key(root, "child_max_connections", &config->child_max_connections))
58 		goto ERROR_EXIT;
59 	if (json_get_int_value_for_key(root, "client_idle_limit", &config->client_idle_limit))
60 		goto ERROR_EXIT;
61 	if (json_get_int_value_for_key(root, "max_pool", &config->max_pool))
62 		goto ERROR_EXIT;
63 	if (json_get_bool_value_for_key(root, "replication_mode", &config->replication_mode))
64 		goto ERROR_EXIT;
65 	if (json_get_bool_value_for_key(root, "enable_pool_hba", &config->enable_pool_hba))
66 		goto ERROR_EXIT;
67 	if (json_get_int_value_for_key(root, "load_balance_mode", (int*)&config->load_balance_mode))
68 		goto ERROR_EXIT;
69 	if (json_get_bool_value_for_key(root, "replication_stop_on_mismatch", &config->replication_stop_on_mismatch))
70 		goto ERROR_EXIT;
71 	if (json_get_bool_value_for_key(root, "failover_if_affected_tuples_mismatch", &config->failover_if_affected_tuples_mismatch))
72 		goto ERROR_EXIT;
73 	if (json_get_bool_value_for_key(root, "replicate_select", &config->replicate_select))
74 		goto ERROR_EXIT;
75 	if (json_get_int_value_for_key(root, "master_slave_mode", (int*)&config->master_slave_mode))
76 		goto ERROR_EXIT;
77 	if (json_get_bool_value_for_key(root, "connection_cache", &config->connection_cache))
78 		goto ERROR_EXIT;
79 	if (json_get_int_value_for_key(root, "health_check_timeout", &config->health_check_timeout))
80 		goto ERROR_EXIT;
81 	if (json_get_int_value_for_key(root, "health_check_period", &config->health_check_period))
82 		goto ERROR_EXIT;
83 	if (json_get_int_value_for_key(root, "health_check_max_retries", &config->health_check_max_retries))
84 		goto ERROR_EXIT;
85 	if (json_get_int_value_for_key(root, "health_check_retry_delay", &config->health_check_retry_delay))
86 		goto ERROR_EXIT;
87 	if (json_get_bool_value_for_key(root, "fail_over_on_backend_error", &config->fail_over_on_backend_error))
88 		goto ERROR_EXIT;
89 	if (json_get_int_value_for_key(root, "recovery_timeout", &config->recovery_timeout))
90 		goto ERROR_EXIT;
91 	if (json_get_int_value_for_key(root, "search_primary_node_timeout", &config->search_primary_node_timeout))
92 		goto ERROR_EXIT;
93 	if (json_get_int_value_for_key(root, "client_idle_limit_in_recovery", &config->client_idle_limit_in_recovery))
94 		goto ERROR_EXIT;
95 	if (json_get_bool_value_for_key(root, "insert_lock", &config->insert_lock))
96 		goto ERROR_EXIT;
97 	if (json_get_bool_value_for_key(root, "memory_cache_enabled", &config->memory_cache_enabled))
98 		goto ERROR_EXIT;
99 	if (json_get_bool_value_for_key(root, "use_watchdog", &config->use_watchdog))
100 		goto ERROR_EXIT;
101 	if (json_get_bool_value_for_key(root, "clear_memqcache_on_escalation", &config->clear_memqcache_on_escalation))
102 		goto ERROR_EXIT;
103 	if (json_get_int_value_for_key(root, "wd_port", &config->wd_port))
104 		goto ERROR_EXIT;
105 	if (json_get_int_value_for_key(root, "wd_priority", &config->wd_priority))
106 		goto ERROR_EXIT;
107 	if (json_get_int_value_for_key(root, "master_slave_sub_mode", (int*)&config->master_slave_sub_mode))
108 		goto ERROR_EXIT;
109 
110 
111 	/* backend_desc array */
112 	value = json_get_value_for_key(root,"backend_desc");
113 	if (value == NULL || value->type != json_array)
114 		goto ERROR_EXIT;
115 
116 	config->backend_desc->num_backends = value->u.array.length;
117 	for (i = 0; i < config->backend_desc->num_backends; i++)
118 	{
119 		json_value *arr_value = value->u.array.values[i];
120 		char *ptr;
121 		if (json_get_int_value_for_key(arr_value, "backend_port", &config->backend_desc->backend_info[i].backend_port))
122 			goto ERROR_EXIT;
123 		ptr = json_get_string_value_for_key(arr_value, "backend_hostname");
124 		if (ptr == NULL)
125 			goto ERROR_EXIT;
126 		strncpy(config->backend_desc->backend_info[i].backend_hostname, ptr,sizeof(config->backend_desc->backend_info[i].backend_hostname) -1);
127 	}
128 
129 	/* wd_remote_nodes array */
130 	value = json_get_value_for_key(root,"wd_remote_nodes");
131 	if (value == NULL || value->type != json_array)
132 		goto ERROR_EXIT;
133 
134 	config->wd_remote_nodes.num_wd = value->u.array.length;
135 	for (i = 0; i < config->wd_remote_nodes.num_wd; i++)
136 	{
137 		json_value *arr_value = value->u.array.values[i];
138 		char *ptr;
139 		if (json_get_int_value_for_key(arr_value, "wd_port", &config->wd_remote_nodes.wd_remote_node_info[i].wd_port))
140 			goto ERROR_EXIT;
141 		if (json_get_int_value_for_key(arr_value, "pgpool_port", &config->wd_remote_nodes.wd_remote_node_info[i].pgpool_port))
142 			goto ERROR_EXIT;
143 		ptr = json_get_string_value_for_key(arr_value, "hostname");
144 		if (ptr == NULL)
145 			goto ERROR_EXIT;
146 		strncpy(config->wd_remote_nodes.wd_remote_node_info[i].hostname, ptr,sizeof(config->wd_remote_nodes.wd_remote_node_info[i].hostname) -1);
147 	}
148 
149 	json_value_free(root);
150 	return config;
151 
152 ERROR_EXIT:
153 	if (root)
154 		json_value_free(root);
155 	if (config->backend_desc)
156 		pfree(config->backend_desc);
157 	pfree(config);
158 	return NULL;
159 }
160 
get_pool_config_json(void)161 char* get_pool_config_json(void)
162 {
163 	int i;
164 	char* json_str;
165 
166 	JsonNode* jNode = jw_create_with_object(true);
167 
168 	jw_put_int(jNode, "num_init_children", pool_config->num_init_children);
169 	jw_put_int(jNode, "listen_backlog_multiplier", pool_config->listen_backlog_multiplier);
170 	jw_put_int(jNode, "child_life_time", pool_config->child_life_time);
171 	jw_put_int(jNode, "connection_life_time", pool_config->connection_life_time);
172 	jw_put_int(jNode, "child_max_connections", pool_config->child_max_connections);
173 	jw_put_int(jNode, "client_idle_limit", pool_config->client_idle_limit);
174 	jw_put_int(jNode, "max_pool", pool_config->max_pool);
175 	jw_put_bool(jNode, "replication_mode", pool_config->replication_mode);
176 	jw_put_bool(jNode, "enable_pool_hba", pool_config->enable_pool_hba);
177 	jw_put_int(jNode, "load_balance_mode", pool_config->load_balance_mode);
178 	jw_put_bool(jNode, "replication_stop_on_mismatch", pool_config->replication_stop_on_mismatch);
179 	jw_put_bool(jNode, "failover_if_affected_tuples_mismatch", pool_config->failover_if_affected_tuples_mismatch);
180 	jw_put_bool(jNode, "replicate_select", pool_config->replicate_select);
181 	jw_put_int(jNode, "master_slave_mode", pool_config->master_slave_mode);
182 	jw_put_bool(jNode, "connection_cache", pool_config->connection_cache);
183 	jw_put_int(jNode, "health_check_timeout", pool_config->health_check_timeout);
184 	jw_put_int(jNode, "health_check_period", pool_config->health_check_period);
185 	jw_put_int(jNode, "health_check_max_retries", pool_config->health_check_max_retries);
186 	jw_put_int(jNode, "health_check_retry_delay", pool_config->health_check_retry_delay);
187 	jw_put_bool(jNode, "fail_over_on_backend_error", pool_config->fail_over_on_backend_error);
188 	jw_put_int(jNode, "recovery_timeout", pool_config->recovery_timeout);
189 	jw_put_int(jNode, "search_primary_node_timeout", pool_config->search_primary_node_timeout);
190 	jw_put_int(jNode, "client_idle_limit_in_recovery", pool_config->client_idle_limit_in_recovery);
191 	jw_put_bool(jNode, "insert_lock", pool_config->insert_lock);
192 	jw_put_bool(jNode, "memory_cache_enabled", pool_config->memory_cache_enabled);
193 	jw_put_bool(jNode, "use_watchdog", pool_config->use_watchdog);
194 	jw_put_bool(jNode, "clear_memqcache_on_escalation", pool_config->clear_memqcache_on_escalation);
195 	jw_put_int(jNode, "wd_port", pool_config->wd_port);
196 	jw_put_int(jNode, "wd_priority", pool_config->wd_priority);
197 	jw_put_int(jNode, "master_slave_sub_mode", pool_config->master_slave_sub_mode);
198 
199 	/* Array of backends */
200 	jw_start_array(jNode, "backend_desc");
201 	for (i=0; i < pool_config->backend_desc->num_backends; i++)
202 	{
203 		jw_start_object(jNode, "BackendInfo");
204 		jw_put_string(jNode, "backend_hostname",pool_config->backend_desc->backend_info[i].backend_hostname);
205 		jw_put_int(jNode, "backend_port", pool_config->backend_desc->backend_info[i].backend_port);
206 		jw_end_element(jNode);
207 	}
208 	jw_end_element(jNode); /* backend_desc array End */
209 
210 	/* Array of wd_remote_nodes */
211 	jw_start_array(jNode, "wd_remote_nodes");
212 	for (i=0; i < pool_config->wd_remote_nodes.num_wd; i++)
213 	{
214 		jw_start_object(jNode, "WdRemoteNodesConfig");
215 		jw_put_string(jNode, "hostname",pool_config->wd_remote_nodes.wd_remote_node_info[i].hostname);
216 		jw_put_int(jNode, "wd_port", pool_config->wd_remote_nodes.wd_remote_node_info[i].wd_port);
217 		jw_put_int(jNode, "pgpool_port", pool_config->wd_remote_nodes.wd_remote_node_info[i].pgpool_port);
218 		jw_end_element(jNode);
219 	}
220 	jw_end_element(jNode); /* wd_remote_nodes array End */
221 
222 	jw_finish_document(jNode);
223 	json_str = pstrdup(jw_get_json_string(jNode));
224 	jw_destroy(jNode);
225 	return json_str;
226 }
227 
228 /* The function returns the simple JSON string that contains
229  * only one KEY,VALUE along with the authkey key value if provided
230  */
get_simple_request_json(char * key,char * value,unsigned int sharedKey,char * authKey)231 char* get_simple_request_json(char *key, char* value, unsigned int sharedKey, char* authKey)
232 {
233 	char* json_str;
234 
235 	JsonNode* jNode = jw_create_with_object(true);
236 
237 	jw_put_int(jNode, WD_IPC_SHARED_KEY, sharedKey); /* put the shared key*/
238 
239 	if (authKey != NULL && strlen(authKey) > 0)
240 		jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /*  put the auth key*/
241 
242 	jw_put_string(jNode, key, value);
243 	jw_finish_document(jNode);
244 	json_str = pstrdup(jw_get_json_string(jNode));
245 	jw_destroy(jNode);
246 	return json_str;
247 }
248 
get_data_request_json(char * request_type,unsigned int sharedKey,char * authKey)249 char* get_data_request_json(char* request_type, unsigned int sharedKey, char* authKey)
250 {
251 	return get_simple_request_json(WD_JSON_KEY_DATA_REQ_TYPE, request_type, sharedKey, authKey);
252 }
253 
parse_data_request_json(char * json_data,int data_len,char ** request_type)254 bool parse_data_request_json(char* json_data, int data_len, char** request_type)
255 {
256 	json_value *root;
257 	char* ptr;
258 
259 	*request_type = NULL;
260 
261 	root = json_parse(json_data,data_len);
262 
263 	/* The root node must be object */
264 	if (root == NULL || root->type != json_object)
265 	{
266 		json_value_free(root);
267 		ereport(LOG,
268 			(errmsg("watchdog is unable to parse data request json"),
269 				 errdetail("invalid json data \"%s\"",json_data)));
270 		return false;
271 	}
272 	ptr = json_get_string_value_for_key(root, WD_JSON_KEY_DATA_REQ_TYPE);
273 	if (ptr == NULL)
274 	{
275 		json_value_free(root);
276 		ereport(LOG,
277 			(errmsg("watchdog is unable to parse data request json"),
278 				 errdetail("request name node not found in json data \"%s\"",json_data)));
279 		return false;
280 	}
281 	*request_type = pstrdup(ptr);
282 	json_value_free(root);
283 	return true;
284 }
285 
286 
287 /* The function reads the backend node status from shared memory
288  * and creates a json packet from it
289  */
get_backend_node_status_json(WatchdogNode * wdNode)290 char* get_backend_node_status_json(WatchdogNode* wdNode)
291 {
292 	int i;
293 	char* json_str;
294 	JsonNode* jNode = jw_create_with_object(true);
295 
296 	jw_start_array(jNode, "BackendNodeStatusList");
297 
298 	for (i=0;i< pool_config->backend_desc->num_backends;i++)
299 	{
300 		BACKEND_STATUS backend_status = pool_config->backend_desc->backend_info[i].backend_status;
301 		jw_put_int_value(jNode, backend_status);
302 	}
303 	/* put the primary node id */
304 	jw_end_element(jNode);
305 	jw_put_int(jNode, "PrimaryNodeId", Req_info->primary_node_id);
306 	jw_put_string(jNode, "NodeName",wdNode->nodeName);
307 
308 	jw_finish_document(jNode);
309 	json_str = pstrdup(jw_get_json_string(jNode));
310 	jw_destroy(jNode);
311 	return json_str;
312 }
313 
get_pg_backend_node_status_from_json(char * json_data,int data_len)314 WDPGBackendStatus* get_pg_backend_node_status_from_json(char* json_data, int data_len)
315 {
316 	json_value *root = NULL;
317 	json_value *value = NULL;
318 	char *ptr;
319 	int i;
320 	WDPGBackendStatus* backendStatus = NULL;
321 
322 	root = json_parse(json_data,data_len);
323 	/* The root node must be object */
324 	if (root == NULL || root->type != json_object)
325 		return NULL;
326 
327 	/* backend status array */
328 	value = json_get_value_for_key(root,"BackendNodeStatusList");
329 	if (value == NULL || value->type != json_array)
330 		return NULL;
331 
332 	if (value->u.array.length <=0 || value->u.array.length > MAX_NUM_BACKENDS )
333 		return NULL;
334 
335 	backendStatus = palloc(sizeof(WDPGBackendStatus));
336 	backendStatus->node_count = value->u.array.length;
337 
338 	for (i = 0; i < backendStatus->node_count; i++)
339 	{
340 		backendStatus->backend_status[i] = value->u.array.values[i]->u.integer;
341 	}
342 
343 	if (json_get_int_value_for_key(root, "PrimaryNodeId", &backendStatus->primary_node_id))
344 	{
345 		ereport(ERROR,
346 			(errmsg("invalid json data"),
347 				 errdetail("unable to find Watchdog Node ID")));
348 	}
349 
350 	ptr = json_get_string_value_for_key(root, "NodeName");
351 	if (ptr)
352 	{
353 		strncpy(backendStatus->nodeName, ptr, sizeof(backendStatus->nodeName) -1);
354 	}
355 	else
356 	{
357 		backendStatus->nodeName[0] = 0;
358 	}
359 
360 	return backendStatus;
361 }
362 
get_beacon_message_json(WatchdogNode * wdNode)363 char* get_beacon_message_json(WatchdogNode* wdNode)
364 {
365 	char* json_str;
366 	struct timeval current_time;
367 	long seconds_since_current_state;
368 	long seconds_since_node_startup;
369 
370 	gettimeofday(&current_time,NULL);
371 
372 	seconds_since_current_state = WD_TIME_DIFF_SEC(current_time, wdNode->current_state_time);
373 	seconds_since_node_startup = WD_TIME_DIFF_SEC(current_time, wdNode->startup_time);
374 
375 	JsonNode* jNode = jw_create_with_object(true);
376 
377 	jw_put_int(jNode, "State", wdNode->state);
378 	jw_put_long(jNode, "SecondsSinceStartup", seconds_since_node_startup);
379 	jw_put_long(jNode, "SecondsSinceCurrentState", seconds_since_current_state);
380 	jw_put_int(jNode, "QuorumStatus", wdNode->quorum_status);
381 	jw_put_int(jNode, "AliveNodeCount", wdNode->standby_nodes_count);
382 	jw_put_bool(jNode, "Escalated", wdNode->escalated == 0?false:true);
383 
384 	jw_finish_document(jNode);
385 	json_str = pstrdup(jw_get_json_string(jNode));
386 	jw_destroy(jNode);
387 	return json_str;
388 }
389 
get_watchdog_node_info_json(WatchdogNode * wdNode,char * authkey)390 char* get_watchdog_node_info_json(WatchdogNode* wdNode, char* authkey)
391 {
392 	char* json_str;
393 	long seconds_since_current_state;
394 	long seconds_since_node_startup;
395 	struct timeval current_time;
396 
397 	gettimeofday(&current_time,NULL);
398 
399 	seconds_since_current_state = WD_TIME_DIFF_SEC(current_time, wdNode->current_state_time);
400 	seconds_since_node_startup = WD_TIME_DIFF_SEC(current_time, wdNode->startup_time);
401 
402 	JsonNode* jNode = jw_create_with_object(true);
403 
404 	jw_put_string(jNode, "PGPOOL_VERSION", VERSION);
405 	jw_put_string(jNode, "DATA_VERSION_MAJOR", WD_MESSAGE_DATA_VERSION_MAJOR);
406 	jw_put_string(jNode, "DATA_VERSION_MINOR", WD_MESSAGE_DATA_VERSION_MINOR);
407 
408 	jw_put_int(jNode, "State", wdNode->state);
409 	jw_put_int(jNode, "WdPort", wdNode->wd_port);
410 	jw_put_int(jNode, "PgpoolPort", wdNode->pgpool_port);
411 	jw_put_int(jNode, "WdPriority", wdNode->wd_priority);
412 
413 	jw_put_string(jNode, "NodeName",wdNode->nodeName);
414 	jw_put_string(jNode, "HostName",wdNode->hostname);
415 	jw_put_string(jNode, "VIP",wdNode->delegate_ip);
416 
417 	jw_put_long(jNode, "SecondsSinceStartup", seconds_since_node_startup);
418 	jw_put_long(jNode, "SecondsSinceCurrentState", seconds_since_current_state);
419 	jw_put_int(jNode, "QuorumStatus", wdNode->quorum_status);
420 	jw_put_int(jNode, "AliveNodeCount", wdNode->standby_nodes_count);
421 	jw_put_bool(jNode, "Escalated", wdNode->escalated == 0?false:true);
422 
423 	if(authkey)
424 		jw_put_string(jNode, "authkey",authkey);
425 
426 	jw_finish_document(jNode);
427 	json_str = pstrdup(jw_get_json_string(jNode));
428 	jw_destroy(jNode);
429 	return json_str;
430 
431 }
432 
get_watchdog_node_from_json(char * json_data,int data_len,char ** authkey)433 WatchdogNode* get_watchdog_node_from_json(char* json_data, int data_len, char** authkey)
434 {
435 	json_value *root = NULL;
436 	char* ptr;
437 	WatchdogNode* wdNode = palloc0(sizeof(WatchdogNode));
438 
439 	root = json_parse(json_data,data_len);
440 	/* The root node must be object */
441 	if (root == NULL || root->type != json_object)
442 		goto ERROR_EXIT;
443 
444 	if (json_get_long_value_for_key(root, "StartupTimeSecs", &wdNode->startup_time.tv_sec))
445 	{
446 		bool escalated;
447 		long seconds_since_node_startup;
448 		long seconds_since_current_state;
449 		struct timeval current_time;
450 
451 		gettimeofday(&current_time,NULL);
452 
453 		/*The new version does not have StartupTimeSecs Key */
454 		if (json_get_long_value_for_key(root, "SecondsSinceStartup", &seconds_since_node_startup))
455 			goto ERROR_EXIT;
456 		if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", &seconds_since_current_state))
457 			goto ERROR_EXIT;
458 		if (json_get_bool_value_for_key(root, "Escalated", &escalated))
459 			goto ERROR_EXIT;
460 		if (json_get_int_value_for_key(root, "QuorumStatus", &wdNode->quorum_status))
461 			goto ERROR_EXIT;
462 		if (json_get_int_value_for_key(root, "AliveNodeCount", &wdNode->standby_nodes_count))
463 			goto ERROR_EXIT;
464 
465 		if (escalated)
466 			wdNode->escalated = 1;
467 		else
468 			wdNode->escalated = 0;
469 
470 		/* create the time */
471 		wdNode->current_state_time.tv_sec = current_time.tv_sec - seconds_since_current_state;
472 		wdNode->startup_time.tv_sec = current_time.tv_sec - seconds_since_node_startup;
473 		wdNode->current_state_time.tv_usec = wdNode->startup_time.tv_usec = 0;
474 	}
475 	else
476 	{
477 		/* we do this to know that we got the info from older version*/
478 		wdNode->current_state_time.tv_sec = 0;
479 	}
480 
481 	if (json_get_int_value_for_key(root, "State", (int*)&wdNode->state))
482 		goto ERROR_EXIT;
483 	if (json_get_int_value_for_key(root, "WdPort", &wdNode->wd_port))
484 		goto ERROR_EXIT;
485 	if (json_get_int_value_for_key(root, "PgpoolPort", &wdNode->pgpool_port))
486 		goto ERROR_EXIT;
487 	if (json_get_int_value_for_key(root, "WdPriority", &wdNode->wd_priority))
488 		goto ERROR_EXIT;
489 
490 
491 	ptr = json_get_string_value_for_key(root, "NodeName");
492 	if (ptr == NULL)
493 		goto ERROR_EXIT;
494 	strncpy(wdNode->nodeName, ptr, sizeof(wdNode->nodeName) -1);
495 
496 	ptr = json_get_string_value_for_key(root, "HostName");
497 	if (ptr == NULL)
498 		goto ERROR_EXIT;
499 	strncpy(wdNode->hostname, ptr, sizeof(wdNode->hostname) -1);
500 
501 	ptr = json_get_string_value_for_key(root, "VIP");
502 	if (ptr == NULL)
503 		goto ERROR_EXIT;
504 	strncpy(wdNode->delegate_ip, ptr, sizeof(wdNode->delegate_ip) -1);
505 
506 	ptr = json_get_string_value_for_key(root, "DATA_VERSION_MAJOR");
507 	if (ptr == NULL)
508 		wdNode->wd_data_major_version = 1;
509 	else
510 		wdNode->wd_data_major_version = atoi(ptr);
511 
512 	ptr = json_get_string_value_for_key(root, "DATA_VERSION_MINOR");
513 	if (ptr == NULL)
514 		wdNode->wd_data_minor_version = 0;
515 	else
516 		wdNode->wd_data_minor_version = atoi(ptr);
517 
518 	ptr = json_get_string_value_for_key(root, "PGPOOL_VERSION");
519 	if (ptr != NULL)
520 		strncpy(wdNode->pgp_version, ptr, sizeof(wdNode->pgp_version) - 1);
521 	else
522 		wdNode->pgp_version[0] = '0';
523 
524 	if (authkey)
525 	{
526 		ptr = json_get_string_value_for_key(root, "authkey");
527 		if (ptr != NULL)
528 			*authkey = pstrdup(ptr);
529 		else
530 			*authkey = NULL;
531 	}
532 
533 	return wdNode;
534 
535 	ERROR_EXIT:
536 	if (root)
537 		json_value_free(root);
538 	pfree(wdNode);
539 	return NULL;
540 }
541 
parse_beacon_message_json(char * json_data,int data_len,int * state,long * seconds_since_node_startup,long * seconds_since_current_state,int * quorumStatus,int * standbyNodesCount,bool * escalated)542 bool parse_beacon_message_json(char* json_data, int data_len,
543 							   int* state,
544 							   long* seconds_since_node_startup,
545 							   long* seconds_since_current_state,
546 							   int* quorumStatus,
547 							   int* standbyNodesCount,
548 							   bool* escalated)
549 {
550 	json_value *root = NULL;
551 
552 	root = json_parse(json_data,data_len);
553 	/* The root node must be object */
554 	if (root == NULL || root->type != json_object)
555 		goto ERROR_EXIT;
556 
557 	if (json_get_int_value_for_key(root, "State", state))
558 		goto ERROR_EXIT;
559 	if (json_get_long_value_for_key(root, "SecondsSinceStartup", seconds_since_node_startup))
560 		goto ERROR_EXIT;
561 	if (json_get_long_value_for_key(root, "SecondsSinceCurrentState", seconds_since_current_state))
562 		goto ERROR_EXIT;
563 	if (json_get_bool_value_for_key(root, "Escalated", escalated))
564 		goto ERROR_EXIT;
565 	if (json_get_int_value_for_key(root, "QuorumStatus", quorumStatus))
566 		goto ERROR_EXIT;
567 	if (json_get_int_value_for_key(root, "AliveNodeCount", standbyNodesCount))
568 		goto ERROR_EXIT;
569 
570 	if (root)
571 		json_value_free(root);
572 
573 	return true;
574 
575 ERROR_EXIT:
576 	if (root)
577 		json_value_free(root);
578 	return false;
579 }
580 
get_lifecheck_node_status_change_json(int nodeID,int nodeStatus,char * message,char * authKey)581 char* get_lifecheck_node_status_change_json(int nodeID, int nodeStatus, char* message, char* authKey)
582 {
583 	char* json_str;
584 	JsonNode* jNode = jw_create_with_object(true);
585 
586 	if (authKey != NULL && strlen(authKey) > 0)
587 		jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /*  put the auth key*/
588 
589 	/* add the node ID */
590 	jw_put_int(jNode, "NodeID", nodeID);
591 	/* add the node status */
592 	jw_put_int(jNode, "NodeStatus",nodeStatus);
593 	/* add the node message if any */
594 	if (message)
595 		jw_put_string(jNode, "Message", message);
596 
597 	jw_finish_document(jNode);
598 	json_str = pstrdup(jw_get_json_string(jNode));
599 	jw_destroy(jNode);
600 	return json_str;
601 }
602 
parse_node_status_json(char * json_data,int data_len,int * nodeID,int * nodeStatus,char ** message)603 bool parse_node_status_json(char* json_data, int data_len, int* nodeID, int* nodeStatus, char** message)
604 {
605 	json_value* root;
606 	char* ptr = NULL;
607 	root = json_parse(json_data,data_len);
608 
609 	/* The root node must be object */
610 	if (root == NULL || root->type != json_object)
611 		goto ERROR_EXIT;
612 
613 	if (json_get_int_value_for_key(root, "NodeID", nodeID))
614 		goto ERROR_EXIT;
615 
616 	if (json_get_int_value_for_key(root, "NodeStatus", nodeStatus))
617 		goto ERROR_EXIT;
618 
619 	ptr = json_get_string_value_for_key(root, "Message");
620 	if (ptr != NULL)
621 		*message = pstrdup(ptr);
622 
623 	json_value_free(root);
624 	return true;
625 
626 ERROR_EXIT:
627 	if (root)
628 		json_value_free(root);
629 	return false;
630 }
631 
get_WDNodeInfo_from_wd_node_json(json_value * source)632 WDNodeInfo* get_WDNodeInfo_from_wd_node_json(json_value* source)
633 {
634 	char* ptr;
635 	WDNodeInfo* wdNodeInfo = palloc0(sizeof(WDNodeInfo));
636 	if (source->type != json_object)
637 		ereport(ERROR,
638 			(errmsg("invalid json data"),
639 				 errdetail("node is not of object type")));
640 
641 	if (json_get_int_value_for_key(source, "ID", &wdNodeInfo->id))
642 	{
643 		ereport(ERROR,
644 			(errmsg("invalid json data"),
645 				 errdetail("unable to find Watchdog Node ID")));
646 	}
647 
648 	ptr = json_get_string_value_for_key(source, "NodeName");
649 	if (ptr == NULL)
650 	{
651 		ereport(ERROR,
652 			(errmsg("invalid json data"),
653 				 errdetail("unable to find Watchdog Node Name")));
654 	}
655 	strncpy(wdNodeInfo->nodeName, ptr, sizeof(wdNodeInfo->nodeName) -1);
656 
657 	ptr = json_get_string_value_for_key(source, "HostName");
658 	if (ptr == NULL)
659 	{
660 		ereport(ERROR,
661 			(errmsg("invalid json data"),
662 				 errdetail("unable to find Watchdog Host Name")));
663 	}
664 	strncpy(wdNodeInfo->hostName, ptr, sizeof(wdNodeInfo->hostName) -1);
665 
666 	ptr = json_get_string_value_for_key(source, "DelegateIP");
667 	if (ptr == NULL)
668 	{
669 		ereport(ERROR,
670 			(errmsg("invalid json data"),
671 				 errdetail("unable to find Watchdog delegate IP")));
672 	}
673 	strncpy(wdNodeInfo->delegate_ip, ptr, sizeof(wdNodeInfo->delegate_ip) -1);
674 
675 	if (json_get_int_value_for_key(source, "WdPort", &wdNodeInfo->wd_port))
676 	{
677 		ereport(ERROR,
678 				(errmsg("invalid json data"),
679 				 errdetail("unable to find WdPort")));
680 	}
681 
682 	if (json_get_int_value_for_key(source, "PgpoolPort", &wdNodeInfo->pgpool_port))
683 	{
684 		ereport(ERROR,
685 				(errmsg("invalid json data"),
686 				 errdetail("unable to find PgpoolPort")));
687 	}
688 
689 	if (json_get_int_value_for_key(source, "State", &wdNodeInfo->state))
690 	{
691 		ereport(ERROR,
692 				(errmsg("invalid json data"),
693 				 errdetail("unable to find state")));
694 	}
695 
696 	ptr = json_get_string_value_for_key(source, "StateName");
697 	if (ptr == NULL)
698 	{
699 		ereport(ERROR,
700 			(errmsg("invalid json data"),
701 				 errdetail("unable to find Watchdog State Name")));
702 	}
703 	strncpy(wdNodeInfo->stateName, ptr, sizeof(wdNodeInfo->stateName) -1);
704 
705 	if (json_get_int_value_for_key(source, "Priority", &wdNodeInfo->wd_priority))
706 	{
707 		ereport(ERROR,
708 				(errmsg("invalid json data"),
709 				 errdetail("unable to find state")));
710 	}
711 
712 	return wdNodeInfo;
713 
714 }
715 
get_wd_node_function_json(char * func_name,int * node_id_set,int count,unsigned int sharedKey,char * authKey)716 char* get_wd_node_function_json(char* func_name, int *node_id_set, int count, unsigned int sharedKey, char* authKey)
717 {
718 	char* json_str;
719 	int  i;
720 	JsonNode* jNode = jw_create_with_object(true);
721 
722 	jw_put_int(jNode, WD_IPC_SHARED_KEY, sharedKey); /* put the shared key*/
723 
724 	if (authKey != NULL && strlen(authKey) > 0)
725 		jw_put_string(jNode, WD_IPC_AUTH_KEY, authKey); /*  put the auth key*/
726 
727 	jw_put_string(jNode, "Function", func_name);
728 	jw_put_int(jNode, "NodeCount", count);
729 	if (count > 0)
730 	{
731 		jw_start_array(jNode, "NodeIdList");
732 		for (i=0; i < count; i++) {
733 			jw_put_int_value(jNode, node_id_set[i]);
734 		}
735 		jw_end_element(jNode);
736 	}
737 	jw_finish_document(jNode);
738 	json_str = pstrdup(jw_get_json_string(jNode));
739 	jw_destroy(jNode);
740 	return json_str;
741 }
742 
parse_wd_node_function_json(char * json_data,int data_len,char ** func_name,int ** node_id_set,int * count)743 bool parse_wd_node_function_json(char* json_data, int data_len, char** func_name, int **node_id_set, int *count)
744 {
745 	json_value *root, *value;
746 	char* ptr;
747 	int node_count = 0;
748 	int i;
749 
750 	*node_id_set = NULL;
751 	*func_name = NULL;
752 	*count = 0;
753 
754 	root = json_parse(json_data,data_len);
755 
756 	/* The root node must be object */
757 	if (root == NULL || root->type != json_object)
758 	{
759 		json_value_free(root);
760 		ereport(LOG,
761 			(errmsg("watchdog is unable to parse node function json"),
762 				 errdetail("invalid json data \"%.*s\"",data_len,json_data)));
763 		return false;
764 	}
765 	ptr = json_get_string_value_for_key(root, "Function");
766 	if (ptr == NULL)
767 	{
768 		json_value_free(root);
769 		ereport(LOG,
770 			(errmsg("watchdog is unable to parse node function json"),
771 				 errdetail("function node not found in json data \"%s\"",json_data)));
772 		return false;
773 	}
774 	*func_name = pstrdup(ptr);
775 	/* If it is a node function ?*/
776 	if (json_get_int_value_for_key(root, "NodeCount", &node_count))
777 	{
778 		/*node count not found, But we don't care much about this*/
779 		json_value_free(root);
780 		return true;
781 	}
782 	if (node_count <= 0)
783 	{
784 		json_value_free(root);
785 		return true;
786 	}
787 	*count = node_count;
788 
789 	value = json_get_value_for_key(root,"NodeIdList");
790 	if (value == NULL)
791 	{
792 		json_value_free(root);
793 		ereport(LOG,
794 			(errmsg("invalid json data"),
795 				 errdetail("unable to find NodeIdList node from data")));
796 		return false;
797 	}
798 	if (value->type != json_array)
799 	{
800 		json_value_free(root);
801 		ereport(WARNING,
802 				(errmsg("invalid json data"),
803 				 errdetail("NodeIdList node does not contains Array")));
804 		return false;
805 	}
806 	if (node_count != value->u.array.length)
807 	{
808 		json_value_free(root);
809 		ereport(WARNING,
810 				(errmsg("invalid json data"),
811 				 errdetail("NodeIdList array contains %d nodes while expecting %d",value->u.array.length, node_count)));
812 		return false;
813 	}
814 
815 	*node_id_set = palloc(sizeof(int) * node_count);
816 	for (i = 0; i < node_count; i++)
817 	{
818 		*node_id_set[i] = value->u.array.values[i]->u.integer;
819 	}
820 	json_value_free(root);
821 	return true;
822 }
823 
get_wd_simple_message_json(char * message)824 char* get_wd_simple_message_json(char* message)
825 {
826 	char* json_str;
827 	JsonNode* jNode = jw_create_with_object(true);
828 
829 	jw_put_string(jNode, "MESSAGE", message);
830 	jw_finish_document(jNode);
831 	json_str = pstrdup(jw_get_json_string(jNode));
832 	jw_destroy(jNode);
833 	return json_str;
834 }
835 
836