diff --git a/contrib/nDPIsrvd.h b/contrib/nDPIsrvd.h index 568e9befc..320fdac08 100644 --- a/contrib/nDPIsrvd.h +++ b/contrib/nDPIsrvd.h @@ -1,18 +1,223 @@ #ifndef NDPISRVD_H #define NDPISRVD_H 1 +#include +#include +#include +#include +#include +#include + +#include "config.h" +#include "jsmn/jsmn.h" + struct nDPIsrvd_socket { int fd; + int socket_family; + union { - struct { + struct + { char const * dst_ip; unsigned short dst_port; - } ip; - struct { + } ip_socket; + struct + { char * path; - } unix; + } unix_socket; } address; + + struct + { + char raw[NETWORK_BUFFER_MAX_SIZE]; + size_t used; + char * json_string; + size_t json_string_start; + unsigned long long int json_string_length; + } buffer; + + struct + { + jsmn_parser parser; + jsmntok_t tokens[128]; + int current_token; + int tokens_found; + } jsmn; }; +#define FIRST_ENUM_VALUE 1 + +enum nDPIsrvd_connect_return +{ + CONNECT_OK = FIRST_ENUM_VALUE, + CONNECT_ERROR_SOCKET, + CONNECT_ERROR_PTON, + CONNECT_ERROR, + CONNECT_LAST_ENUM_VALUE +}; + +enum nDPIsrvd_read_return +{ + READ_OK = CONNECT_LAST_ENUM_VALUE, + READ_PEER_DISCONNECT, + READ_ERROR, + READ_LAST_ENUM_VALUE +}; + +enum nDPIsrvd_parse_return +{ + PARSE_OK = READ_LAST_ENUM_VALUE, + PARSE_INVALID_OPENING_CHAR, + PARSE_SIZE_EXCEEDS_CONVERSION_LIMIT, + PARSE_SIZE_MISSING, + PARSE_STRING_TOO_BIG, + PARSE_INVALID_CLOSING_CHAR, + PARSE_JSMN_ERROR, + PARSE_LAST_ENUM_VALUE +}; + +enum nDPIsrvd_callback_return +{ + CALLBACK_OK = PARSE_LAST_ENUM_VALUE, + CALLBACK_ERROR, + CALLBACK_LAST_ENUM_VALUE +}; + +typedef enum nDPIsrvd_callback_return (*json_callback)(struct nDPIsrvd_socket * const sock, void * user_data); + +static inline struct nDPIsrvd_socket * nDPIsrvd_init(void) +{ + struct nDPIsrvd_socket * sock = (struct nDPIsrvd_socket *)malloc(sizeof(*sock)); + + if (sock != NULL) + { + sock->fd = -1; + sock->socket_family = -1; + } + return sock; +} + +static inline enum nDPIsrvd_connect_return nDPIsrvd_connect_ip(struct nDPIsrvd_socket * const sock, + char const * dst_ip, + unsigned short dst_port) +{ + struct sockaddr_in remote_addr = {}; + + sock->socket_family = remote_addr.sin_family = AF_INET; + sock->fd = socket(sock->socket_family, SOCK_STREAM, 0); + + if (sock->fd < 0) + { + return CONNECT_ERROR_SOCKET; + } + + if (inet_pton(sock->socket_family, &dst_ip[0], &remote_addr.sin_addr) != 1) + { + return CONNECT_ERROR_PTON; + } + remote_addr.sin_port = htons(dst_port); + + if (connect(sock->fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr)) != 0) + { + return CONNECT_ERROR; + } + + return CONNECT_OK; +} + +static inline enum nDPIsrvd_connect_return nDPIsrvd_connect_unix(struct nDPIsrvd_socket * const sock, + char const * const path) +{ + (void)sock; + (void)path; + + return CONNECT_OK; +} + +static inline enum nDPIsrvd_read_return nDPIsrvd_read(struct nDPIsrvd_socket * const sock) +{ + ssize_t bytes_read = + read(sock->fd, sock->buffer.raw + sock->buffer.used, sizeof(sock->buffer.raw) - sock->buffer.used); + + if (bytes_read == 0) + { + return READ_PEER_DISCONNECT; + } + if (bytes_read < 0) + { + return READ_ERROR; + } + + sock->buffer.used += bytes_read; + + return READ_OK; +} + +static inline enum nDPIsrvd_parse_return nDPIsrvd_parse(struct nDPIsrvd_socket * const sock, + json_callback cb, + void * user_data) +{ + while (sock->buffer.used >= nDPIsrvd_JSON_BYTES + 1) + { + if (sock->buffer.raw[nDPIsrvd_JSON_BYTES] != '{') + { + return PARSE_INVALID_OPENING_CHAR; + } + + errno = 0; + sock->buffer.json_string_length = strtoull((const char *)sock->buffer.raw, &sock->buffer.json_string, 10); + sock->buffer.json_string_length += sock->buffer.json_string - sock->buffer.raw; + sock->buffer.json_string_start = sock->buffer.json_string - sock->buffer.raw; + + if (errno == ERANGE) + { + return PARSE_SIZE_EXCEEDS_CONVERSION_LIMIT; + } + if (sock->buffer.json_string == sock->buffer.raw) + { + return PARSE_SIZE_MISSING; + } + if (sock->buffer.json_string_length > sizeof(sock->buffer.raw)) + { + return PARSE_STRING_TOO_BIG; + } + if (sock->buffer.json_string_length > sock->buffer.used) + { + break; + } + + if (sock->buffer.raw[sock->buffer.json_string_length - 1] != '}') + { + return PARSE_INVALID_CLOSING_CHAR; + } + + jsmn_init(&sock->jsmn.parser); + sock->jsmn.tokens_found = jsmn_parse(&sock->jsmn.parser, + (char *)(sock->buffer.raw + sock->buffer.json_string_start), + sock->buffer.json_string_length - sock->buffer.json_string_start, + sock->jsmn.tokens, + sizeof(sock->jsmn.tokens) / sizeof(sock->jsmn.tokens[0])); + if (sock->jsmn.tokens_found < 0 || sock->jsmn.tokens[0].type != JSMN_OBJECT) + { + return PARSE_JSMN_ERROR; + } + + for (sock->jsmn.current_token = 1; sock->jsmn.current_token < sock->jsmn.tokens_found; + sock->jsmn.current_token++) + { + cb(sock, user_data); + } + + memmove(sock->buffer.raw, + sock->buffer.raw + sock->buffer.json_string_length, + sock->buffer.used - sock->buffer.json_string_length); + sock->buffer.used -= sock->buffer.json_string_length; + sock->buffer.json_string_length = 0; + sock->buffer.json_string_start = 0; + } + + return PARSE_OK; +} + #endif diff --git a/examples/c-captured/c-captured.c b/examples/c-captured/c-captured.c index eb56470e7..8b6785aea 100644 --- a/examples/c-captured/c-captured.c +++ b/examples/c-captured/c-captured.c @@ -7,127 +7,68 @@ #include #include -#include "config.h" -#include "jsmn.h" +#include "nDPIsrvd.h" +#include "jsmn/jsmn.h" static char serv_listen_addr[INET_ADDRSTRLEN] = DISTRIBUTOR_HOST; static uint16_t serv_listen_port = DISTRIBUTOR_PORT; -int main(void) +static enum nDPIsrvd_callback_return nDPIsrvd_json_callback(struct nDPIsrvd_socket * const sock, void * user_data) { - int sockfd = socket(AF_INET, SOCK_STREAM, 0); - struct sockaddr_in remote_addr = {}; - socklen_t remote_addrlen = sizeof(remote_addr); - uint8_t buf[NETWORK_BUFFER_MAX_SIZE]; - size_t buf_used = 0; - size_t json_start = 0; - unsigned long long int json_bytes = 0; - jsmn_parser parser; - jsmntok_t tokens[128]; + (void)user_data; - if (sockfd < 0) + if (sock->jsmn.current_token % 2 == 1) { - perror("socket"); + printf("[%.*s : ", + sock->jsmn.tokens[sock->jsmn.current_token].end - sock->jsmn.tokens[sock->jsmn.current_token].start, + sock->buffer.json_string + sock->jsmn.tokens[sock->jsmn.current_token].start); + } + else + { + printf("%.*s] ", + sock->jsmn.tokens[sock->jsmn.current_token].end - sock->jsmn.tokens[sock->jsmn.current_token].start, + sock->buffer.json_string + sock->jsmn.tokens[sock->jsmn.current_token].start); + } + + return CALLBACK_OK; +} + +int main(int argc, char ** argv) +{ + struct nDPIsrvd_socket * sock = nDPIsrvd_init(); + + (void)argc; + + if (sock == NULL) + { + fprintf(stderr, "%s: nDPIsrvd socket memory allocation failed!\n", argv[0]); return 1; } - remote_addr.sin_family = AF_INET; - if (inet_pton(AF_INET, &serv_listen_addr[0], &remote_addr.sin_addr) != 1) + printf("Connecting to %s:%u\n", serv_listen_addr, serv_listen_port); + enum nDPIsrvd_connect_return connect_ret = nDPIsrvd_connect_ip(sock, serv_listen_addr, serv_listen_port); + if (connect_ret != CONNECT_OK) { - perror("inet_pton"); - return 1; - } - remote_addr.sin_port = htons(serv_listen_port); - - if (connect(sockfd, (struct sockaddr *)&remote_addr, remote_addrlen) != 0) - { - perror("connect"); + fprintf(stderr, "%s: nDPIsrvd socket connect failed!\n", argv[0]); return 1; } while (1) { errno = 0; - ssize_t bytes_read = read(sockfd, buf + buf_used, sizeof(buf) - buf_used); - - if (bytes_read <= 0 || errno != 0) + enum nDPIsrvd_read_return read_ret = nDPIsrvd_read(sock); + if (read_ret != READ_OK) { - fprintf(stderr, "Remote end disconnected.\n"); break; } - buf_used += bytes_read; - while (buf_used >= nDPIsrvd_JSON_BYTES + 1) + enum nDPIsrvd_parse_return parse_ret = nDPIsrvd_parse(sock, nDPIsrvd_json_callback, NULL); + switch (parse_ret) { - if (buf[nDPIsrvd_JSON_BYTES] != '{') - { - fprintf(stderr, "BUG: JSON invalid opening character: '%c'\n", buf[nDPIsrvd_JSON_BYTES]); - exit(1); - } - - char * json_str_start = NULL; - json_bytes = strtoull((char *)buf, &json_str_start, 10); - json_bytes += (uint8_t *)json_str_start - buf; - json_start = (uint8_t *)json_str_start - buf; - - if (errno == ERANGE) - { - fprintf(stderr, "BUG: Size of JSON exceeds limit\n"); - exit(1); - } - if ((uint8_t *)json_str_start == buf) - { - fprintf(stderr, "BUG: Missing size before JSON string: \"%.*s\"\n", nDPIsrvd_JSON_BYTES, buf); - exit(1); - } - if (json_bytes > sizeof(buf)) - { - fprintf(stderr, "BUG: JSON string too big: %llu > %zu\n", json_bytes, sizeof(buf)); - exit(1); - } - if (json_bytes > buf_used) - { + default: break; - } - - if (buf[json_bytes - 1] != '}') - { - fprintf(stderr, "BUG: Invalid JSON string: %.*s\n", (int)json_bytes, buf); - exit(1); - } - - int r; - jsmn_init(&parser); - r = jsmn_parse(&parser, - (char *)(buf + json_start), - json_bytes - json_start, - tokens, - sizeof(tokens) / sizeof(tokens[0])); - if (r < 0 || tokens[0].type != JSMN_OBJECT) - { - fprintf(stderr, "JSON parsing failed with return value %d at position %u\n", r, parser.pos); - fprintf(stderr, "JSON string: '%.*s'\n", (int)(json_bytes - json_start), (char *)(buf + json_start)); - exit(1); - } - - for (int i = 1; i < r; i++) - { - if (i % 2 == 1) - { - printf("[%.*s : ", tokens[i].end - tokens[i].start, (char *)(buf + json_start) + tokens[i].start); - } - else - { - printf("%.*s] ", tokens[i].end - tokens[i].start, (char *)(buf + json_start) + tokens[i].start); - } - } - printf("EoF\n"); - - memmove(buf, buf + json_bytes, buf_used - json_bytes); - buf_used -= json_bytes; - json_bytes = 0; - json_start = 0; } + printf("EoF\n"); } return 0;