version 1.1, 2011/08/29 14:58:50
|
version 1.2, 2011/10/31 13:53:51
|
Line 0
|
Line 1
|
|
/************************************************************************* |
|
* (C) 2011 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org> |
|
* by Michael Pounov <misho@elwix.org> |
|
* |
|
* $Author$ |
|
* $Id$ |
|
* |
|
************************************************************************** |
|
The ELWIX and AITNET software is distributed under the following |
|
terms: |
|
|
|
All of the documentation and software included in the ELWIX and AITNET |
|
Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org> |
|
|
|
Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 |
|
by Michael Pounov <misho@elwix.org>. All rights reserved. |
|
|
|
Redistribution and use in source and binary forms, with or without |
|
modification, are permitted provided that the following conditions |
|
are met: |
|
1. Redistributions of source code must retain the above copyright |
|
notice, this list of conditions and the following disclaimer. |
|
2. Redistributions in binary form must reproduce the above copyright |
|
notice, this list of conditions and the following disclaimer in the |
|
documentation and/or other materials provided with the distribution. |
|
3. All advertising materials mentioning features or use of this software |
|
must display the following acknowledgement: |
|
This product includes software developed by Michael Pounov <misho@elwix.org> |
|
ELWIX - Embedded LightWeight unIX and its contributors. |
|
4. Neither the name of AITNET nor the names of its contributors |
|
may be used to endorse or promote products derived from this software |
|
without specific prior written permission. |
|
|
|
THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND |
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
SUCH DAMAGE. |
|
*/ |
|
#include "global.h" |
|
|
|
|
|
/* |
|
* io_vals2buffer() 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 |
|
*/ |
|
int |
|
io_vals2buffer(u_char *buf, int buflen, array_t *vars) |
|
{ |
|
int Limit = 0; |
|
register int i; |
|
ait_val_t *v, *val; |
|
u_char *data; |
|
|
|
assert(buf); |
|
assert(vars); |
|
if (!buf || !vars) |
|
return -1; |
|
if (!buflen || !io_arraySize(vars)) |
|
return 0; |
|
|
|
Limit = sizeof(ait_val_t) * io_arraySize(vars); |
|
if (Limit > buflen) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d needed min %d ...\n", |
|
buflen, Limit); |
|
return -1; |
|
} else { |
|
memset(buf, 0, buflen); |
|
|
|
v = (ait_val_t*) buf; |
|
data = 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_LEN(&v[i]) = htobe32(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: |
|
v[i].val.net = htobe64(val->val.net); |
|
break; |
|
case buffer: |
|
case string: |
|
if (AIT_LEN(val) > buflen - Limit) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d " |
|
"needed min %d ...\n", buflen, Limit + AIT_LEN(val)); |
|
return -1; |
|
} else |
|
Limit += AIT_LEN(val); |
|
|
|
memcpy(data, val->val.buffer, AIT_LEN(val)); |
|
/* Debug:: data offset in packet, not matter for anything! */ |
|
v[i].val.net = data - buf; |
|
data += AIT_LEN(val); |
|
break; |
|
default: |
|
io_SetErr(EINVAL, "Error:: unsupported variable type=%d at element #%d ...\n", |
|
AIT_TYPE(val), i); |
|
return -1; |
|
} |
|
} |
|
|
|
return Limit; |
|
} |
|
|
|
/* |
|
* io_buffer2vals() 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() |
|
*/ |
|
array_t * |
|
io_buffer2vals(u_char *buf, int buflen, int vnum, int zcpy) |
|
{ |
|
array_t *vars; |
|
int Limit = 0; |
|
register int i; |
|
ait_val_t *v, *val; |
|
u_char *data; |
|
|
|
assert(buf); |
|
if (!buf || !buflen || !vnum) |
|
return NULL; |
|
|
|
Limit = sizeof(ait_val_t) * vnum; |
|
if (Limit > buflen) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d needed min %d ...\n", |
|
buflen, Limit); |
|
return NULL; |
|
} else { |
|
if (!(vars = io_arrayInit(vnum))) |
|
return NULL; |
|
|
|
v = (ait_val_t*) buf; |
|
data = buf + Limit; |
|
} |
|
|
|
/* de-marshaling */ |
|
for (i = 0; i < io_arraySize(vars); i++) { |
|
if (!zcpy) { |
|
val = malloc(sizeof(ait_val_t)); |
|
if (!val) { |
|
LOGERR; |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} |
|
} else |
|
val = v + i; |
|
io_arraySet(vars, i, val); |
|
|
|
val->val_type = v[i].val_type; |
|
#if defined(__OpenBSD__) |
|
AIT_LEN(val) = betoh32(AIT_LEN(&v[i])); |
|
#else |
|
AIT_LEN(val) = be32toh(AIT_LEN(&v[i])); |
|
#endif |
|
|
|
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 defined(__OpenBSD__) |
|
val->val.net = betoh64(v[i].val.net); |
|
#else |
|
val->val.net = be64toh(v[i].val.net); |
|
#endif |
|
break; |
|
case buffer: |
|
case string: |
|
if (AIT_LEN(val) > buflen - Limit) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d " |
|
"needed min %d ...\n", 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 = malloc(AIT_LEN(val)); |
|
if (!val->val.buffer) { |
|
LOGERR; |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} else |
|
memcpy(val->val.buffer, data, AIT_LEN(val)); |
|
} else |
|
val->val.buffer = data; |
|
data += AIT_LEN(val); |
|
break; |
|
default: |
|
io_SetErr(EINVAL, "Error:: unsupported variable type=%d at element #%d ...\n", |
|
AIT_TYPE(val), i); |
|
if (!zcpy) |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} |
|
} |
|
|
|
return vars; |
|
} |
|
|
|
/* buffer marshaling without swapping bytes to network order */ |
|
|
|
/* |
|
* io_vals2map() 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 |
|
*/ |
|
int |
|
io_vals2map(u_char *buf, int buflen, array_t *vars) |
|
{ |
|
int Limit = 0; |
|
register int i; |
|
ait_val_t *v, *val; |
|
u_char *data; |
|
|
|
assert(buf); |
|
assert(vars); |
|
if (!buf || !vars) |
|
return -1; |
|
if (!buflen || !io_arraySize(vars)) |
|
return 0; |
|
|
|
Limit = sizeof(ait_val_t) * io_arraySize(vars); |
|
if (Limit > buflen) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d needed min %d ...\n", |
|
buflen, Limit); |
|
return -1; |
|
} else { |
|
memset(buf, 0, buflen); |
|
|
|
v = (ait_val_t*) buf; |
|
data = 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_LEN(&v[i]) = 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: |
|
v[i].val.net = val->val.net; |
|
break; |
|
case buffer: |
|
case string: |
|
if (AIT_LEN(val) > buflen - Limit) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d " |
|
"needed min %d ...\n", buflen, Limit + AIT_LEN(val)); |
|
return -1; |
|
} else |
|
Limit += AIT_LEN(val); |
|
|
|
memcpy(data, val->val.buffer, AIT_LEN(val)); |
|
/* Debug:: data offset in packet, not matter for anything! */ |
|
v[i].val.net = data - buf; |
|
data += AIT_LEN(val); |
|
break; |
|
default: |
|
io_SetErr(EINVAL, "Error:: unsupported variable type=%d at element #%d ...\n", |
|
AIT_TYPE(val), i); |
|
return -1; |
|
} |
|
} |
|
|
|
return Limit; |
|
} |
|
|
|
/* |
|
* io_map2vals() 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() |
|
*/ |
|
array_t * |
|
io_map2vals(u_char *buf, int buflen, int vnum, int zcpy) |
|
{ |
|
array_t *vars; |
|
int Limit = 0; |
|
register int i; |
|
ait_val_t *v, *val; |
|
u_char *data; |
|
|
|
assert(buf); |
|
if (!buf || !buflen || !vnum) |
|
return NULL; |
|
|
|
Limit = sizeof(ait_val_t) * vnum; |
|
if (Limit > buflen) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d needed min %d ...\n", |
|
buflen, Limit); |
|
return NULL; |
|
} else { |
|
if (!(vars = io_arrayInit(vnum))) |
|
return NULL; |
|
|
|
v = (ait_val_t*) buf; |
|
data = buf + Limit; |
|
} |
|
|
|
/* de-marshaling */ |
|
for (i = 0; i < io_arraySize(vars); i++) { |
|
if (!zcpy) { |
|
val = malloc(sizeof(ait_val_t)); |
|
if (!val) { |
|
LOGERR; |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} |
|
} else |
|
val = v + i; |
|
io_arraySet(vars, i, val); |
|
|
|
val->val_type = v[i].val_type; |
|
AIT_LEN(val) = AIT_LEN(&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: |
|
val->val.net = v[i].val.net; |
|
break; |
|
case buffer: |
|
case string: |
|
if (AIT_LEN(val) > buflen - Limit) { |
|
io_SetErr(EMSGSIZE, "Error:: too short buffer buflen=%d " |
|
"needed min %d ...\n", 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 = malloc(AIT_LEN(val)); |
|
if (!val->val.buffer) { |
|
LOGERR; |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} else |
|
memcpy(val->val.buffer, data, AIT_LEN(val)); |
|
} else |
|
val->val.buffer = data; |
|
data += AIT_LEN(val); |
|
break; |
|
default: |
|
io_SetErr(EINVAL, "Error:: unsupported variable type=%d at element #%d ...\n", |
|
AIT_TYPE(val), i); |
|
if (!zcpy) |
|
io_arrayFree(vars); |
|
io_arrayDestroy(&vars); |
|
return NULL; |
|
} |
|
} |
|
|
|
return vars; |
|
} |