/* * ndpi_serializer.c * * Copyright (C) 2011-19 - ntop.org * * This file is part of nDPI, an open source deep packet inspection * library based on the OpenDPI and PACE technology by ipoque GmbH * * nDPI 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 3 of the License, or * (at your option) any later version. * * nDPI 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 nDPI. If not, see . * */ #ifdef HAVE_CONFIG_H #include "ndpi_config.h" #endif #include #include #include #include "ndpi_api.h" #include "ndpi_config.h" #include #ifndef WIN32 #include #endif #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ #include #endif /* ********************************** */ static u_int64_t ndpi_htonll(u_int64_t v) { union { u_int32_t lv[2]; u_int64_t llv; } u; u.lv[0] = htonl(v >> 32); u.lv[1] = htonl(v & 0xFFFFFFFFULL); return u.llv; } /* ********************************** */ static u_int64_t ndpi_ntohll(u_int64_t v) { union { u_int32_t lv[2]; u_int64_t llv; } u; u.llv = v; return ((u_int64_t)ntohl(u.lv[0]) << 32) | (u_int64_t)ntohl(u.lv[1]); } /* ********************************** */ /* * Escapes a string to be suitable for a JSON value, adding double quotes, and terminating the string with a null byte. * It is recommended to provide a destination buffer (dst) which is as large as double the source buffer (src) at least. * Upon successful return, these functions return the number of characters printed (excluding the null byte used to terminate the string). */ static int ndpi_json_string_escape(const char *src, int src_len, char *dst, int dst_max_len) { char c = 0; int i, j = 0; dst[j++] = '"'; for (i = 0; i < src_len && j < dst_max_len; i++) { c = src[i]; switch (c) { case '\\': case '"': case '/': dst[j++] = '\\'; dst[j++] = c; break; case '\b': dst[j++] = '\\'; dst[j++] = 'b'; break; case '\t': dst[j++] = '\\'; dst[j++] = 't'; break; case '\n': dst[j++] = '\\'; dst[j++] = 'n'; break; case '\f': dst[j++] = '\\'; dst[j++] = 'f'; break; case '\r': dst[j++] = '\\'; dst[j++] = 'r'; break; default: if(c < ' ') ; /* non printable */ else dst[j++] = c; } } dst[j++] = '"'; dst[j+1] = '\0'; return j; } /* ********************************** */ void ndpi_reset_serializer(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->fmt == ndpi_serialization_format_json) { u_int32_t buff_diff; serializer->size_used = 0; buff_diff = serializer->buffer_size - serializer->size_used; /* Note: please keep a space at the beginning as it is used for arrays when an end-of-record is used */ serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, " {}"); } else if(serializer->fmt == ndpi_serialization_format_csv) serializer->size_used = 0; else /* TLV */ serializer->size_used = 2 * sizeof(u_int8_t); } /* ********************************** */ int ndpi_init_serializer(ndpi_serializer *_serializer, ndpi_serialization_format fmt) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memset(serializer, 0, sizeof(ndpi_private_serializer)); serializer->buffer_size = 8192; serializer->buffer = (u_int8_t *) malloc(serializer->buffer_size * sizeof(u_int8_t)); if(serializer->buffer == NULL) return(-1); serializer->fmt = fmt; serializer->buffer[0] = 1; /* version */ serializer->buffer[1] = (u_int8_t) fmt; serializer->csv_separator[0] = ','; serializer->csv_separator[1] = '\0'; ndpi_reset_serializer(_serializer); return(1); } /* ********************************** */ char* ndpi_serializer_get_buffer(ndpi_serializer *_serializer, u_int32_t *buffer_len) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; char *buf = (char*)serializer->buffer; /* NULL terminate the buffer if there is space available */ if(serializer->buffer_size > serializer->size_used) serializer->buffer[serializer->size_used] = '\0'; *buffer_len = serializer->size_used; if(serializer->fmt == ndpi_serialization_format_json) { while(buf[0] == '\0') buf++, *buffer_len = *buffer_len - 1 ; } return(buf); } /* ********************************** */ u_int32_t ndpi_serializer_get_buffer_len(ndpi_serializer *_serializer) { return(((ndpi_private_serializer*)_serializer)->size_used); } /* ********************************** */ void ndpi_serializer_set_csv_separator(ndpi_serializer *_serializer, char separator) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; serializer->csv_separator[0] = separator; } /* ********************************** */ void ndpi_term_serializer(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->buffer) { free(serializer->buffer); serializer->buffer_size = 0; serializer->buffer = NULL; } } /* ********************************** */ static int ndpi_extend_serializer_buffer(ndpi_serializer *_serializer, u_int32_t min_len) { u_int32_t new_size; void *r; ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(min_len < 1024) min_len = 1024; new_size = serializer->buffer_size + min_len; r = realloc((void *) serializer->buffer, new_size); if(r == NULL) return(-1); serializer->buffer = r; serializer->buffer_size = new_size; return(0); } /* ********************************** */ static void ndpi_serialize_single_uint32(ndpi_serializer *_serializer, u_int32_t s) { u_int32_t v = htonl(s); ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int32_t)); serializer->size_used += sizeof(u_int32_t); } /* ********************************** */ static void ndpi_serialize_single_uint64(ndpi_serializer *_serializer, u_int64_t s) { u_int64_t v = ndpi_htonll(s); ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memcpy(&serializer->buffer[serializer->size_used], &v, sizeof(u_int64_t)); serializer->size_used += sizeof(u_int64_t); } /* ********************************** */ /* TODO: fix portability across platforms */ static void ndpi_serialize_single_float(ndpi_serializer *_serializer, float s) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memcpy(&serializer->buffer[serializer->size_used], &s, sizeof(s)); serializer->size_used += sizeof(float); } /* ********************************** */ static void ndpi_serialize_single_string(ndpi_serializer *_serializer, const char *s, u_int16_t slen) { u_int16_t l = htons(slen); ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; memcpy(&serializer->buffer[serializer->size_used], &l, sizeof(u_int16_t)); serializer->size_used += sizeof(u_int16_t); if(slen > 0) memcpy(&serializer->buffer[serializer->size_used], s, slen); serializer->size_used += slen; } /* ********************************** */ static void ndpi_deserialize_single_uint32(ndpi_serializer *_deserializer, u_int32_t *s) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; *s = ntohl(*((u_int32_t *) &deserializer->buffer[deserializer->size_used])); deserializer->size_used += sizeof(u_int32_t); } /* ********************************** */ static void ndpi_deserialize_single_int32(ndpi_serializer *_deserializer, int32_t *s) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; *s = ntohl(*((int32_t *) &deserializer->buffer[deserializer->size_used])); deserializer->size_used += sizeof(int32_t); } /* ********************************** */ static void ndpi_deserialize_single_uint64(ndpi_serializer *_deserializer, u_int64_t *s) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; *s = ndpi_ntohll(*(u_int64_t*)&deserializer->buffer[deserializer->size_used]); deserializer->size_used += sizeof(u_int64_t); } /* ********************************** */ static void ndpi_deserialize_single_int64(ndpi_serializer *_deserializer, int64_t *s) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; *s = ndpi_ntohll(*(int64_t*)&deserializer->buffer[deserializer->size_used]); deserializer->size_used += sizeof(int64_t); } /* ********************************** */ /* TODO: fix portability across platforms */ static void ndpi_deserialize_single_float(ndpi_serializer *_deserializer, float *s) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; *s = *(float*)&deserializer->buffer[deserializer->size_used]; deserializer->size_used += sizeof(float); } /* ********************************** */ static void ndpi_deserialize_single_string(ndpi_serializer *_deserializer, ndpi_string *v) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer[deserializer->size_used])); deserializer->size_used += sizeof(u_int16_t); v->str = (char *) &deserializer->buffer[deserializer->size_used]; deserializer->size_used += v->str_len; } /* ********************************** */ int ndpi_serialize_end_of_record(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int16_t needed = sizeof(u_int8_t) /* type */; if(serializer->fmt == ndpi_serialization_format_json) needed += 1; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { if(!(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY)) { // serializer->json_buffer[0] = '['; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "]"); } serializer->status |= NDPI_SERIALIZER_STATUS_ARRAY | NDPI_SERIALIZER_STATUS_EOR; serializer->status &= ~NDPI_SERIALIZER_STATUS_COMMA; } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_end_of_record; } return(0); } /* ********************************** */ static void ndpi_serialize_json_pre(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->status & NDPI_SERIALIZER_STATUS_EOR) { serializer->size_used--; /* Remove ']' */ serializer->status &= ~NDPI_SERIALIZER_STATUS_EOR; serializer->buffer[serializer->size_used++] = ','; serializer->buffer[serializer->size_used++] = '{'; } else { if(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) serializer->size_used--; /* Remove ']'*/ serializer->size_used--; /* Remove '}'*/ } if(serializer->status & NDPI_SERIALIZER_STATUS_COMMA) serializer->buffer[serializer->size_used++] = ','; } /* ********************************** */ static void ndpi_serialize_json_post(ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; serializer->buffer[serializer->size_used++] = '}'; if(serializer->status & NDPI_SERIALIZER_STATUS_ARRAY) serializer->buffer[serializer->size_used++] = ']'; serializer->status |= NDPI_SERIALIZER_STATUS_COMMA; } /* ********************************** */ int ndpi_serialize_uint32_uint32(ndpi_serializer *_serializer, u_int32_t key, u_int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 24; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "\"%u\":%u", key, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%u", (serializer->size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint32; ndpi_serialize_single_uint32(_serializer, key); ndpi_serialize_single_uint32(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_uint32_uint64(ndpi_serializer *_serializer, u_int32_t key, u_int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int16_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int64_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 32; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "\"%u\":%llu", key, (unsigned long long)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%llu", (serializer->size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_uint64; ndpi_serialize_single_uint32(_serializer, key); ndpi_serialize_single_uint64(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_uint32_string(ndpi_serializer *_serializer, u_int32_t key, const char *_value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; const char *value = _value ? _value : ""; u_int16_t slen = strlen(value); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int16_t) /* len */ + slen; if(serializer->fmt == ndpi_serialization_format_json) needed += 24 + slen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "\"%u\":", key); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += ndpi_json_string_escape(value, slen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%s", (serializer->size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_uint32_string; ndpi_serialize_single_uint32(_serializer, key); ndpi_serialize_single_string(_serializer, value, slen); } return(0); } /* ********************************** */ int ndpi_serialize_string_int32(ndpi_serializer *_serializer, const char *key, int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int16_t klen = strlen(key); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":%d", value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%d", (serializer->size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int32; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_uint32(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_int64(ndpi_serializer *_serializer, const char *key, int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int16_t klen = strlen(key); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":%lld", (long long int)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%lld", (serializer->size_used > 0) ? serializer->csv_separator : "", (long long int)value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_int64; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_uint32(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_uint32(ndpi_serializer *_serializer, const char *key, u_int32_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int16_t klen = strlen(key); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int32_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":%u", value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%u", (serializer->size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint32; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_uint32(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_uint32_format(ndpi_serializer *_serializer, const char *key, u_int32_t value, const char *format) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; if(serializer->fmt == ndpi_serialization_format_json) { /* JSON supports base 10 numbers only http://cjihrig.com/blog/json-overview/ */ return(ndpi_serialize_string_uint32(_serializer, key, value)); } else return(ndpi_serialize_string_uint32_format(_serializer, key, value, format)); } /* ********************************** */ int ndpi_serialize_string_uint64(ndpi_serializer *_serializer, const char *key, u_int64_t value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int16_t klen = strlen(key); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(u_int64_t); if(serializer->fmt == ndpi_serialization_format_json) needed += 32 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":%llu", (unsigned long long)value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%llu", (serializer->size_used > 0) ? serializer->csv_separator : "", (unsigned long long)value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_uint64; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_uint64(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_float(ndpi_serializer *_serializer, const char *key, float value, const char *format /* e.f. "%.2f" */) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; u_int16_t klen = strlen(key); u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen /* key */ + sizeof(float); if(serializer->fmt == ndpi_serialization_format_json) needed += 32 + klen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->buffer[serializer->size_used] = ':'; serializer->size_used++; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, format, value); ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { if(serializer->size_used > 0) serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s", serializer->csv_separator); serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, format, value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_float; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_float(_serializer, value); } return(0); } /* ********************************** */ int ndpi_serialize_string_string(ndpi_serializer *_serializer, const char *key, const char *_value) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; const char *value = _value ? _value : ""; u_int16_t klen = strlen(key), vlen = strlen(value); u_int32_t needed = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + klen + sizeof(u_int16_t) /* len */ + vlen; u_int32_t buff_diff = serializer->buffer_size - serializer->size_used; if(serializer->fmt == ndpi_serialization_format_json) needed += 16 + klen + vlen; if(buff_diff < needed) { if(ndpi_extend_serializer_buffer(_serializer, needed - buff_diff) < 0) return(-1); buff_diff = serializer->buffer_size - serializer->size_used; } if(serializer->fmt == ndpi_serialization_format_json) { ndpi_serialize_json_pre(_serializer); serializer->size_used += ndpi_json_string_escape(key, klen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, ":"); buff_diff = serializer->buffer_size - serializer->size_used; serializer->size_used += ndpi_json_string_escape(value, vlen, (char *) &serializer->buffer[serializer->size_used], buff_diff); buff_diff = serializer->buffer_size - serializer->size_used; ndpi_serialize_json_post(_serializer); } else if(serializer->fmt == ndpi_serialization_format_csv) { serializer->size_used += snprintf((char *) &serializer->buffer[serializer->size_used], buff_diff, "%s%s", (serializer->size_used > 0) ? serializer->csv_separator : "", value); } else { serializer->buffer[serializer->size_used++] = ndpi_serialization_string_string; ndpi_serialize_single_string(_serializer, key, klen); ndpi_serialize_single_string(_serializer, value, vlen); } return(0); } /* ********************************** */ /* ********************************** */ int ndpi_init_deserializer_buf(ndpi_deserializer *_deserializer, u_int8_t *serialized_buffer, u_int32_t serialized_buffer_len) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(serialized_buffer_len < (2 * sizeof(u_int8_t))) return(-1); deserializer->buffer = serialized_buffer; if(deserializer->buffer[0] != 1) return(-2); /* Invalid version */ deserializer->buffer_size = serialized_buffer_len; deserializer->fmt = deserializer->buffer[1]; ndpi_reset_serializer(_deserializer); return(0); } /* ********************************** */ int ndpi_init_deserializer(ndpi_deserializer *deserializer, ndpi_serializer *_serializer) { ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer; return(ndpi_init_deserializer_buf(deserializer, serializer->buffer, serializer->size_used)); } /* ********************************** */ ndpi_serialization_element_type ndpi_deserialize_get_nextitem_type(ndpi_deserializer *_deserializer) { ndpi_serialization_element_type et; ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(deserializer->size_used >= deserializer->buffer_size) return(ndpi_serialization_unknown); et = (ndpi_serialization_element_type) deserializer->buffer[deserializer->size_used]; return et; } /* ********************************** */ int ndpi_deserialize_end_of_record(ndpi_deserializer *_deserializer) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_end_of_record) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int16_t expected = sizeof(u_int8_t) /* type */; if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_uint32_uint32(ndpi_deserializer *_deserializer, u_int32_t *key, u_int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_uint32) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int16_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int32_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_uint32(_deserializer, key); ndpi_deserialize_single_uint32(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_uint32_uint64(ndpi_deserializer *_deserializer, u_int32_t *key, u_int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_uint64) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int16_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int64_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_uint32(_deserializer, key); ndpi_deserialize_single_uint64(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_uint32_string(ndpi_deserializer *_deserializer, u_int32_t *key, ndpi_string *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_uint32_string) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int32_t) /* key */ + sizeof(u_int16_t) /* len */; if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_uint32(_deserializer, key); ndpi_deserialize_single_string(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_int32(ndpi_deserializer *_deserializer, ndpi_string *key, int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_int32) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(int32_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_int32(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_int64(ndpi_deserializer *_deserializer, ndpi_string *key, int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_int64) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(int64_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_int64(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_uint32(ndpi_deserializer *_deserializer, ndpi_string *key, u_int32_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_uint32) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(u_int32_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_uint32(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_uint64(ndpi_deserializer *_deserializer, ndpi_string *key, u_int64_t *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_uint64) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(u_int64_t); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_uint64(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_float(ndpi_deserializer *_deserializer, ndpi_string *key, float *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_float) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(float); if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_float(_deserializer, value); return(0); } else return(-1); } /* ********************************** */ int ndpi_deserialize_string_string(ndpi_deserializer *_deserializer, ndpi_string *key, ndpi_string *value) { ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer; if(ndpi_deserialize_get_nextitem_type(_deserializer) == ndpi_serialization_string_string) { u_int32_t buff_diff = deserializer->buffer_size - deserializer->size_used; u_int32_t expected = sizeof(u_int8_t) /* type */ + sizeof(u_int16_t) /* key len */ + sizeof(u_int16_t) /* len */; if(buff_diff < expected) return(-2); deserializer->size_used++; /* Skip element type */ ndpi_deserialize_single_string(_deserializer, key); ndpi_deserialize_single_string(_deserializer, value); return(0); } else return(-1); } /* ********************************** */