/* * Copyright (c) 2013-2016, Wind River Systems, Inc. * * 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) Neither the name of Wind River Systems 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 THE COPYRIGHT HOLDERS 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 COPYRIGHT HOLDER 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. */ /** This file is used to test functions in file host_guest_msg.c. Functions under test are directly copied to here to simplify compile. Once tested and refactored, the functions can be copied back to their original location with appropriate debug traces. build: gcc -I. -o test_host_guest_msg test_host_guest_msg.c -ljson-c usage: binary can be executed directly on a linux desktop. ./test_host_guest_msg - run without parameters to check TCs PASS or FAIL ./test_host_guest_msg 1 - show error logs ./test_host_guest_msg 2 - show error and debug logs */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //number of guest #define NUM_GUEST 3 //number of reads #define NUM_READS 3 int debug = 0; #define PRINT_ERR(format, ...) if(debug >= 1) printf(format, ##__VA_ARGS__) #define PRINT_DEBUG(format, ...) if(debug >= 2) printf(format, ##__VA_ARGS__) // One tokener for each instance connection serve as reassembly buffer struct json_tokener* tok[NUM_GUEST]; void process_msg(json_object *jobj_msg, int fd); //---------------------------------------------------------- // Functions Under Test //---------------------------------------------------------- void parser(void *buf, ssize_t len, int fd, json_tokener* tok, int newline_found) { PRINT_DEBUG("parser: len=%lu, buf=%s\n", len, (char *)buf); json_object *jobj = json_tokener_parse_ex(tok, buf, len); enum json_tokener_error jerr = json_tokener_get_error(tok); if (jerr == json_tokener_success) { process_msg(jobj, fd); json_object_put(jobj); return; } else if (jerr == json_tokener_continue) { // partial JSON is parsed , continue to read from socket PRINT_DEBUG("partial message parsed, continue read socket\n"); PRINT_DEBUG("processed so far buf=%s\n", (char *)buf); // if newline was found in the middle of the buffer, the message should // be completed at this point. Throw out incomplete message by resetting // tokener. if (newline_found) { PRINT_DEBUG("newline_found. throw out the partial message\n"); json_tokener_reset(tok); } } else { PRINT_ERR("JSON Parsing Error: %s\n", json_tokener_error_desc(jerr)); json_tokener_reset(tok); } } //---------------------------------------------------------- // Functions Under Test //---------------------------------------------------------- void handle_virtio_serial_msg(void *buf, ssize_t len, int fd, json_tokener* tok) { void *origbuf = buf; void *newline; ssize_t len_head; next: if (len == 0) return; PRINT_DEBUG("analyzing buffer at offset %lu, len %zd\n", buf-origbuf, len); // search for newline as delimiter newline = memchr(buf, '\n', len); if (newline) { PRINT_DEBUG("found newline start at offset %lu\n", newline - origbuf); // split buffer to head and tail at the location of newline. // feed the head to the parser and recursively process the tail. len_head = newline-buf; // parse head if (len_head > 0) parser(buf, len_head, fd, tok, 1); // start of the tail: skip newline buf += len_head+1; // length of the tail: deduct 1 for the newline character len -= len_head+1; // continue to process the tail. goto next; } else { parser(buf, len, fd, tok, 0); } } // buffer to simulate socket to read, one socket per guest void *socket[NUM_GUEST][NUM_READS]; // resulting parsed socket char socket_processed[NUM_GUEST][NUM_READS][500]; // expected result char *socket_expected[NUM_GUEST][NUM_READS]; // track current buffer being processed for particular guest int current_processed[NUM_GUEST]; void free_tok() { int fd; for (fd=0; fd 1) debug = atoi(argv[1]); setup_test(); printf("\n===== TC1 one valid message per read: "); init_socket_tc1(); for (read = 0; read