--- libaitio/src/Attic/vars.c 2011/08/29 14:58:50 1.1.2.1 +++ libaitio/src/Attic/vars.c 2012/08/29 13:51:30 1.13 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: vars.c,v 1.1.2.1 2011/08/29 14:58:50 misho Exp $ +* $Id: vars.c,v 1.13 2012/08/29 13:51:30 misho Exp $ * ************************************************************************** The ELWIX and AITNET software is distributed under the following @@ -12,7 +12,7 @@ terms: All of the documentation and software included in the ELWIX and AITNET Releases is copyrighted by ELWIX - Sofia/Bulgaria -Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 +Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 by Michael Pounov . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -45,4 +45,704 @@ SUCH DAMAGE. */ #include "global.h" + +static int +vars2buffer(u_char * __restrict buf, int buflen, int be, array_t * __restrict vars) +{ + int Limit = 0; + register int i; + ait_val_t *v, *val; + u_char *dat; + + assert(buf); + assert(vars); + if (!buf || !vars) + return -1; + if (!buflen || !io_arraySize(vars)) + return 0; + be = !!be; + + Limit = sizeof(ait_val_t) * io_arraySize(vars); + if (Limit > buflen) { + io_SetErr(EMSGSIZE, "Short buffer buflen=%d needed min %d", + buflen, Limit); + return -1; + } else { + memset(buf, 0, buflen); + + v = (ait_val_t*) buf; + dat = buf + Limit; + } + + /* marshaling */ + for (i = 0; i < io_arraySize(vars); i++) { + val = io_array(vars, i, ait_val_t*); + + v[i].val_type = val->val_type; + AIT_IN(&v[i]) = 1; + AIT_BE(&v[i]) = be; + AIT_LE(&v[i]) = !be; + if (AIT_BE(&v[i])) { + AIT_KEY(&v[i]) = htobe16(AIT_KEY(val)); + AIT_LEN(&v[i]) = htobe32(AIT_LEN(val)); + } + if (AIT_LE(&v[i])) { + AIT_KEY(&v[i]) = htole16(AIT_KEY(val)); + AIT_LEN(&v[i]) = htole32(AIT_LEN(val)); + } + + switch (AIT_TYPE(val)) { + case blob: + case f32: + case f64: + case i8: + case i16: + case i32: + case i64: + case u8: + case u16: + case u32: + case u64: + if (AIT_BE(&v[i])) + v[i].val.net = htobe64(val->val.net); + if (AIT_LE(&v[i])) + v[i].val.net = htole64(val->val.net); + break; + case data: + if (AIT_LEN(val) > buflen - Limit) { + io_SetErr(EMSGSIZE, "Short buffer buflen=%d " + "needed min %d", buflen, Limit + AIT_LEN(val)); + return -1; + } else + Limit += AIT_LEN(val); + + memcpy(dat, val->val_data, AIT_LEN(val)); + /* Debug:: data offset in packet, not matter for anything! */ + v[i].val.net = dat - buf; + dat += AIT_LEN(val); + break; + case buffer: + case string: + if (AIT_LEN(val) > buflen - Limit) { + io_SetErr(EMSGSIZE, "Short buffer buflen=%d " + "needed min %d", buflen, Limit + AIT_LEN(val)); + return -1; + } else + Limit += AIT_LEN(val); + + memcpy(dat, val->val.buffer, AIT_LEN(val)); + /* Debug:: data offset in packet, not matter for anything! */ + v[i].val.net = dat - buf; + dat += AIT_LEN(val); + break; + default: + io_SetErr(EINVAL, "Unsupported variable type=%d at element #%d", + AIT_TYPE(val), i); + return -1; + } + } + + return Limit; +} + +static array_t * +buffer2vars(u_char * __restrict buf, int buflen, int vnum, int zcpy) +{ + array_t *vars; + int Limit = 0; + register int i; + ait_val_t *v, *val; + u_char *dat; + + assert(buf); + if (!buf || !buflen || !vnum) + return NULL; + + Limit = sizeof(ait_val_t) * vnum; + if (Limit > buflen) { + io_SetErr(EMSGSIZE, "Short buffer buflen=%d needed min %d", + buflen, Limit); + return NULL; + } else { + if (!(vars = io_arrayInit(vnum))) + return NULL; + + v = (ait_val_t*) buf; + dat = buf + Limit; + } + + /* de-marshaling */ + for (i = 0; i < io_arraySize(vars); i++) { + if (!zcpy) { + val = io_malloc(sizeof(ait_val_t)); + if (!val) { + LOGERR; + io_arrayFree(vars); + io_arrayDestroy(&vars); + return NULL; + } + AIT_IN(val) = 0; + } else { + val = v + i; + AIT_IN(val) = 1; + } + io_arraySet(vars, i, val); + + val->val_type = v[i].val_type; + AIT_BE(val) = AIT_BE(&v[i]); + AIT_LE(val) = AIT_LE(&v[i]); + if (AIT_BE(val)) { + AIT_LEN(val) = be32toh(AIT_LEN(&v[i])); + AIT_KEY(val) = be16toh(AIT_KEY(&v[i])); + } + if (AIT_LE(val)) { + AIT_LEN(val) = le32toh(AIT_LEN(&v[i])); + AIT_KEY(val) = le16toh(AIT_KEY(&v[i])); + } + + switch (AIT_TYPE(val)) { + case blob: + case f32: + case f64: + case i8: + case i16: + case i32: + case i64: + case u8: + case u16: + case u32: + case u64: + if (AIT_BE(val)) + val->val.net = be64toh(v[i].val.net); + if (AIT_LE(val)) + val->val.net = le64toh(v[i].val.net); + break; + case data: + /* WARNING:: remap data type to buffer */ + val->val_type = buffer; + case buffer: + case string: + if (AIT_LEN(val) > buflen - Limit) { + io_SetErr(EMSGSIZE, "Short buffer buflen=%d " + "needed min %d", buflen, Limit + AIT_LEN(val)); + if (!zcpy) + io_arrayFree(vars); + io_arrayDestroy(&vars); + return NULL; + } else + Limit += AIT_LEN(val); + + if (!zcpy) { + val->val.buffer = io_malloc(AIT_LEN(val)); + if (!val->val.buffer) { + LOGERR; + io_arrayFree(vars); + io_arrayDestroy(&vars); + return NULL; + } else + memcpy(val->val.buffer, dat, AIT_LEN(val)); + } else + val->val.buffer = dat; + dat += AIT_LEN(val); + break; + default: + io_SetErr(EINVAL, "Unsupported variable type=%d at element #%d", + AIT_TYPE(val), i); + if (!zcpy) + io_arrayFree(vars); + io_arrayDestroy(&vars); + return NULL; + } + } + + return vars; +} + + +/* buffer marshaling with swapping bytes to network order */ + +/* + * io_vars2buffer() - Marshaling data from array with variables to buffer + * + * @buf = Buffer + * @buflen = Size of buffer + * @vars = Variable array + * return: -1 error, 0 nothing done or >0 size of marshaled data + */ +inline int +io_vars2buffer(u_char * __restrict buf, int buflen, array_t * __restrict vars) +{ + return vars2buffer(buf, buflen, 42, vars); +} + +/* + * io_buffer2vars() - De-marshaling data from buffer to array with variables + * + * @buf = Buffer + * @buflen = Size of buffer + * @vnum = Number of variables into buffer + * @zcpy = Zero-copy for variables, if !=0 don't use io_arrayFree() for free variables and + *DON'T MODIFY OR DESTROY BUFFER*. =0 call io_arrayFree() before io_arrayDestroy() + * return: =NULL error, !=NULL allocated variable array, after use must free with io_arrayDestroy() + */ +inline array_t * +io_buffer2vars(u_char * __restrict buf, int buflen, int vnum, int zcpy) +{ + return buffer2vars(buf, buflen, vnum, zcpy); +} + +/* buffer marshaling without swapping bytes to network order */ + +/* + * io_vars2map() - Marshaling data from array with variables to memory map + * + * @buf = Buffer + * @buflen = Size of buffer + * @vars = Variable array + * return: -1 error, 0 nothing done or >0 size of marshaled data + */ +inline int +io_vars2map(u_char *buf, int buflen, array_t *vars) +{ + return vars2buffer(buf, buflen, 0, vars); +} + +/* + * io_map2vars() - De-marshaling data from memory map to array with variables + * + * @buf = Buffer + * @buflen = Size of buffer + * @vnum = Number of variables into buffer + * @zcpy = Zero-copy for variables, if !=0 don't use io_arrayFree() for free variables and + *DON'T MODIFY OR DESTROY BUFFER*. =0 call io_arrayFree() before io_arrayDestroy() + * return: =NULL error, !=NULL allocated variable array, after use must free with io_arrayDestroy() + */ +inline array_t * +io_map2vars(u_char *buf, int buflen, int vnum, int zcpy) +{ + return buffer2vars(buf, buflen, vnum, zcpy); +} + + +/* + * io_allocVars() - Allocate ait_val_t array + * + * @varnum = Number of variables + * return: =NULL error or !=NULL allocated array + */ +inline array_t * +io_allocVars(int varnum) +{ + array_t *arr; + register int i; + ait_val_t *v; + + if (!(arr = io_arrayInit(varnum))) + return NULL; + + for (i = 0; i < io_arraySize(arr); i++) { + if (!(v = io_allocVar())) { + io_freeVars(&arr); + return NULL; + } else + io_arraySet(arr, i, v); + } + + return arr; +} + +/* + * io_getVars() - Get ait_val_t element from array and if not exists allocate it + * + * @vars = Variable array + * @n = index of variable into array + * return: NULL error or !=NULL ait_val_t element + */ +inline ait_val_t * +io_getVars(array_t ** __restrict vars, int n) +{ + register int i; + ait_val_t *v; + + if (!vars) + return NULL; + + if (!*vars) { + if (!(*vars = io_allocVars(n + 1))) + return NULL; + } else { + if (n >= (i = io_arraySize(*vars))) { + if (io_arrayGrow(*vars, n + 1, 0)) + return NULL; + for (; i < io_arraySize(*vars); i++) + if (!io_arrayGet(*vars, i)) { + if (!(v = io_allocVar())) + return NULL; + else + io_arraySet(*vars, n, v); + } + } + } + + return io_array(*vars, n, ait_val_t*); +} + +/* + * io_clrVars() - Clear ait_val_t elements from array + * + * @vars = Variable array + * return: -1 error or size of array + */ +inline int +io_clrVars(array_t * __restrict vars) +{ + register int i; + ait_val_t *v; + + if (!vars) + return -1; + + for (i = 0; i < io_arraySize(vars); i++) + if ((v = io_array(vars, i, ait_val_t*))) + AIT_FREE_VAL(v); + + return io_arraySize(vars); +} + +/* + * io_freeVars() - Free ait_val_t array + * + * @vars = Variable array + * return: none + */ +inline void +io_freeVars(array_t ** __restrict vars) +{ + if (!vars || !*vars) + return; + + io_clrVars(*vars); + io_arrayFree(*vars); + io_arrayDestroy(vars); +} + +/* + * io_allocVar() - Allocate memory for variable + * + * return: NULL error or new variable, after use free variable with io_freeVar() + */ +inline ait_val_t * +io_allocVar(void) +{ + ait_val_t *v = NULL; + + v = io_malloc(sizeof(ait_val_t)); + if (!v) { + LOGERR; + return NULL; + } else + memset(v, 0, sizeof(ait_val_t)); + v->val_type = empty; + + return v; +} + +/* + * io_freeVar() - Free allocated memory for variable + * + * @val = Variable + * return: none + */ +inline void +io_freeVar(ait_val_t ** __restrict val) +{ + if (val && *val) { + AIT_FREE_VAL(*val); + io_free(*val); + *val = NULL; + } +} + +/* + * io_makeVar() - Allocate memory and fill variable + * + * @type = type of variable + * @... = arg1 is value of variable + * @... = arg2 is length of variabla. Not required for numbers and strings! + * return: NULL error or new variable, after use free variable with io_freeVar() + */ +ait_val_t * +io_makeVar(ait_type_t type, ...) +{ + ait_val_t *v = NULL; + va_list lst; + void *p = NULL; + uint32_t len = 0; + uint64_t n = 0LL; + + v = io_allocVar(); + if (!v) + return NULL; + + va_start(lst, type); + switch (type) { + case empty: + v->val_type = (uint8_t) empty; + break; + case ptr: + p = va_arg(lst, void*); + len = va_arg(lst, uint32_t); + AIT_SET_PTR(v, p, len); + break; + case data: + p = va_arg(lst, void*); + len = va_arg(lst, uint32_t); + AIT_SET_DATA(v, p, len); + break; + case buffer: + p = va_arg(lst, void*); + len = va_arg(lst, uint32_t); + AIT_SET_BUF(v, p, len); + break; + case string: + p = va_arg(lst, char*); + AIT_SET_STR(v, (char*) p); + break; + case blob: + n = va_arg(lst, uint32_t); + len = va_arg(lst, uint32_t); + AIT_SET_BLOB(v, n, len); + break; + case f32: + AIT_SET_F32(v, (float) va_arg(lst, double)); + break; + case f64: + AIT_SET_F64(v, va_arg(lst, double)); + break; + case u8: + AIT_SET_U8(v, (uint8_t) va_arg(lst, int)); + break; + case u16: + AIT_SET_U16(v, (uint16_t) va_arg(lst, int)); + break; + case u32: + AIT_SET_U32(v, va_arg(lst, uint32_t)); + break; + case u64: + AIT_SET_U64(v, va_arg(lst, uint64_t)); + break; + case i8: + AIT_SET_I8(v, (int8_t) va_arg(lst, int)); + break; + case i16: + AIT_SET_I16(v, (int16_t) va_arg(lst, int)); + break; + case i32: + AIT_SET_I32(v, va_arg(lst, int32_t)); + break; + case i64: + AIT_SET_I64(v, va_arg(lst, int64_t)); + break; + } + va_end(lst); + + return v; +} + +static int +_cmp_arr_key_asc(const void *a, const void *b) +{ + return AIT_KEY(*(ait_val_t**) a) - AIT_KEY(*(ait_val_t**) b); +} + +static int +_cmp_arr_key_desc(const void *a, const void *b) +{ + return AIT_KEY(*(ait_val_t**) b) - AIT_KEY(*(ait_val_t**) a); +} + +static int +_cmp_arr_val_asc(const void *a, const void *b) +{ + return AIT_RAW(*(ait_val_t**) a) - AIT_RAW(*(ait_val_t**) b); +} + +static int +_cmp_arr_val_desc(const void *a, const void *b) +{ + return AIT_RAW(*(ait_val_t**) b) - AIT_RAW(*(ait_val_t**) a); +} + +/* + * io_sortVarsByVal() - Sorting array with variables by value + * + * @vars = Variable array + * @order = Sort order. If =0 ascend or !=0 descend + * @cmp = Custom compare function for sorting. If =NULL compare by value + * return: none + */ +inline void +io_sortVarsByVal(array_t * __restrict vars, int order, int (*cmp)(const void*, const void*)) +{ + if (!vars) + return; + + if (cmp) + qsort(vars->arr_data, vars->arr_num, sizeof(void*), cmp); + else if (order) + qsort(vars->arr_data, vars->arr_num, sizeof(void*), _cmp_arr_val_desc); + else + qsort(vars->arr_data, vars->arr_num, sizeof(void*), _cmp_arr_val_asc); +} + +/* + * io_sortVarsByKey() - Sorting array with variables by key + * + * @vars = Variable array + * @order = Sort order. If =0 ascend or !=0 descend + * return: none + */ +inline void +io_sortVarsByKey(array_t * __restrict vars, int order) +{ + if (!vars) + return; + + if (order) + qsort(vars->arr_data, vars->arr_num, sizeof(void*), _cmp_arr_key_desc); + else + qsort(vars->arr_data, vars->arr_num, sizeof(void*), _cmp_arr_key_asc); +} + +/* + * io_findKeyVars() - Find variable by key from array + * + * @vars = Variables + * @key = Search key + * return: NULL error or not found, !=NULL valid element + */ +ait_val_t * +io_findKeyVars(array_t * __restrict vars, u_short key) +{ + array_t *tmp; + ait_val_t **vv, *v = NULL; + register int i; + const u_char *p; + + if (!vars) + return NULL; + + if (io_arrayCopy(&tmp, vars) == -1) + return NULL; + else + qsort(tmp->arr_data, tmp->arr_num, sizeof(void*), _cmp_arr_key_asc); + + /* binary search */ + for (p = (const u_char*) tmp->arr_data, i = io_arraySize(tmp); i; i >>= 1) { + vv = (ait_val_t**) (p + (i >> 1) * sizeof(void*)); + if (!(key - AIT_KEY(*vv))) { /* found! */ + v = *vv; + break; + } + if ((key - AIT_KEY(*vv)) > 0) { /* move right key > current */ + p = (const u_char*) vv + sizeof(void*); + i--; + } /* else move left */ + } + + io_arrayDestroy(&tmp); + return v; +} + +/* + * io_hashVar() - Generate hash key for variable from string or value + * + * @v = variable + * @key = key string for hash, if =NULL hash will built from variable + * return: hash key + */ +u_short +io_hashVar(ait_val_t * __restrict v, const char * __restrict key) +{ + void *p; + u_short cksum; + int l; + + if (!v) + return 0; + + if (key) { + p = (void*) key; + l = (strlen(key) + 1) / 2; + } else { + switch (AIT_TYPE(v)) { + case empty: + AIT_KEY(v) = 0; + return 0; + case string: + case buffer: + p = AIT_ADDR(v); + l = AIT_LEN(v) / 2; + break; + case data: + p = v->val_data; + l = AIT_LEN(v) / 2; + break; + default: + p = &AIT_RAW(v); + l = sizeof AIT_RAW(v) / 2; + break; + } + } + + cksum = crcFletcher16((u_short*) p, l); + + if (AIT_BE(v)) + AIT_KEY(v) = htobe16(cksum); + else if (AIT_LE(v)) + AIT_KEY(v) = htole16(cksum); + else + AIT_KEY(v) = cksum; + + return AIT_KEY(v); +} + +/* + * io_hashKeyVars() - Generate hash keys for variables + * + * @vars = Variables + * return -1 error or 0 ok + */ +inline int +io_hashKeyVars(array_t * __restrict vars) +{ + register int i; + + if (!vars) + return -1; + + for (i = 0; i < io_arraySize(vars); i++) + io_hashVar(io_array(vars, i, ait_val_t*), NULL); + + return 0; +} + +/* + * io_findKeyHash() - Find variable by hash string from array + * + * @vars = Variables + * @key = Search string + * return: NULL error or not found, !=NULL valid element + */ +inline ait_val_t * +io_findKeyHash(array_t * __restrict vars, const char * __restrict key) +{ + u_short k = 0; + + if (!vars || !key) + return NULL; + + k = crcFletcher16((u_short*) key, (strlen(key) + 1) / 2); + return io_findKeyVars(vars, k); +}