1 /*
2  * Intracluster message object (struct ha_msg)
3  *
4  * Copyright (C) 1999, 2000 Alan Robertson <alanr@unix.sh>
5  * This software licensed under the GNU LGPL.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  *
21  */
22 
23 #ifndef _HA_MSG_H
24 #	define _HA_MSG_H 1
25 #include <stdio.h>
26 #include <clplumbing/cl_log.h>
27 #include <clplumbing/ipc.h>
28 #include <clplumbing/longclock.h>
29 #include <clplumbing/cl_uuid.h>
30 #include <compress.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 
35 
36 enum cl_netstring_type{
37 	FT_STRING = 0,
38 	FT_BINARY,
39 	FT_STRUCT,
40 	FT_LIST,
41 	FT_COMPRESS,
42 	FT_UNCOMPRESS
43 };
44 
45 enum cl_msgfmt{
46 	MSGFMT_NVPAIR,
47 	MSGFMT_NETSTRING
48 };
49 
50 
51 #define NEEDHEAD	1
52 #define NOHEAD		0
53 #define HA_MSG_ASSERT(X)  do{  if(!(X)){				\
54 	cl_log(LOG_ERR, "Assertion failed on line %d in file \"%s\""    \
55 	, __LINE__, __FILE__);					         \
56 	abort();		   				         \
57 	}								\
58     }while(0)
59 
60 typedef struct hb_msg_stats_s {
61 	unsigned long		totalmsgs;	/* Total # of messages */
62 						/* ever handled */
63 	unsigned long		allocmsgs;	/* # Msgs currently allocated */
64 	longclock_t		lastmsg;
65 }hb_msg_stats_t;
66 
67 struct ha_msg {
68 	int	nfields;
69 	int	nalloc;
70 	char **	names;
71 	size_t* nlens;
72 	void **	values;
73 	size_t*	vlens;
74 	int *	types;
75 };
76 
77 typedef struct ha_msg HA_Message;
78 
79 struct fieldtypefuncs_s{
80 
81 	/* memfree frees the memory involved*/
82 	void (*memfree)(void*);
83 
84 	/* dup makes a complete copy of the field*/
85 	void* (*dup)(const void*, size_t);
86 
87 	/* display printout the field*/
88 	void (*display)(int, int, char* , void*, int);
89 
90 	/* add the field into a message*/
91 	int (*addfield) (struct ha_msg* msg, char* name, size_t namelen,
92 			 void* value, size_t vallen, int depth);
93 
94 	/* return the string length required to add this field*/
95 	int (*stringlen) (size_t namlen, size_t vallen, const void* value);
96 
97 	/* return the netstring length required to add this field*/
98 	int (*netstringlen) (size_t namlen, size_t vallen, const void* value);
99 
100 	/* print the field into the provided buffer, convert it first */
101 	/* if ncecessary*/
102 	int (*tostring)(char*, char*, void* ,size_t,int);
103 
104 	/* print the field into the provided buffer*/
105 	int (*tonetstring)(char*, char*, char*, size_t,
106 			   void*, size_t, int, size_t*);
107 
108 	/* convert the given string to a field
109 	   note: this functions involves allocate memory for
110 	   for the field
111 	*/
112 	int (*stringtofield)(void*, size_t, int depth, void**, size_t* );
113 
114 	/* convert the given netstring to a field
115 	   note: this functions involves allocate memory for
116 	   for the field
117 	*/
118 	int (*netstringtofield)(const void*, size_t, void**, size_t*);
119 
120 	/* action before packing*/
121 	int (*prepackaction)(struct ha_msg* m, int index);
122 
123 	/* action before a user get the value of a field*/
124 	int (*pregetaction)(struct ha_msg* m, int index);
125 
126 };
127 
128 #define NUM_MSG_TYPES  6
129 extern struct fieldtypefuncs_s fieldtypefuncs[NUM_MSG_TYPES];
130 
131 #define MSG_NEEDAUTH		0x01
132 #define MSG_ALLOWINTR		0X02
133 #define MSG_NEEDCOMPRESS	0x04
134 #define MSG_NOSIZECHECK		0x08
135 
136 #define	IFACE		"!^!\n"
137 #define	MSG_START	">>>\n"
138 #define	MSG_END		"<<<\n"
139 #define	MSG_START_NETSTRING	"###\n"
140 #define	MSG_END_NETSTRING	"%%%\n"
141 #define	EQUAL		"="
142 
143 #define MAXDEPTH 16     /* Maximum recursive message depth */
144 #define MAXLENGTH	1024
145 
146 	/* Common field names for our messages */
147 #define	F_TYPE		"t"		/* Message type */
148 #define	F_SUBTYPE	"subt"		/* Message type */
149 #define	F_ORIG		"src"		/* Real Originator */
150 #define	F_ORIGUUID	"srcuuid"	/* Real Originator uuid*/
151 #define	F_NODE		"node"		/* Node being described */
152 #define	F_NODELIST	"nodelist"	/* Node list being described */
153 #define	F_DELNODELIST	"delnodelist"	/* Del node list being described */
154 #define	F_TO		"dest"		/* Destination (optional) */
155 #define F_TOUUID	"destuuid"	/* Destination uuid(optional) */
156 #define	F_STATUS	"st"		/* New status (type = status) */
157 #define	F_WEIGHT	"weight"	/* weight of node */
158 #define	F_SITE		"site"		/* site of node */
159 #define F_PROTOCOL	"protocol"	/* Protocol number for communication*/
160 #define	F_CLIENTNAME	"cn"		/* Client name */
161 #define	F_CLIENTSTATUS	"cs"		/* Client status */
162 #define	F_TIME		"ts"		/* Timestamp */
163 #define F_SEQ		"seq"		/* Sequence number */
164 #define	F_LOAD		"ld"		/* Load average */
165 #define	F_COMMENT	"info"		/* Comment */
166 #define	F_TTL		"ttl"		/* Time To Live */
167 #define F_AUTH		"auth"		/* Authentication string */
168 #define F_HBGENERATION	"hg"		/* Heartbeat generation number */
169 #define F_CLIENT_GENERATION "client_gen" /* client generation number*/
170 #define F_FIRSTSEQ	"firstseq"	/* Lowest seq # to retransmit */
171 #define F_LASTSEQ	"lastseq"	/* Highest seq # to retransmit */
172 #define F_RESOURCES	"rsc_hold"	/* What resources do we hold? */
173 #define F_FROMID	"from_id"	/* from Client id */
174 #define F_TOID		"to_id"		/* To client id */
175 #define F_PID		"pid"		/* PID of client */
176 #define F_UID		"uid"		/* uid of client */
177 #define F_GID		"gid"		/* gid of client */
178 #define F_ISSTABLE	"isstable"	/* true/false for RESOURCES */
179 #define F_APIREQ	"reqtype"	/* API request type for "hbapi" */
180 #define F_APIRESULT	"result"	/* API request result code */
181 #define F_IFNAME	"ifname"	/* Interface name */
182 #define F_PNAME		"pname"		/* Parameter name */
183 #define F_PVALUE	"pvalue"	/* Parameter name */
184 #define F_DEADTIME	"deadtime"	/* Dead time interval in ms. */
185 #define F_KEEPALIVE	"keepalive"	/* Keep alive time interval in ms. */
186 #define F_LOGFACILITY	"logfacility"	/* Suggested cluster syslog facility */
187 #define F_NODETYPE	"nodetype"	/* Type of node */
188 #define F_NUMNODES	"numnodes"	/* num of total nodes(excluding ping nodes*/
189 #define F_RTYPE		"rtype"		/* Resource type */
190 #define F_ORDERSEQ	"oseq"		/* Order Sequence number */
191 #define F_DT		"dt"		/* Dead time field for heartbeat*/
192 #define F_ACKSEQ	"ackseq"	/* The seq number this msg is acking*/
193 #define F_CRM_DATA	"crm_xml"
194 #define F_XML_TAGNAME	"__name__"
195 #define F_STATE		"state"		/*used in ccm for state info*/
196 
197 
198 	/* Message types */
199 #define	T_STATUS	"status"	/* Status (heartbeat) */
200 #define	T_IFSTATUS	"ifstat"	/* Interface status */
201 #define	T_ASKRESOURCES	"ask_resources"	/* Let other node ask my resources */
202 #define T_ASKRELEASE	"ip-request"	/* Please give up these resources... */
203 #define T_ACKRELEASE	"ip-request-resp"/* Resources given up... */
204 #define	T_QCSTATUS	"query-cstatus"	/* Query client status */
205 #define	T_RCSTATUS	"respond-cstatus"/* Respond client status */
206 #define	T_STONITH	"stonith"	/* Stonith return code */
207 #define T_SHUTDONE	"shutdone"	/* External Shutdown complete */
208 #define T_CRM		"crmd"		/* Cluster resource manager message */
209 #define T_ATTRD		"attrd"		/* Cluster resource manager message */
210 #define T_ADDNODE	"addnode"	/* Add node message*/
211 #define T_DELNODE	"delnode"	/* Delete node message*/
212 #define T_SETWEIGHT	"setweight"	/* Set node weight*/
213 #define T_SETSITE	"setsite"	/* Set node site*/
214 #define T_REQNODES      "reqnodes"	/* Request node list */
215 #define T_REPNODES	"repnodes"	/* reply node list rquest*/
216 
217 #define T_APIREQ	"hbapi-req"	/* Heartbeat API request */
218 #define T_APIRESP	"hbapi-resp"	/* Heartbeat API response */
219 #define T_APICLISTAT	"hbapi-clstat"	/* Client status notification" */
220 
221 #define	NOSEQ_PREFIX	"NS_"		/* PREFIX: Give no sequence number    */
222 	/* Used for messages which can't be retransmitted		      */
223 	/* Either they're protocol messages or from dumb (ping) endpoints     */
224 #define	T_REXMIT	NOSEQ_PREFIX "rexmit"    	 /* Rexmit request    */
225 #define	T_NAKREXMIT	NOSEQ_PREFIX "nak_rexmit"	/* NAK Rexmit request */
226 #define	T_NS_STATUS	NOSEQ_PREFIX "st"		/* ping status        */
227 #define T_ACKMSG	NOSEQ_PREFIX "ackmsg"		/* ACK message*/
228 
229 /* Messages associated with nice_failback */
230 #define T_STARTING      "starting"      /* Starting Heartbeat		*/
231 					/* (requesting resource report)	*/
232 #define T_RESOURCES	"resource"      /* Resources report		*/
233 
234 /* Messages associated with stonith completion results */
235 #define T_STONITH_OK		"OK"  	  /* stonith completed successfully */
236 #define T_STONITH_BADHOST	"badhost" /* stonith failed */
237 #define T_STONITH_BAD		"bad"	  /* stonith failed */
238 #define T_STONITH_NOTCONFGD	"n_stnth" /* no stonith device configured */
239 #define T_STONITH_UNNEEDED	"unneeded" /* STONITH not required */
240 
241 /* Set up message statistics area */
242 
243 int	netstring_extra(int);
244 int	cl_msg_stats_add(longclock_t time, int size);
245 
246 void	cl_msg_setstats(volatile hb_msg_stats_t* stats);
247 void	cl_dump_msgstats(void);
248 void	cl_set_compression_threshold(size_t threadhold);
249 void	cl_set_traditional_compression(gboolean value);
250 
251 /* Allocate new (empty) message */
252 struct ha_msg *	ha_msg_new(int nfields);
253 
254 /* Free message */
255 void		ha_msg_del(struct ha_msg *msg);
256 
257 /* Copy message */
258 struct ha_msg*	ha_msg_copy(const struct ha_msg *msg);
259 
260 int ha_msg_expand(struct ha_msg* msg );
261 
262 /*Add a null-terminated name and binary value to a message*/
263 int		ha_msg_addbin(struct ha_msg * msg, const char * name,
264 				  const void * value, size_t vallen);
265 
266 int		ha_msg_adduuid(struct ha_msg * msg, const char * name,
267 			       const cl_uuid_t*	uuid);
268 
269 /* Add null-terminated name and a value to the message */
270 int		ha_msg_add(struct ha_msg * msg
271 		,	const char* name, const char* value);
272 
273 int		cl_msg_remove(struct ha_msg* msg, const char* name);
274 int		cl_msg_remove_value(struct ha_msg* msg, const void* value);
275 int		cl_msg_remove_offset(struct ha_msg* msg, int offset);
276 
277 /* Modify null-terminated name and a value to the message */
278 int		cl_msg_modstring(struct ha_msg * msg,
279 			   const char* name,
280 			   const char* value);
281 int		cl_msg_modbin(struct ha_msg * msg,
282 			      const char* name,
283 			      const void* value,
284 			      size_t vlen);
285 
286 int		cl_msg_moduuid(struct ha_msg * msg, const char * name,
287 			       const cl_uuid_t*	uuid);
288 
289 int		cl_msg_modstruct(struct ha_msg * msg,
290 				 const char* name,
291 				 const struct ha_msg* value);
292 #define ha_msg_mod(msg, name, value) cl_msg_modstring(msg, name, value)
293 int	cl_msg_replace(struct ha_msg* msg, int index,
294 			const void* value, size_t vlen, int type);
295 int     cl_msg_replace_value(struct ha_msg* msg, const void *old_value,
296 			     const void* value, size_t vlen, int type);
297 
298 /* Add name, value (with known lengths) to the message */
299 int		ha_msg_nadd(struct ha_msg * msg, const char * name, int namelen
300 		,	const char * value, int vallen);
301 
302 /* Add a name/value/type to a message (with sizes for name and value) */
303 int		ha_msg_nadd_type(struct ha_msg * msg, const char * name, int namelen
304 				 ,	const char * value, int vallen, int type);
305 
306 /* Add name=value string to a message */
307 int		ha_msg_add_nv(struct ha_msg* msg, const char * nvline, const char * bufmax);
308 
309 
310 /* Return value associated with particular name */
311 #define ha_msg_value(m,name) cl_get_string(m, name)
312 
313 /* Call wait(in|out) but only for a finite time */
314 int cl_ipc_wait_timeout(
315     IPC_Channel * chan, int (*waitfun)(IPC_Channel * chan), unsigned int timeout);
316 
317 /* Reads an IPC stream -- converts it into a message */
318 struct ha_msg * msgfromIPC_timeout(IPC_Channel *ch, int flag, unsigned int timeout, int *rc_out);
319 struct ha_msg *	msgfromIPC(IPC_Channel * f, int flag);
320 
321 IPC_Message * ipcmsgfromIPC(IPC_Channel * ch);
322 
323 /* Reads a stream -- converts it into a message */
324 struct ha_msg *	msgfromstream(FILE * f);
325 
326 /* Reads a stream with string format--converts it into a message */
327 struct ha_msg *	msgfromstream_string(FILE * f);
328 
329 /* Reads a stream with netstring format--converts it into a message */
330 struct ha_msg * msgfromstream_netstring(FILE * f);
331 
332 /* Same as above plus copying the iface name to "iface" */
333 struct ha_msg * if_msgfromstream(FILE * f, char *iface);
334 
335 /* Writes a message into a stream */
336 int		msg2stream(struct ha_msg* m, FILE * f);
337 
338 /* Converts a message into a string and adds the iface name on start */
339 char *     msg2if_string(const struct ha_msg *m, const char * iface);
340 
341 /* Converts a string gotten via UDP into a message */
342 struct ha_msg *	string2msg(const char * s, size_t length);
343 
344 /* Converts a message into a string */
345 char *		msg2string(const struct ha_msg *m);
346 
347 /* Converts a message into a string in the provided buffer with certain
348 depth and with or without start/end */
349 int		msg2string_buf(const struct ha_msg *m, char* buf,
350 			       size_t len, int depth, int needhead);
351 
352 /* Converts a message into wire format */
353 char*		msg2wirefmt(struct ha_msg *m, size_t* );
354 char*		msg2wirefmt_noac(struct ha_msg*m, size_t* len);
355 
356 /* Converts wire format data into a message */
357 struct ha_msg*	wirefmt2msg(const char* s, size_t length, int flag);
358 
359 /* Convets wire format data into an IPC message */
360 IPC_Message*	wirefmt2ipcmsg(void* p, size_t len, IPC_Channel* ch);
361 
362 /* Converts an ha_msg into an IPC message */
363 IPC_Message* hamsg2ipcmsg(struct ha_msg* m, IPC_Channel* ch);
364 
365 /* Converts an IPC message into an ha_msg */
366 struct ha_msg* ipcmsg2hamsg(IPC_Message*m);
367 
368 /* Outputs a message to an IPC channel */
369 int msg2ipcchan(struct ha_msg*m, IPC_Channel*ch);
370 
371 /* Outpus a message to an IPC channel without authencating
372 the message */
373 struct ha_msg* msgfromIPC_noauth(IPC_Channel * ch);
374 
375 /* Reads from control fifo, and creates a new message from it */
376 /* This adds the default sequence#, load avg, etc. to the message */
377 struct ha_msg *	controlfifo2msg(FILE * f);
378 
379 /* Check if the message is authenticated */
380 gboolean	isauthentic(const struct ha_msg * msg);
381 
382 /* Get the required string length for the given message */
383 int get_stringlen(const struct ha_msg *m);
384 
385 /* Get the requried netstring length for the given message*/
386 int get_netstringlen(const struct ha_msg *m);
387 
388 /* Add a child message to a message as a field */
389 int ha_msg_addstruct(struct ha_msg * msg, const char * name, const void* ptr);
390 
391 int ha_msg_addstruct_compress(struct ha_msg*, const char*, const void*);
392 
393 /* Get binary data from a message */
394 const void * cl_get_binary(const struct ha_msg *msg, const char * name, size_t * vallen);
395 
396 /* Get uuid data from a message */
397 int cl_get_uuid(const struct ha_msg *msg, const char * name, cl_uuid_t* retval);
398 
399 /* Get string data from a message */
400 const char * cl_get_string(const struct ha_msg *msg, const char *name);
401 
402 /* Get the type for a field from a message */
403 int cl_get_type(const struct ha_msg *msg, const char *name);
404 
405 /* Get a child message from a message*/
406 struct ha_msg *cl_get_struct(struct ha_msg *msg, const char* name);
407 
408 /* Log the contents of a  message */
409 void cl_log_message (int log_level, const struct ha_msg *m);
410 
411 /* Supply messaging system with old style authentication/authorization method */
412 void cl_set_oldmsgauthfunc(gboolean (*authfunc)(const struct ha_msg*));
413 
414 /* Set default messaging format */
415 void cl_set_msg_format(enum cl_msgfmt mfmt);
416 
417 /* Add a string to a list*/
418 int cl_msg_list_add_string(struct ha_msg* msg, const char* name, const char* value);
419 
420 /* Return length of a list*/
421 int cl_msg_list_length(struct ha_msg* msg, const char* name);
422 
423 /* Return nth element of a list*/
424 void* cl_msg_list_nth_data(struct ha_msg* msg, const char* name, int n);
425 
426 /* Functions to add/mod/get an integer */
427 int	ha_msg_add_int(struct ha_msg * msg, const char * name, int value);
428 int	ha_msg_mod_int(struct ha_msg * msg, const char * name, int value);
429 int	ha_msg_value_int(const struct ha_msg * msg, const char * name, int* value);
430 
431 /* Functions to add/mod/get an unsigned long */
432 int	ha_msg_add_ul(struct ha_msg * msg, const char * name, unsigned long value);
433 int	ha_msg_mod_ul(struct ha_msg * msg, const char * name, unsigned long value);
434 int	ha_msg_value_ul(const struct ha_msg * msg, const char * name, unsigned long* value);
435 
436 /* Functions to add/get a string list*/
437 GList*	ha_msg_value_str_list(struct ha_msg * msg, const char * name);
438 
439 int		cl_msg_add_list_int(struct ha_msg* msg, const char* name,
440 				    int* buf, size_t n);
441 int		cl_msg_get_list_int(struct ha_msg* msg, const char* name,
442 				    int* buf, size_t* n);
443 GList*		cl_msg_get_list(struct ha_msg* msg, const char* name);
444 int		cl_msg_add_list(struct ha_msg* msg, const char* name, GList* list);
445 int		cl_msg_add_list_str(struct ha_msg* msg, const char* name,
446 				    char** buf, size_t n);
447 
448 /* Function to add/get a string hash table*/
449 GHashTable*	ha_msg_value_str_table(struct ha_msg * msg, const char * name);
450 int		ha_msg_add_str_table(struct ha_msg * msg, const char * name,
451 				     GHashTable* hash_table);
452 int		ha_msg_mod_str_table(struct ha_msg * msg, const char * name,
453 				     GHashTable* hash_table);
454 
455 /*internal use for list type*/
456 size_t string_list_pack_length(const GList* list);
457 int string_list_pack(GList* list, char* buf, char* maxp);
458 GList* string_list_unpack(const char* packed_str_list, size_t length);
459 void list_cleanup(GList* list);
460 
461 gboolean must_use_netstring(const struct ha_msg*);
462 
463 
464 #endif /* __HA_MSG_H */
465