--- libelwix/src/vars.c 2013/03/07 23:04:15 1.2.2.1 +++ libelwix/src/vars.c 2022/10/24 00:10:22 1.13 @@ -3,7 +3,7 @@ * by Michael Pounov * * $Author: misho $ -* $Id: vars.c,v 1.2.2.1 2013/03/07 23:04:15 misho Exp $ +* $Id: vars.c,v 1.13 2022/10/24 00:10:22 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, 2012, 2013 +Copyright 2004 - 2022 by Michael Pounov . All rights reserved. Redistribution and use in source and binary forms, with or without @@ -46,7 +46,7 @@ SUCH DAMAGE. #include "global.h" -static int +static inline int vars2buffer(u_char * __restrict buf, int buflen, int be, array_t * __restrict vars) { int Limit = 0; @@ -123,6 +123,7 @@ vars2buffer(u_char * __restrict buf, int buflen, int b break; case buffer: case string: + case ptr: if (AIT_LEN(val) > buflen - Limit) { elwix_SetErr(EMSGSIZE, "Short buffer buflen=%d " "needed min %d", buflen, Limit + AIT_LEN(val)); @@ -145,7 +146,7 @@ vars2buffer(u_char * __restrict buf, int buflen, int b return Limit; } -static array_t * +static inline array_t * buffer2vars(u_char * __restrict buf, int buflen, int vnum, int zcpy) { array_t *vars; @@ -218,7 +219,8 @@ buffer2vars(u_char * __restrict buf, int buflen, int v val->val.net = le64toh(v[i].val.net); break; case data: - /* WARNING:: remap data type to buffer */ + case ptr: + /* WARNING:: remap data and ptr type to buffer! */ val->val_type = buffer; case buffer: case string: @@ -247,7 +249,372 @@ buffer2vars(u_char * __restrict buf, int buflen, int v return vars; } +/* + * ait_var2tlv() - Marshaling data from variable to TLV buffer + * + * @buf = Buffer, If =NULL then we return only needed buffer size + * @buflen = Size of buffer + * @var = Variable + * return: -1 error, 0 nothing done or >0 size of marshaled data + */ +int +ait_var2tlv(u_char * __restrict buf, int buflen, ait_val_t * __restrict v) +{ + int Limit = 0; + u_char *dat; + assert(v); + if (!v) + return -1; + if (AIT_TYPE(v) == empty) + return 0; + + /* calculate amount of data into buffer */ + Limit = 5 + AIT_LEN(v); + /* check only needed buffer size */ + if (!buf) + return Limit; + else + dat = buf; + + if (Limit > buflen) { + elwix_SetErr(EMSGSIZE, "Short buffer buflen=%d needed min %d", + buflen, Limit); + return -1; + } else + memset(buf, 0, buflen); + + /* marshaling */ + *dat++ = AIT_TYPE(v); + + *((uint32_t*) dat) = htonl(AIT_LEN(v)); + dat += sizeof(uint32_t); + + switch (AIT_TYPE(v)) { + case i8: + *((int8_t*) dat) = AIT_GET_I8(v); + break; + case u8: + *((uint8_t*) dat) = AIT_GET_U8(v); + break; + case i16: + *((int16_t*) dat) = AIT_GET_I16(v); + break; + case u16: + *((uint16_t*) dat) = AIT_GET_U16(v); + break; + case i32: + *((int32_t*) dat) = AIT_GET_I32(v); + break; + case blob: + case u32: + *((uint32_t*) dat) = AIT_GET_U32(v); + break; + case i64: + *((int64_t*) dat) = AIT_GET_I64(v); + break; + case u64: + *((uint64_t*) dat) = AIT_GET_U64(v); + break; + case f32: + *((float*) dat) = AIT_GET_F32(v); + break; + case f64: + *((double*) dat) = AIT_GET_F64(v); + break; + case data: + memcpy(dat, AIT_GET_DATA(v), AIT_LEN(v)); + break; + case buffer: + memcpy(dat, AIT_GET_BUF(v), AIT_LEN(v)); + break; + case string: + memcpy(dat, AIT_GET_STR(v), AIT_LEN(v)); + break; + case ptr: + memcpy(dat, AIT_GET_PTR(v), AIT_LEN(v)); + break; + default: + elwix_SetErr(EINVAL, "Unsupported variable type=%d", AIT_TYPE(v)); + return -1; + } + + return Limit; +} + +/* + * ait_vars2tlv() - Marshaling data from array with variables to TLV buffer + * + * @buf = Buffer, If =NULL then we return only needed buffer size + * @buflen = Size of buffer + * @vars = Variable array + * return: -1 error, 0 nothing done or >0 size of marshaled data + */ +int +ait_vars2tlv(u_char * __restrict buf, int buflen, array_t * __restrict vars) +{ + int Limit = 0; + register int i; + ait_val_t *val; + u_char *dat; + + assert(vars); + if (!vars) + return -1; + if (!array_Size(vars)) + return 0; + + /* calculate amount of data into buffer */ + for (i = 0, Limit = 0; i < array_Size(vars); + Limit += 5 + AIT_LEN(array(vars, i, ait_val_t*)), i++); + /* check only needed buffer size */ + if (!buf) + return Limit; + + if (Limit > buflen) { + elwix_SetErr(EMSGSIZE, "Short buffer buflen=%d needed min %d", + buflen, Limit); + return -1; + } else + memset(buf, 0, buflen); + + /* marshaling */ + for (i = 0, dat = buf; i < array_Size(vars) && dat < (buf + Limit); i++) { + val = array(vars, i, ait_val_t*); + + *dat++ = AIT_TYPE(val); + + *((uint32_t*) dat) = htonl(AIT_LEN(val)); + dat += sizeof(uint32_t); + + switch (AIT_TYPE(val)) { + case i8: + *((int8_t*) dat) = AIT_GET_I8(val); + break; + case u8: + *((uint8_t*) dat) = AIT_GET_U8(val); + break; + case i16: + *((int16_t*) dat) = AIT_GET_I16(val); + break; + case u16: + *((uint16_t*) dat) = AIT_GET_U16(val); + break; + case i32: + *((int32_t*) dat) = AIT_GET_I32(val); + break; + case blob: + case u32: + *((uint32_t*) dat) = AIT_GET_U32(val); + break; + case i64: + *((int64_t*) dat) = AIT_GET_I64(val); + break; + case u64: + *((uint64_t*) dat) = AIT_GET_U64(val); + break; + case f32: + *((float*) dat) = AIT_GET_F32(val); + break; + case f64: + *((double*) dat) = AIT_GET_F64(val); + break; + case data: + memcpy(dat, AIT_GET_DATA(val), AIT_LEN(val)); + break; + case buffer: + memcpy(dat, AIT_GET_BUF(val), AIT_LEN(val)); + break; + case string: + memcpy(dat, AIT_GET_STR(val), AIT_LEN(val)); + break; + case ptr: + memcpy(dat, AIT_GET_PTR(val), AIT_LEN(val)); + break; + default: + elwix_SetErr(EINVAL, "Unsupported variable type=%d at element #%d", + AIT_TYPE(val), i); + return -1; + } + dat += AIT_LEN(val); + } + + return Limit; +} + +/* + * ait_tlv2var() - De-marshaling data from TLV buffer to variable + * + * @buf = Buffer + * @buflen = Size of buffer + * @next_tlv = Next TLV position, if it is !=NULL + * return: =NULL error, !=NULL allocated variable array, after use must free with ait_freeVar() + */ +ait_val_t * +ait_tlv2var(u_char * __restrict buf, int buflen, off_t *next_tlv) +{ + ait_val_t *val; + u_char *dat; + + assert(buf); + if (!buf || !buflen) + return NULL; + + if (!(val = ait_allocVar())) + return NULL; + else + dat = buf; + + /* de-marshaling */ + if (*dat != empty) { + val->val_type = *dat++; + AIT_LEN(val) = ntohl(*((uint32_t*) dat)); + dat += sizeof(uint32_t); + + switch (AIT_TYPE(val)) { + case f32: + AIT_SET_F32(val, *((float*) dat)); + break; + case f64: + AIT_SET_F64(val, *((double*) dat)); + break; + case i8: + AIT_SET_I8(val, *((int8_t*) dat)); + break; + case i16: + AIT_SET_I16(val, *((int16_t*) dat)); + break; + case i32: + AIT_SET_I32(val, *((int32_t*) dat)); + break; + case i64: + AIT_SET_I64(val, *((int64_t*) dat)); + break; + case u8: + AIT_SET_U8(val, *((uint8_t*) dat)); + break; + case u16: + AIT_SET_U16(val, *((uint16_t*) dat)); + break; + case blob: + case u32: + AIT_SET_U32(val, *((uint32_t*) dat)); + break; + case u64: + AIT_SET_U64(val, *((uint64_t*) dat)); + break; + case data: + AIT_SET_DATA(val, dat, AIT_LEN(val)); + break; + case ptr: + case buffer: + AIT_SET_BUF(val, dat, AIT_LEN(val)); + break; + case string: + AIT_SET_STR(val, (char*) dat); + break; + default: + elwix_SetErr(EINVAL, "Unsupported variable type=%d", AIT_TYPE(val)); + ait_freeVar(&val); + return NULL; + } + dat += AIT_LEN(val); + } + + if (next_tlv) + *next_tlv = dat - buf; + + return val; +} + +/* + * ait_tlv2vars() - De-marshaling data from TLV buffer to array with variables + * + * @buf = Buffer + * @buflen = Size of buffer + * return: =NULL error, !=NULL allocated variable array, after use must free with ait_freeVars() + */ +array_t * +ait_tlv2vars(u_char * __restrict buf, int buflen) +{ + array_t *vars; + register int i; + ait_val_t *val; + u_char *dat; + + assert(buf); + if (!buf || !buflen) + return NULL; + + if (!(vars = ait_allocVars(1))) + return NULL; + + /* de-marshaling */ + for (i = 0, dat = buf; *dat != empty && dat < (buf + buflen); i++) { + val = ait_getVars(&vars, i); + if (!val) { + ait_freeVars(&vars); + return NULL; + } + + val->val_type = *dat++; + AIT_LEN(val) = ntohl(*((uint32_t*) dat)); + dat += sizeof(uint32_t); + + switch (AIT_TYPE(val)) { + case f32: + AIT_SET_F32(val, *((float*) dat)); + break; + case f64: + AIT_SET_F64(val, *((double*) dat)); + break; + case i8: + AIT_SET_I8(val, *((int8_t*) dat)); + break; + case i16: + AIT_SET_I16(val, *((int16_t*) dat)); + break; + case i32: + AIT_SET_I32(val, *((int32_t*) dat)); + break; + case i64: + AIT_SET_I64(val, *((int64_t*) dat)); + break; + case u8: + AIT_SET_U8(val, *((uint8_t*) dat)); + break; + case u16: + AIT_SET_U16(val, *((uint16_t*) dat)); + break; + case blob: + case u32: + AIT_SET_U32(val, *((uint32_t*) dat)); + break; + case u64: + AIT_SET_U64(val, *((uint64_t*) dat)); + break; + case data: + AIT_SET_DATA(val, dat, AIT_LEN(val)); + break; + case ptr: + case buffer: + AIT_SET_BUF(val, dat, AIT_LEN(val)); + break; + case string: + AIT_SET_STR(val, (char*) dat); + break; + default: + elwix_SetErr(EINVAL, "Unsupported variable type=%d at element #%d", + AIT_TYPE(val), i); + ait_freeVars(&vars); + return NULL; + } + dat += AIT_LEN(val); + } + + return vars; +} + /* buffer marshaling with swapping bytes to network order */ /* @@ -258,7 +625,7 @@ buffer2vars(u_char * __restrict buf, int buflen, int v * @vars = Variable array * return: -1 error, 0 nothing done or >0 size of marshaled data */ -inline int +int ait_vars2buffer(u_char * __restrict buf, int buflen, array_t * __restrict vars) { return vars2buffer(buf, buflen, 42, vars); @@ -274,7 +641,7 @@ ait_vars2buffer(u_char * __restrict buf, int buflen, a *DON'T MODIFY OR DESTROY BUFFER*. =0 call array_Free() before array_Destroy() * return: =NULL error, !=NULL allocated variable array, after use must free with array_Destroy() */ -inline array_t * +array_t * ait_buffer2vars(u_char * __restrict buf, int buflen, int vnum, int zcpy) { return buffer2vars(buf, buflen, vnum, zcpy); @@ -290,7 +657,7 @@ ait_buffer2vars(u_char * __restrict buf, int buflen, i * @vars = Variable array * return: -1 error, 0 nothing done or >0 size of marshaled data */ -inline int +int ait_vars2map(u_char *buf, int buflen, array_t *vars) { return vars2buffer(buf, buflen, 0, vars); @@ -306,13 +673,62 @@ ait_vars2map(u_char *buf, int buflen, array_t *vars) *DON'T MODIFY OR DESTROY BUFFER*. =0 call array_Free() before array_Destroy() * return: =NULL error, !=NULL allocated variable array, after use must free with array_Destroy() */ -inline array_t * +array_t * ait_map2vars(u_char *buf, int buflen, int vnum, int zcpy) { return buffer2vars(buf, buflen, vnum, zcpy); } +/* + * ait_array2vars() - Build array with variables from Null Terminated String Array + * + * @args = Null-terminated array with strings + * @dn = Convert numbers from strings to numbers into variables + * return: =NULL error, !=NULL allocated variable array, after use must free with ait_freeVars() + */ +array_t * +ait_array2vars(const char **args, int dn) +{ + array_t *vars; + ait_val_t *val; + register int i; + long n; + double d; + char *str; + if (!args) + return NULL; + + vars = ait_allocVars(0); + if (!vars) + return NULL; + + for (i = 0; *args; i++, args++) { + val = ait_getVars(&vars, i); + if (!val) { + ait_freeVars(&vars); + return NULL; + } + + if (dn) { + n = strtol(*args, &str, 0); + if (!str || !*str) { + AIT_SET_I64(val, (int64_t) n); + continue; + } + d = strtod(*args, &str); + if (!str || !*str) { + AIT_SET_F64(val, d); + continue; + } + AIT_SET_STR(val, *args); + } else + AIT_SET_STR(val, *args); + } + + return vars; +} + /* variables array */ /* @@ -321,7 +737,7 @@ ait_map2vars(u_char *buf, int buflen, int vnum, int zc * @varnum = Number of variables * return: =NULL error or !=NULL allocated array */ -inline array_t * +array_t * ait_allocVars(int varnum) { array_t *arr; @@ -349,7 +765,7 @@ ait_allocVars(int varnum) * @n = index of variable into array * return: NULL error or !=NULL ait_val_t element */ -inline ait_val_t * +ait_val_t * ait_getVars(array_t ** __restrict vars, int n) { register int i; @@ -382,7 +798,7 @@ ait_getVars(array_t ** __restrict vars, int n) * @vars = Variable array * return: -1 error or size of array */ -inline int +int ait_clrVars(array_t * __restrict vars) { register int i; @@ -404,24 +820,68 @@ ait_clrVars(array_t * __restrict vars) * @vars = Variable array * return: none */ -inline void +void ait_freeVars(array_t ** __restrict vars) { + register int i; + ait_val_t *v; + if (!vars || !*vars) return; - ait_clrVars(*vars); - array_Free(*vars); + for (i = 0; i < array_Size(*vars); i++) + if ((v = array(*vars, i, ait_val_t*))) { + /* free memory if isn't zero copy */ + if (!AIT_IN(v)) { + AIT_FREE_VAL(v); + if ((*vars)->arr_data[i]) + e_free((*vars)->arr_data[i]); + } else + AIT_FREE_VAL(v); + (*vars)->arr_data[i] = NULL; + } + (*vars)->arr_last = -1; + array_Destroy(vars); } +/* + * ait_resideVars() - Calculate footprint of resided variables into array + * + * @vars = Variable array + * return: bytes for whole array + */ +size_t +ait_resideVars(array_t * __restrict vars) +{ + size_t ret = 0; + register int i; + if (vars) { + ret = array_Size(vars) * sizeof(ait_val_t); + for (i = 0; i < array_Size(vars); i++) + switch (AIT_TYPE(array(vars, i, ait_val_t*))) { + case buffer: + case string: + case data: + case ptr: + ret += AIT_LEN(array(vars, i, ait_val_t*)); + break; + default: + break; + } + } + + return ret; +} + + /* * ait_allocVar() - Allocate memory for variable * * return: NULL error or new variable, after use free variable with ait_freeVar() */ -inline ait_val_t * +ait_val_t * ait_allocVar(void) { ait_val_t *v = NULL; @@ -442,7 +902,7 @@ ait_allocVar(void) * @val = Variable * return: none */ -inline void +void ait_freeVar(ait_val_t ** __restrict val) { if (val && *val) { @@ -570,7 +1030,7 @@ _cmp_arr_val_desc(const void *a, const void *b) * @cmp = Custom compare function for sorting. If =NULL compare by value * return: none */ -inline void +void ait_sortVarsByVal(array_t * __restrict vars, int order, int (*cmp)(const void*, const void*)) { if (!vars) @@ -591,7 +1051,7 @@ ait_sortVarsByVal(array_t * __restrict vars, int order * @order = Sort order. If =0 ascend or !=0 descend * return: none */ -inline void +void ait_sortVarsByKey(array_t * __restrict vars, int order) { if (!vars) @@ -702,7 +1162,7 @@ ait_hashVar(ait_val_t * __restrict v, const char * __r * @vars = Variables * return -1 error or 0 ok */ -inline int +int ait_hashKeyVars(array_t * __restrict vars) { register int i; @@ -723,7 +1183,7 @@ ait_hashKeyVars(array_t * __restrict vars) * @key = Search string * return: NULL error or not found, !=NULL valid element */ -inline ait_val_t * +ait_val_t * ait_findKeyHash(array_t * __restrict vars, const char * __restrict key) { u_short k = 0; @@ -748,23 +1208,21 @@ ait_sprintfVar(ait_val_t * __restrict v, const char *f { int ret = 0; va_list lst; - char *str = NULL; + char str[65536] = { [0 ... 65535] = 0 }; if (!v || !fmt) return -1; va_start(lst, fmt); - ret = vasprintf(&str, fmt, lst); + ret = vsnprintf(str, sizeof str - 1, fmt, lst); va_end(lst); - if (str && ret > -1) { + if (ret > -1) { AIT_FREE_VAL(v); AIT_SET_STR(v, str); } else LOGERR; - if (str) - free(str); return ret; } @@ -777,7 +1235,7 @@ ait_sprintfVar(ait_val_t * __restrict v, const char *f * @... = data * return: -1 error or 0 ok */ -inline int +int ait_setlikeVar(ait_val_t * __restrict v, ait_type_t t, u_int l, ...) { va_list lst; @@ -812,7 +1270,7 @@ ait_setlikeVar(ait_val_t * __restrict v, ait_type_t t, * @v = variable * return: return raw data */ -inline uint64_t +uint64_t ait_getlikeVar(ait_val_t * __restrict v) { if (!v) @@ -828,7 +1286,7 @@ ait_getlikeVar(ait_val_t * __restrict v) * @b = 2nd variable * return: 0 is equal or !=0 is different */ -inline int +int ait_cmpVar(ait_val_t * __restrict a, ait_val_t * __restrict b) { intptr_t ret;