diff options
Diffstat (limited to 'lib/clplumbing/cl_msg_types.c')
-rw-r--r-- | lib/clplumbing/cl_msg_types.c | 1736 |
1 files changed, 1736 insertions, 0 deletions
diff --git a/lib/clplumbing/cl_msg_types.c b/lib/clplumbing/cl_msg_types.c new file mode 100644 index 0000000..56cf56a --- /dev/null +++ b/lib/clplumbing/cl_msg_types.c @@ -0,0 +1,1736 @@ +/* + * Heartbeat message type functions + * + * Copyright (C) 2004 Guochun Shi <gshi@ncsa.uiuc.edu> + * + * This software licensed under the GNU LGPL. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include <lha_internal.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <time.h> +#include <errno.h> +#include <sys/utsname.h> +#include <ha_msg.h> +#include <unistd.h> +#include <clplumbing/cl_log.h> +#include <clplumbing/ipc.h> +#include <clplumbing/base64.h> +#include <clplumbing/netstring.h> +#include <glib.h> + +#ifndef MAX +# define MAX(a,b) (((a) > (b)) ? (a) : (b)) +#endif + + +extern const char* FT_strings[]; + + + +#define NL_TO_SYM 0 +#define SYM_TO_NL 1 + +static const int SPECIAL_SYMS[MAXDEPTH] = { + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 15, + 16, + 17, + 18, +}; + +#define SPECIAL_SYM 19 + +struct ha_msg* string2msg_ll(const char*, size_t, int, int); +int compose_netstring(char*, const char*, const char*, size_t, size_t*); +int msg2netstring_buf(const struct ha_msg*, char*, size_t, size_t*); +int struct_display_print_spaces(char *buffer, int depth); +int struct_display_as_xml(int log_level, int depth, struct ha_msg *data, + const char *prefix, gboolean formatted); +int struct_stringlen(size_t namlen, size_t vallen, const void* value); +int struct_netstringlen(size_t namlen, size_t vallen, const void* value); +int convert_nl_sym(char* s, int len, char sym, int direction); +int bytes_for_int(int x); + +int +bytes_for_int(int x) +{ + int len = 0; + if(x < 0) { + x = 0-x; + len=1; + } + while(x > 9) { + x /= 10; + len++; + } + return len+1; +} + +int +netstring_extra(int x) +{ + return (bytes_for_int(x) + x + 2); +} + +int +get_netstringlen(const struct ha_msg *m) +{ + int i; + int total_len =0 ; + + if (m == NULL){ + cl_log(LOG_ERR, "get_netstringlen:" + "asking netstringlen of a NULL message"); + return 0; + } + + total_len = sizeof(MSG_START_NETSTRING) + + sizeof(MSG_END_NETSTRING) -2 ; + + + for (i = 0; i < m->nfields; i++){ + int len; + len = fieldtypefuncs[m->types[i]].netstringlen(m->nlens[i], + m->vlens[i], + m->values[i]); + total_len += netstring_extra(len); + } + + + return total_len; + + +} + + + +int +get_stringlen(const struct ha_msg *m) +{ + int i; + int total_len =0 ; + + if (m == NULL){ + cl_log(LOG_ERR, "get_stringlen:" + "asking stringlen of a NULL message"); + return 0; + } + + total_len = sizeof(MSG_START)+sizeof(MSG_END)-1; + + for (i = 0; i < m->nfields; i++){ + total_len += fieldtypefuncs[m->types[i]].stringlen(m->nlens[i], + m->vlens[i], + m->values[i]); + } + + return total_len; +} + + + +/* + compute the total size of the resulted string + if the string list is to be converted + +*/ +size_t +string_list_pack_length(const GList* _list) +{ + size_t i; + GList* list = UNCONST_CAST_POINTER(GList *, _list); + size_t total_length = 0; + + if (list == NULL){ + cl_log(LOG_WARNING, "string_list_pack_length():" + "list is NULL"); + + return 0; + } + for (i = 0; i < g_list_length(list) ; i++){ + + int len = 0; + char * element = g_list_nth_data(list, i); + if (element == NULL){ + cl_log(LOG_ERR, "string_list_pack_length: " + "%luth element of the string list is NULL" + , (unsigned long)i); + return 0; + } + len = strlen(element); + total_length += bytes_for_int(len) + len + 2; + /* 2 is for ":" and "," */ + } + return total_length ; +} + + + +/* + convert a string list into a single string + the format to convert is similar to netstring: + <length> ":" <the actual string> "," + + for example, a list containing two strings "abc" "defg" + will be converted into + 3:abc,4:defg, + @list: the list to be converted + @buf: the converted string should be put in the @buf + @maxp: max pointer +*/ + + +int +string_list_pack(GList* list, char* buf, char* maxp) +{ + size_t i; + char* p = buf; + + for (i = 0; i < g_list_length(list) ; i++){ + char * element = g_list_nth_data(list, i); + int element_len; + + if (element == NULL){ + cl_log(LOG_ERR, "string_list_pack: " + "%luth element of the string list is NULL" + , (unsigned long)i); + return 0; + } + element_len = strlen(element); + if (p + 2 + element_len + bytes_for_int(element_len)> maxp){ + cl_log(LOG_ERR, "%s: memory out of boundary", + __FUNCTION__); + return 0; + } + p += sprintf(p, "%d:%s,", element_len,element); + + if (p > maxp){ + cl_log(LOG_ERR, "string_list_pack: " + "buffer overflowed "); + return 0; + } + } + + + return (p - buf); +} + + + +/* + this is reverse process of pack_string_list +*/ +GList* +string_list_unpack(const char* packed_str_list, size_t length) +{ + GList* list = NULL; + const char* psl = packed_str_list; + const char * maxp= packed_str_list + length; + int len = 0; + + + while(TRUE){ + char* buf; + + if (*psl == '\0' || psl >= maxp){ + break; + } + + if (sscanf( psl, "%d:", &len) <= 0 ){ + break; + } + + if (len <=0){ + cl_log(LOG_ERR, "unpack_string_list:" + "reading len of string error"); + if (list){ + list_cleanup(list); + } + return NULL; + } + + while (*psl != ':' && *psl != '\0' ){ + psl++; + } + + if (*psl == '\0'){ + break; + } + + psl++; + + buf = malloc(len + 1); + if (buf == NULL){ + cl_log(LOG_ERR, "unpack_string_list:" + "unable to allocate buf"); + if(list){ + list_cleanup(list); + } + return NULL; + + } + memcpy(buf, psl, len); + buf[len] = '\0'; + list = g_list_append(list, buf); + psl +=len; + + if (*psl != ','){ + cl_log(LOG_ERR, "unpack_string_list:" + "wrong format, s=%s",packed_str_list); + } + psl++; + } + + return list; + +} + + +static void +string_memfree(void* value) +{ + if (value){ + free(value); + }else { + cl_log(LOG_ERR, "string_memfree: " + "value is NULL"); + } + + + return; +} + +static void +binary_memfree(void* value) +{ + string_memfree(value); +} + + +static void +struct_memfree( void* value) +{ + struct ha_msg* msg; + + if (!value){ + cl_log(LOG_ERR, + "value is NULL"); + return ; + } + + msg = (struct ha_msg*) value; + ha_msg_del(msg); + return ; +} + +static void +list_memfree(void* value) +{ + + if (!value){ + cl_log(LOG_ERR, + "value is NULL"); + return ; + } + + list_cleanup(value); + +} + + +static void* +binary_dup(const void* value, size_t len) +{ + + char* dupvalue; + + /* 0 byte binary field is allowed*/ + + if (value == NULL && len > 0){ + cl_log(LOG_ERR, "binary_dup:" + "NULL value with non-zero len=%d", + (int)len); + return NULL; + } + + dupvalue = malloc(len + 1); + if (dupvalue == NULL){ + cl_log(LOG_ERR, "binary_dup:" + "malloc failed"); + return NULL; + } + + if (value != NULL) { + memcpy(dupvalue, value, len); + } + + dupvalue[len] =0; + + return dupvalue; +} + +static void* +string_dup(const void* value, size_t len) +{ + return binary_dup(value, len); +} + + +static void* +struct_dup(const void* value, size_t len) +{ + char* dupvalue; + + (void)len; + + if (!value){ + cl_log(LOG_ERR,"struct_dup:" + "value is NULL"); + return NULL ; + } + + + dupvalue = (void*)ha_msg_copy((const struct ha_msg*)value); + if (dupvalue == NULL){ + cl_log(LOG_ERR, "struct_dup: " + "ha_msg_copy failed"); + return NULL; + } + + return dupvalue; +} + +static GList* +list_copy(const GList* _list) +{ + size_t i; + GList* newlist = NULL; + GList* list = UNCONST_CAST_POINTER(GList *, _list); + + for (i = 0; i < g_list_length(list); i++){ + char* dup_element = NULL; + char* element = g_list_nth_data(list, i); + int len; + if (element == NULL){ + cl_log(LOG_WARNING, "list_copy:" + "element is NULL"); + continue; + } + + len = strlen(element); + dup_element= malloc(len + 1); + if ( dup_element == NULL){ + cl_log(LOG_ERR, "duplicate element failed"); + continue; + } + memcpy(dup_element, element,len); + dup_element[len] = 0; + + newlist = g_list_append(newlist, dup_element); + } + + return newlist; +} + +static void* +list_dup( const void* value, size_t len) +{ + char* dupvalue; + + (void)len; + if (!value){ + cl_log(LOG_ERR,"struct_dup:" + "value is NULL"); + return NULL ; + } + + dupvalue = (void*)list_copy((const GList*)value); + + if (!dupvalue){ + cl_log(LOG_ERR, "list_dup: " + "list_copy failed"); + return NULL; + } + + return dupvalue; +} + + +static void +general_display(int log_level, int seq, char* name, void* value, int vlen, int type) +{ + int netslen; + int slen; + HA_MSG_ASSERT(value); + HA_MSG_ASSERT(name); + + slen = fieldtypefuncs[type].stringlen(strlen(name), vlen, value); + netslen = fieldtypefuncs[type].netstringlen(strlen(name), vlen, value); + cl_log(log_level, "MSG[%d] : [(%s)%s=%p(%d %d)]", + seq, FT_strings[type], + name, value, slen, netslen); + +} +static void +string_display(int log_level, int seq, char* name, void* value, int vlen) +{ + HA_MSG_ASSERT(name); + HA_MSG_ASSERT(value); + cl_log(log_level, "MSG[%d] : [%s=%s]", + seq, name, (const char*)value); + return; +} + +static void +binary_display(int log_level, int seq, char* name, void* value, int vlen) +{ + general_display(log_level, seq, name, value, vlen, FT_BINARY); +} + +static void +compress_display(int log_level, int seq, char* name, void* value, int vlen){ + general_display(log_level, seq, name, value, vlen, FT_COMPRESS); +} + + +static void +general_struct_display(int log_level, int seq, char* name, void* value, int vlen, int type) +{ + int slen; + int netslen; + + HA_MSG_ASSERT(name); + HA_MSG_ASSERT(value); + + slen = fieldtypefuncs[type].stringlen(strlen(name), vlen, value); + netslen = fieldtypefuncs[type].netstringlen(strlen(name), vlen, value); + + cl_log(log_level, "MSG[%d] : [(%s)%s=%p(%d %d)]", + seq, FT_strings[type], + name, value, slen, netslen); + if(cl_get_string((struct ha_msg*) value, F_XML_TAGNAME) == NULL) { + cl_log_message(log_level, (struct ha_msg*) value); + } else { + /* use a more friendly output format for nested messages */ + struct_display_as_xml(log_level, 0, value, NULL, TRUE); + } +} +static void +struct_display(int log_level, int seq, char* name, void* value, int vlen) +{ + general_struct_display(log_level, seq, name, value, vlen, FT_STRUCT); + +} +static void +uncompress_display(int log_level, int seq, char* name, void* value, int vlen) +{ + general_struct_display(log_level, seq, name, value, vlen, FT_UNCOMPRESS); +} + +#define update_buffer_head(buffer, len) if(len < 0) { \ + (*buffer) = EOS; return -1; \ + } else { \ + buffer += len; \ + } + +int +struct_display_print_spaces(char *buffer, int depth) +{ + int lpc = 0; + int spaces = 2*depth; + /* <= so that we always print 1 space - prevents problems with syslog */ + for(lpc = 0; lpc <= spaces; lpc++) { + if(sprintf(buffer, "%c", ' ') < 1) { + return -1; + } + buffer += 1; + } + return lpc; +} + +int +struct_display_as_xml( + int log_level, int depth, struct ha_msg *data, + const char *prefix, gboolean formatted) +{ + int lpc = 0; + int printed = 0; + gboolean has_children = FALSE; + char print_buffer[1000]; + char *buffer = print_buffer; + const char *name = cl_get_string(data, F_XML_TAGNAME); + + if(data == NULL) { + return 0; + + } else if(name == NULL) { + cl_log(LOG_WARNING, "Struct at depth %d had no name", depth); + cl_log_message(log_level, data); + return 0; + } + + if(formatted) { + printed = struct_display_print_spaces(buffer, depth); + update_buffer_head(buffer, printed); + } + + printed = sprintf(buffer, "<%s", name); + update_buffer_head(buffer, printed); + + for (lpc = 0; lpc < data->nfields; lpc++) { + const char *prop_name = data->names[lpc]; + const char *prop_value = data->values[lpc]; + if(data->types[lpc] != FT_STRING) { + continue; + } else if(prop_name == NULL) { + continue; + } else if(prop_name[0] == '_' && prop_name[1] == '_') { + continue; + } + printed = sprintf(buffer, " %s=\"%s\"", prop_name, prop_value); + update_buffer_head(buffer, printed); + } + + for (lpc = 0; lpc < data->nfields; lpc++) { + if(data->types[lpc] == FT_STRUCT) { + has_children = TRUE; + break; + } + } + + printed = sprintf(buffer, "%s>", has_children==0?"/":""); + update_buffer_head(buffer, printed); + cl_log(log_level, "%s%s", prefix?prefix:"", print_buffer); + buffer = print_buffer; + + if(has_children == FALSE) { + return 0; + } + + for (lpc = 0; lpc < data->nfields; lpc++) { + if(data->types[lpc] != FT_STRUCT) { + continue; + } else if(0 > struct_display_as_xml( + log_level, depth+1, data->values[lpc], + prefix, formatted)) { + return -1; + } + } + + if(formatted) { + printed = struct_display_print_spaces(buffer, depth); + update_buffer_head(buffer, printed); + } + cl_log(log_level, "%s%s</%s>", prefix?prefix:"", print_buffer, name); + + return 0; +} + + + + +static int +liststring(GList* list, char* buf, int maxlen) +{ + char* p = buf; + char* maxp = buf + maxlen; + size_t i; + + for ( i = 0; i < g_list_length(list); i++){ + char* element = g_list_nth_data(list, i); + if (element == NULL) { + cl_log(LOG_ERR, "%luth element is NULL " + , (unsigned long)i); + return HA_FAIL; + } else{ + if (i == 0){ + p += sprintf(p,"%s",element); + }else{ + p += sprintf(p," %s",element); + } + + } + if ( p > maxp){ + cl_log(LOG_ERR, "buffer overflow"); + return HA_FAIL; + } + + } + + return HA_OK; +} + +static void +list_display(int log_level, int seq, char* name, void* value, int vlen) +{ + GList* list; + char buf[MAXLENGTH]; + + HA_MSG_ASSERT(name); + HA_MSG_ASSERT(value); + + list = value; + + if (liststring(list, buf, MAXLENGTH) != HA_OK){ + cl_log(LOG_ERR, "liststring error"); + return; + } + cl_log(log_level, "MSG[%d] :[(%s)%s=%s]", + seq, FT_strings[FT_LIST], + name, buf); + + return ; + +} + + +/* + * This function changes each new line in the input string + * into a special symbol, or the other way around + */ + +int +convert_nl_sym(char* s, int len, char sym, int direction) +{ + int i; + + if (direction != NL_TO_SYM && direction != SYM_TO_NL){ + cl_log(LOG_ERR, "convert_nl_sym(): direction not defined!"); + return(HA_FAIL); + } + + + for (i = 0; i < len && s[i] != EOS; i++){ + + switch(direction){ + case NL_TO_SYM : + if (s[i] == '\n'){ + s[i] = sym; + break; + } + + if (s[i] == sym){ + cl_log(LOG_ERR + , "convert_nl_sym(): special symbol \'0x%x\' (%c) found" + " in string at %d (len=%d)", s[i], s[i], i, len); + i -= 10; + if(i < 0) { + i = 0; + } + cl_log(LOG_ERR, "convert_nl_sym(): %s", s + i); + return(HA_FAIL); + } + + break; + + case SYM_TO_NL: + + if (s[i] == sym){ + s[i] = '\n'; + break; + } + break; + default: + /* nothing, never executed*/; + + } + } + + return(HA_OK); +} + + +/* + * This function changes each new line in the input string + * into a special symbol, or the other way around + */ + +static int +convert(char* s, int len, int depth, int direction) +{ + + if (direction != NL_TO_SYM && direction != SYM_TO_NL){ + cl_log(LOG_ERR, "convert(): direction not defined!"); + return(HA_FAIL); + } + + + if (depth >= MAXDEPTH ){ + cl_log(LOG_ERR, "convert(): MAXDEPTH exceeded: %d", depth); + return(HA_FAIL); + } + + return convert_nl_sym(s, len, SPECIAL_SYMS[depth], direction); +} + + + + +static int +string_stringlen(size_t namlen, size_t vallen, const void* value) +{ + + HA_MSG_ASSERT(value); +/* HA_MSG_ASSERT( vallen == strlen(value)); */ + return namlen + vallen + 2; +} + +static int +binary_netstringlen(size_t namlen, size_t vallen, const void* value) +{ + int length; + + HA_MSG_ASSERT(value); + + length = 3 + namlen + 1 + vallen; + + return length; +} + + +static int +string_netstringlen(size_t namlen, size_t vallen, const void* value) +{ + HA_MSG_ASSERT(value); + HA_MSG_ASSERT( vallen == strlen(value)); + + return binary_netstringlen(namlen, vallen, value); +} + + +static int +binary_stringlen(size_t namlen, size_t vallen, const void* value) +{ + HA_MSG_ASSERT(value); + + return namlen + B64_stringlen(vallen) + 2 + 3; + /*overhead 3 is for type*/ +} + + + + + +int +struct_stringlen(size_t namlen, size_t vallen, const void* value) +{ + const struct ha_msg* childmsg; + + HA_MSG_ASSERT(value); + + (void)vallen; + childmsg = (const struct ha_msg*)value; + + return namlen +2 + 3 + get_stringlen(childmsg); + /*overhead 3 is for type*/ +} + +int +struct_netstringlen(size_t namlen, size_t vallen, const void* value) +{ + + int ret; + const struct ha_msg* childmsg; + int len; + + HA_MSG_ASSERT(value); + + (void)vallen; + childmsg = (const struct ha_msg*)value; + + len = get_netstringlen(childmsg); + + ret = 3 + namlen + 1 + len; + + return ret; + +} + + +static int +list_stringlen(size_t namlen, size_t vallen, const void* value) +{ + (void)value; + return namlen + vallen + 2 + 3; + /*overhead 3 is for type (FT_STRUCT)*/ +} + +static int +list_netstringlen(size_t namlen, size_t vallen, const void* value) +{ + int ret; + const GList* list; + + list = (const GList*)value; + + ret = 3 + namlen + 1 + string_list_pack_length(list); + + return ret; + +} + +static int +add_binary_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + + int next; + + if ( !msg || !name || !value + || depth < 0){ + cl_log(LOG_ERR, "add_binary_field:" + " invalid input argument"); + return HA_FAIL; + } + + + next = msg->nfields; + msg->names[next] = name; + msg->nlens[next] = namelen; + msg->values[next] = value; + msg->vlens[next] = vallen; + msg->types[next] = FT_BINARY; + msg->nfields++; + + return HA_OK; +} + + +static int +add_struct_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + int next; + + if ( !msg || !name || !value + || depth < 0){ + cl_log(LOG_ERR, "add_struct_field:" + " invalid input argument"); + return HA_FAIL; + } + + next = msg->nfields; + msg->names[next] = name; + msg->nlens[next] = namelen; + msg->values[next] = value; + msg->vlens[next] = vallen; + msg->types[next] = FT_STRUCT; + + msg->nfields++; + + return HA_OK; +} + + + + +static int +add_list_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + int next; + int j; + GList* list = NULL; + + if ( !msg || !name || !value + || namelen <= 0 + || vallen <= 0 + || depth < 0){ + cl_log(LOG_ERR, "add_list_field:" + " invalid input argument"); + return HA_FAIL; + } + + + for (j=0; j < msg->nfields; ++j) { + if (strcmp(name, msg->names[j]) == 0) { + break; + } + } + + if ( j >= msg->nfields){ + list = (GList*)value; + + next = msg->nfields; + msg->names[next] = name; + msg->nlens[next] = namelen; + msg->values[next] = value; + msg->vlens[next] = vallen; + msg->types[next] = FT_LIST; + msg->nfields++; + + } else if( msg->types[j] == FT_LIST ){ + + GList* oldlist = (GList*) msg->values[j]; + int listlen; + size_t i; + + for ( i =0; i < g_list_length((GList*)value); i++){ + list = g_list_append(oldlist, g_list_nth_data((GList*)value, i)); + } + if (list == NULL){ + cl_log(LOG_ERR, "add_list_field:" + " g_list_append() failed"); + return HA_FAIL; + } + + listlen = string_list_pack_length(list); + + msg->values[j] = list; + msg->vlens[j] = listlen; + g_list_free((GList*)value); /*we don't free each element + because they are used in new list*/ + free(name); /* this name is no longer necessary + because msg->names[j] is reused */ + + } else { + cl_log(LOG_ERR, "field already exists " + "with differnt type=%d", msg->types[j]); + return (HA_FAIL); + } + + return HA_OK; +} + + +static int +add_compress_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + + int next; + + if ( !msg || !name || !value + || depth < 0){ + cl_log(LOG_ERR, "add_binary_field:" + " invalid input argument"); + return HA_FAIL; + } + + + next = msg->nfields; + msg->names[next] = name; + msg->nlens[next] = namelen; + msg->values[next] = value; + msg->vlens[next] = vallen; + msg->types[next] = FT_COMPRESS; + msg->nfields++; + + return HA_OK; +} + + + + +static int +add_uncompress_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + int next; + + if ( !msg || !name || !value + || depth < 0){ + cl_log(LOG_ERR, "add_struct_field:" + " invalid input argument"); + return HA_FAIL; + } + + next = msg->nfields; + msg->names[next] = name; + msg->nlens[next] = namelen; + msg->values[next] = value; + msg->vlens[next] = vallen; + msg->types[next] = FT_UNCOMPRESS; + + msg->nfields++; + + return HA_OK; +} + + + +/*print a string to a string, + pretty simple one :) +*/ +static int +str2string(char* buf, char* maxp, void* value, size_t len, int depth) +{ + char* s = value; + char* p = buf; + (void)maxp; + (void)depth; + + if (buf + len > maxp){ + cl_log(LOG_ERR, "%s: out of boundary", + __FUNCTION__); + return -1; + } + + if ( strlen(s) != len){ + cl_log(LOG_ERR, "str2string:" + "the input len != string length"); + return -1; + } + + strcat(buf, s); + while(*p != '\0'){ + if (*p == '\n'){ + *p = SPECIAL_SYM; + } + p++; + } + + return len; + +} + +/*print a binary value to a string using base64 + library +*/ + +static int +binary2string(char* buf, char* maxp, void* value, size_t len, int depth) +{ + int baselen; + int truelen = 0; + + (void)depth; + baselen = B64_stringlen(len) + 1; + + if ( buf + baselen > maxp){ + cl_log(LOG_ERR, "binary2string: out of bounary"); + return -1; + } + + truelen = binary_to_base64(value, len, buf, baselen); + + return truelen; +} + +/*print a struct(ha_msg) to a string + @depth denotes the number of recursion +*/ + +static int +struct2string(char* buf, char* maxp, void* value, size_t len, int depth) +{ + + struct ha_msg* msg = value; + int baselen = get_stringlen(msg); + + (void)len; + + if ( buf + baselen > maxp){ + cl_log(LOG_ERR, "struct2string: not enough buffer" + "for the struct to generate a string"); + return -1; + } + + if (msg2string_buf(msg, buf ,baselen,depth + 1, NEEDHEAD) + != HA_OK){ + + cl_log(LOG_ERR + , "struct2string(): msg2string_buf for" + " child message failed"); + return -1; + + } + + if (convert(buf, baselen, depth, NL_TO_SYM) != HA_OK){ + cl_log(LOG_ERR , "struct2string(): convert failed"); + return -1; + } + + return strlen(buf); +} + + + + +/* print a list to a string + */ + +static int +list2string(char* buf, char* maxp, void* value, size_t len, int depth) +{ + int listlen; + GList* list = (GList*) value; + + (void)len; + (void)depth; + listlen = string_list_pack(list , buf, maxp); + if (listlen == 0){ + cl_log(LOG_ERR, "list2string():" + "string_list_pack() failed"); + return -1; + } + + return listlen; + +} + + +static int +string2str(void* value, size_t len, int depth, void** nv, size_t* nlen ) +{ + if (!value || !nv || !nlen || depth < 0){ + cl_log(LOG_ERR, "string2str:invalid input"); + return HA_FAIL; + } + + if (convert_nl_sym(value, len, SPECIAL_SYM, SYM_TO_NL) != HA_OK){ + cl_log(LOG_ERR, "string2str:convert_nl_sym" + "from symbol to new line failed"); + return HA_FAIL; + } + *nv = value; + *nlen = len; + + return HA_OK; +} + +static int +string2binary(void* value, size_t len, int depth, void** nv, size_t* nlen) +{ + char tmpbuf[MAXLINE]; + char* buf = NULL; + int buf_malloced = 0; + int ret = HA_FAIL; + if (len > MAXLINE){ + buf = malloc(len); + if (buf == NULL){ + cl_log(LOG_ERR, "%s: malloc failed", + __FUNCTION__); + goto out; + } + buf_malloced = 1; + }else { + buf = &tmpbuf[0]; + } + + if (value == NULL && len == 0){ + *nv = NULL; + *nlen = 0; + ret = HA_OK; + goto out; + } + + if ( !value || !nv || depth < 0){ + cl_log(LOG_ERR, "string2binary:invalid input"); + ret = HA_FAIL; + goto out; + } + + memcpy(buf, value, len); + *nlen = base64_to_binary(buf, len, value, len); + + *nv = value; + ret = HA_OK; + out: + if (buf_malloced && buf){ + free(buf); + } + return ret; +} + +static int +string2struct(void* value, size_t vallen, int depth, void** nv, size_t* nlen) +{ + + struct ha_msg *tmpmsg; + + if (!value || !nv || depth < 0){ + cl_log(LOG_ERR, "string2struct:invalid input"); + return HA_FAIL; + } + + + if (convert(value, vallen, depth,SYM_TO_NL) != HA_OK){ + cl_log(LOG_ERR + , "ha_msg_addraw_ll(): convert failed"); + return(HA_FAIL); + } + + tmpmsg = string2msg_ll(value, vallen,depth + 1, 0); + if (tmpmsg == NULL){ + cl_log(LOG_ERR + , "string2struct()" + ": string2msg_ll failed"); + return(HA_FAIL); + } + free(value); + *nv = tmpmsg; + *nlen = 0; + + return HA_OK; + +} + +static int +string2list(void* value, size_t vallen, int depth, void** nv, size_t* nlen) +{ + GList* list; + + if (!value || !nv || !nlen || depth < 0){ + cl_log(LOG_ERR, "string2struct:invalid input"); + return HA_FAIL; + } + + list = string_list_unpack(value, vallen); + if (list == NULL){ + cl_log(LOG_ERR, "ha_msg_addraw_ll():" + "unpack_string_list failed: %s", (char*)value); + return(HA_FAIL); + } + free(value); + + *nv = (void*)list; + *nlen = string_list_pack_length(list); + + return HA_OK; + +} + +static int +fields2netstring(char* sp, char* smax, char* name, size_t nlen, + void* value, size_t vallen, int type, size_t* comlen) +{ + size_t fieldlen; + size_t slen; + int ret = HA_OK; + char* sp_save = sp; + char* tmpsp; + + fieldlen = fieldtypefuncs[type].netstringlen(nlen, vallen, value); + /* this check seems to be superfluous because of the next one + if (fieldlen > MAXMSG){ + cl_log(LOG_INFO, "%s: field too big(%d)", __FUNCTION__, (int)fieldlen); + return HA_FAIL; + } + */ + tmpsp = sp + netstring_extra(fieldlen); + if (tmpsp > smax){ + cl_log(LOG_ERR, "%s: memory out of boundary, tmpsp=%p, smax=%p", + __FUNCTION__, tmpsp, smax); + return HA_FAIL; + } + sp += sprintf(sp , "%d:(%d)%s=", (int)fieldlen, type, name); + switch (type){ + + case FT_STRING: + case FT_BINARY: + case FT_COMPRESS: + memcpy(sp, value, vallen); + slen = vallen; + break; + + case FT_UNCOMPRESS: + case FT_STRUCT: + { + struct ha_msg* msg = (struct ha_msg*) value; + /* infinite recursion? Must say that I got lost at + * this point + */ + ret = msg2netstring_buf(msg, sp,get_netstringlen(msg), + &slen); + break; + } + case FT_LIST: + { + + char buf[MAXLENGTH]; + GList* list = NULL; + int tmplen; + + list = (GList*) value; + + tmplen = string_list_pack_length(list); + if (tmplen >= MAXLENGTH){ + cl_log(LOG_ERR, + "string list length exceeds limit"); + return(HA_FAIL); + } + + if (string_list_pack(list, buf, buf + MAXLENGTH) + != tmplen ){ + cl_log(LOG_ERR, + "packing string list return wrong length"); + return(HA_FAIL); + } + + + memcpy(sp, buf, tmplen); + slen = tmplen; + ret = HA_OK; + break; + } + + default: + ret = HA_FAIL; + cl_log(LOG_ERR, "%s: Wrong type (%d)", __FUNCTION__,type); + } + + if (ret == HA_FAIL){ + return ret; + } + + sp +=slen; + *sp++ = ','; + *comlen = sp - sp_save; + + return HA_OK; + + +} + + +static int +netstring2string(const void* value, size_t vlen, void** retvalue, size_t* ret_vlen) +{ + char* dupvalue; + + if (value == NULL && vlen == 0){ + *retvalue = NULL; + *ret_vlen = 0; + return HA_OK; + } + + if ( !value || !retvalue || !ret_vlen){ + cl_log(LOG_ERR, " netstring2string:" + "invalid input arguments"); + return HA_FAIL; + } + + dupvalue = binary_dup(value, vlen); + if (!dupvalue){ + cl_log(LOG_ERR, "netstring2string:" + "duplicating value failed"); + return HA_FAIL; + } + + *retvalue = dupvalue; + *ret_vlen = vlen; + + return HA_OK; +} + +static int +netstring2binary(const void* value, size_t vlen, void** retvalue, size_t* ret_vlen) +{ + return netstring2string(value, vlen, retvalue, ret_vlen); + +} + +static int +netstring2struct(const void* value, size_t vlen, void** retvalue, size_t* ret_vlen) +{ + struct ha_msg* msg; + + if ( !value || !retvalue || !ret_vlen){ + cl_log(LOG_ERR, " netstring2struct:" + "invalid input arguments"); + return HA_FAIL; + } + + msg = netstring2msg(value, vlen, 0); + if (!msg){ + cl_log(LOG_ERR, "netstring2struct:" + "netstring2msg failed"); + return HA_FAIL; + } + + *retvalue =(void* ) msg; + *ret_vlen = 0; + + return HA_OK; + +} + +static int +netstring2list(const void* value, size_t vlen, void** retvalue, size_t* ret_vlen) +{ + GList* list; + + if ( !value || !retvalue || !ret_vlen){ + cl_log(LOG_ERR, " netstring2struct:" + "invalid input arguments"); + return HA_FAIL; + } + + + list = string_list_unpack(value, vlen); + if (list == NULL){ + cl_log(LOG_ERR, "netstring2list: unpacking string list failed"); + cl_log(LOG_INFO, "thisbuf=%s", (const char*)value); + return HA_FAIL; + } + *retvalue = (void*)list; + + *ret_vlen = string_list_pack_length(list); + + return HA_OK; + +} + + + + + +static int +add_string_field(struct ha_msg* msg, char* name, size_t namelen, + void* value, size_t vallen, int depth) +{ + + size_t internal_type; + unsigned long tmptype; + char *cp_name = NULL; + size_t cp_namelen; + size_t cp_vallen; + void *cp_value = NULL; + int next; + + if ( !msg || !name || !value + || namelen <= 0 + || depth < 0){ + cl_log(LOG_ERR, "add_string_field:" + " invalid input argument"); + return HA_FAIL; + } + + + + internal_type = FT_STRING; + if (name[0] == '('){ + + int nlo = 3; /*name length overhead */ + if (name[2] != ')'){ + if (!cl_msg_quiet_fmterr) { + cl_log(LOG_ERR + , "ha_msg_addraw_ll(): no closing parentheses"); + } + return(HA_FAIL); + } + tmptype = name[1] - '0'; + if (tmptype < 0 || tmptype > 9) { + cl_log(LOG_ERR + , "ha_msg_addraw_ll(): not a number."); + return(HA_FAIL); + } + + internal_type = tmptype; + + if (internal_type == FT_STRING){ + cl_log(LOG_ERR + , "ha_msg_addraw_ll(): wrong type"); + return(HA_FAIL); + } + + cp_name = name; + cp_namelen = namelen - nlo ; + memmove(cp_name, name + nlo, namelen - nlo); + cp_name[namelen - nlo] = EOS; + }else { + cp_name = name; + cp_namelen = namelen; + + } + + if(internal_type < DIMOF(fieldtypefuncs)){ + int (*stringtofield)(void*, size_t, int depth, void**, size_t* ); + int (*fieldstringlen)( size_t, size_t, const void*); + + stringtofield= fieldtypefuncs[internal_type].stringtofield; + + if (!stringtofield || stringtofield(value, vallen, depth, &cp_value, &cp_vallen) != HA_OK){ + cl_log(LOG_ERR, "add_string_field: stringtofield failed"); + return HA_FAIL; + } + + fieldstringlen = fieldtypefuncs[internal_type].stringlen; + if (!fieldstringlen || + fieldstringlen(cp_namelen, cp_vallen, cp_value) <= 0 ){ + + cl_log(LOG_ERR, "add_string_field: stringlen failed"); + return HA_FAIL; + } + + } else { + cl_log(LOG_ERR, "add_string_field():" + " wrong type %lu", (unsigned long)internal_type); + return HA_FAIL; + } + + + next = msg->nfields; + msg->values[next] = cp_value; + msg->vlens[next] = cp_vallen; + msg->names[next] = cp_name; + msg->nlens[next] = cp_namelen; + msg->types[next] = internal_type; + msg->nfields++; + + return HA_OK; + +} + +static int +uncompress2compress(struct ha_msg* msg, int index) +{ + char* buf; + size_t buflen = MAXMSG; + int rc = HA_FAIL; + + buf = malloc(buflen); + if (!buf) { + cl_log(LOG_ERR, "%s: failed to allocate buffer", + __FUNCTION__); + goto err; + } + + if (msg->types[index] != FT_UNCOMPRESS){ + cl_log(LOG_ERR, "%s: the %dth field is not FT_UNCOMPRESS type", + __FUNCTION__, index); + goto err; + } + + + if (cl_compress_field(msg, index, buf, &buflen) != HA_OK){ + cl_log(LOG_ERR, "%s: compressing %dth field failed", __FUNCTION__, index); + goto err; + } + + rc = cl_msg_replace(msg, index, buf, buflen, FT_COMPRESS); + +err: + if (buf) { + free(buf); + } + + return rc; +} + +static int +compress2uncompress(struct ha_msg* msg, int index) +{ + char *buf = NULL; + size_t buflen = MAXUNCOMPRESSED; + struct ha_msg* msgfield; + int err = HA_FAIL; + + buf = malloc(buflen); + + if (!buf) { + cl_log(LOG_ERR, "%s: allocating buffer for uncompression failed", + __FUNCTION__); + goto out; + } + + if (cl_decompress_field(msg, index, buf, &buflen) != HA_OK){ + cl_log(LOG_ERR, "%s: compress field failed", + __FUNCTION__); + goto out; + } + + msgfield = wirefmt2msg(buf, buflen, 0); + if (msgfield == NULL){ + cl_log(LOG_ERR, "%s: wirefmt to msg failed", + __FUNCTION__); + goto out; + } + + err = cl_msg_replace(msg, index, (char*)msgfield, 0, FT_UNCOMPRESS); + + ha_msg_del(msgfield); + +out: + if (buf) { + free(buf); + } + + return err; +} + +/* + * string FT_STRING + * string is the basic type used in heartbeat, it is used for printable ascii value + * + * binary FT_BINARY + * binary means the value can be any binary value, including non-printable ascii value + * + * struct FT_STRUCT + * struct means the value is also an ha_msg (actually it is a pointer to an ha message) + * + * list FT_LIST + * LIST means the value is a GList. Right now we only suppport a Glist of strings + * + * compress FT_COMPRESS + * This field and the next one(FT_UNCOMPRESS) is designed to optimize compression in message + * (see cl_compression.c for more about compression). This field is similar to the binary field. + * It stores a compressed field, which will be an ha_msg if uncompressed. Most of time this field + * act like a binary field until compress2uncompress() is called. That function will be called + * when someone calls cl_get_struct() to get this field value. After that this field is converted + * to a new type FT_UNCOMPRESS + * + * uncompress FT_UNCOMPRESS + * As said above, this field is used to optimize compression. This field is similar to the struct + * field. It's value is a pointer to an ha_msg. This field will be converted to a new type FT_COMPRESS + * when msg2wirefmt() is called, where uncompress2compress is called to do the field compression + */ + +struct fieldtypefuncs_s fieldtypefuncs[NUM_MSG_TYPES]= + { {string_memfree, string_dup, string_display, add_string_field, + string_stringlen,string_netstringlen, str2string,fields2netstring, + string2str, netstring2string, NULL, NULL}, + + {binary_memfree, binary_dup, binary_display, add_binary_field, + binary_stringlen,binary_netstringlen, binary2string,fields2netstring, + string2binary, netstring2binary, NULL, NULL}, + + {struct_memfree, struct_dup, struct_display, add_struct_field, + struct_stringlen, struct_netstringlen, struct2string, fields2netstring, \ + string2struct, netstring2struct, NULL, NULL}, + + {list_memfree, list_dup, list_display, add_list_field, + list_stringlen, list_netstringlen, list2string, fields2netstring, + string2list, netstring2list, NULL, NULL}, + + {binary_memfree, binary_dup, compress_display, add_compress_field, + binary_stringlen,binary_netstringlen, binary2string ,fields2netstring, + string2binary , netstring2binary, NULL, compress2uncompress}, /*FT_COMPRESS*/ + + {struct_memfree, struct_dup, uncompress_display, add_uncompress_field, + struct_stringlen, struct_netstringlen, NULL , fields2netstring, + NULL , netstring2struct, uncompress2compress, NULL}, /*FT_UNCOMPRSS*/ + }; + + |