layer_state_t posix_asynch_io_layer_on_close( layer_connectivity_t* context ) { // prepare return value layer_state_t ret = LAYER_STATE_OK; // posix_asynch_data_t* posix_asynch_data = ( posix_asynch_data_t* ) context->self->user_data; if( shutdown( posix_asynch_data->socket_fd, SHUT_RDWR ) == -1 ) { xi_set_err( XI_SOCKET_SHUTDOWN_ERROR ); close( posix_asynch_data->socket_fd ); // just in case ret = LAYER_STATE_ERROR; goto err_handling; } // close the connection & the socket if( close( posix_asynch_data->socket_fd ) == -1 ) { xi_set_err( XI_SOCKET_CLOSE_ERROR ); ret = LAYER_STATE_ERROR; goto err_handling; } err_handling: // cleanup the memory if( posix_asynch_data ) { XI_SAFE_FREE( posix_asynch_data ); } return ret; }
void test_parse_http(void* data) { (void)(data); // prepare structure http_response_t response; memset( &response, 0, sizeof( http_response_t ) ); // simplest { const char test_response[] = "HTTP/1.1 200 OK\r\n" "Date: Sun, 14 Apr 2013 20:20:01 GMT\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Content-Length: 0\r\n" "Connection: keep-alive\r\n" "X-Request-Id: 9de9ac7071bdbf105804ce0eaf7979adc77f6e25\r\n" "Cache-Control: max-age=0\r\n" "Vary: Accept-Encoding\r\n\r\n"; http_response_t* ret = parse_http( &response, test_response ); tt_assert( ret != 0 ); tt_assert( ret->http_headers_size == 7 ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); // with content { const char test_response[] = "HTTP/1.1 404 Not Found\r\n" "Date: Sun, 14 Apr 2013 20:20:01 GMT\r\n" "Content-Type: text/plain; charset=utf-8\r\n" "Content-Length: 9\r\n" "Connection: keep-alive\r\n" "Vary: Accept-Encoding\r\n\r\n" "Not Found"; http_response_t* ret = parse_http( &response, test_response ); tt_assert( ret != 0 ); tt_assert( ret->http_headers_size == 5 ); tt_assert( strcmp( ret->http_content, "Not Found" ) == 0 ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
layer_state_t contiki_io_layer_connect( layer_connectivity_t* context , const void* data , const layer_hint_t hint ) { XI_UNUSED( hint ); uip_ipaddr_t *ip; resolv_status_t dns_status; xi_connection_data_t* connection_data; layer_t* layer = ( layer_t* ) context->self; contiki_data_t* s = (contiki_data_t* ) layer->user_data; struct uip_conn *c; s->process = PROCESS_CURRENT(); if (s->state == CONNECTED) { xi_debug_logger( "Connecting to the endpoint [ok]" ); return LAYER_STATE_OK; } else if (s->state == CONNECTING) { return LAYER_STATE_WANT_WRITE; } else if (s->state == CLOSED) { connection_data = ( xi_connection_data_t* ) data; dns_status = resolv_lookup(connection_data->address, &ip); if (dns_status != RESOLV_STATUS_CACHED) { if (dns_status == RESOLV_STATUS_NOT_FOUND || dns_status == RESOLV_STATUS_ERROR) { xi_debug_logger( "Getting Host by name [failed]" ); xi_set_err( XI_SOCKET_GETHOSTBYNAME_ERROR ); return LAYER_STATE_ERROR; } if (dns_status != RESOLV_STATUS_RESOLVING) { resolv_query(connection_data->address); } return LAYER_STATE_WANT_WRITE; /* no IP, cannot go further */ } xi_debug_logger( "Getting Host by name [ok]" ); xi_debug_logger( "Connecting to the endpoint..." ); c = uip_connect(ip, uip_htons(connection_data->port)); if(c == NULL) { xi_debug_logger( "Connecting to the endpoint [failed]" ); xi_set_err( XI_SOCKET_CONNECTION_ERROR ); return LAYER_STATE_ERROR; } s->state = CONNECTING; c->appstate.p = &xively_process; c->appstate.state = s; tcpip_poll_tcp(c); return LAYER_STATE_WANT_WRITE; } return LAYER_STATE_ERROR; }
void test_csv_encode_datapoint( void* data ) { (void)(data); // prepare the data xi_datapoint_t data_point; memset( &data_point, 0, sizeof( xi_datapoint_t ) ); // data // const char datastream_id[] = "test_datastream"; // test { data_point.value.i32_value = 216; const char* o = csv_encode_datapoint( &data_point ); // test values tt_assert( o != 0 ); tt_assert( strcmp( o, "216\n" ) == 0 ); } /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
void test_csv_decode_datapoint(void *data) { (void)(data); // prepare the data xi_datapoint_t data_point; memset( &data_point, 0, sizeof( xi_datapoint_t ) ); // data const char test_data[] = "2013-01-01T18:44:21.423452Z,216"; // test const xi_datapoint_t* o = csv_decode_datapoint( test_data, &data_point ); // test tt_assert( o != 0 ); tt_assert( data_point.value.i32_value == 216 ); tt_assert( data_point.timestamp.micro == 423452 ); /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
void test_http_construct_content(void *data) { (void)(data); // simple test { const char expected[] = "Content-Type: text/plain\r\n" "Content-Length: 128\r\n"; const char* ret = http_construct_content( 128 ); tt_assert( strcmp( expected, ret ) == 0 ); } end: xi_set_err( XI_NO_ERR ); ; }
void test_create_and_delete_context(void* data) { (void)(data); #define TEST_API_KEY_STRING "abcXYZ2398138172jckajf39djas_dasd-TyX" #define TEST_FEED_ID_NUMBER 123456 xi_context_t* xi_context = xi_create_context( XI_HTTP , TEST_API_KEY_STRING , TEST_FEED_ID_NUMBER ); tt_assert( xi_context != 0 ); tt_assert( strcmp( xi_context->api_key, TEST_API_KEY_STRING ) == 0 ); tt_assert( xi_context->feed_id == TEST_FEED_ID_NUMBER ); xi_delete_context( xi_context ); end: xi_set_err( XI_NO_ERR ); ; }
void test_csv_decode_datapoint_error( void * data ) { (void)(data); // prepare the data xi_datapoint_t data_point; memset( &data_point, 0, sizeof( xi_datapoint_t ) ); { // test case broken data // prepare data const char test_data[] = "213-01-01T18:44:21.423452Z,216"; // call function const xi_datapoint_t* o = csv_decode_datapoint( test_data, &data_point ); // test values tt_assert( o == 0 ); tt_assert( XI_CSV_TIME_CONVERTION_ERROR == xi_get_last_error() ); } { // test case wrong content // prepare data const char test_data[] = "2013-01-01T18:44:21,216"; // call function const xi_datapoint_t* o = csv_decode_datapoint( test_data, &data_point ); // test values tt_assert( o == 0 ); tt_assert( XI_CSV_DECODE_DATAPOINT_PARSER_ERROR == xi_get_last_error() ); } /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
void test_csv_encode_create_datastream_error( void* data ) { (void)(data); // prepare the data xi_datapoint_t data_point; memset( &data_point, 0, sizeof( xi_datapoint_t ) ); // data const char datastream_id[] = "abcdefghabcdefghabcdefghabcdefgh" // 32 * 8 + 1 = 257 should exceed the capacity "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "abcdefghabcdefghabcdefghabcdefgh" "a"; // 1 additional // test { data_point.value.i32_value = 216; const char* o = csv_encode_create_datastream( datastream_id, &data_point ); // test values tt_assert( o == 0 ); tt_assert( XI_CSV_ENCODE_DATASTREAM_BUFFER_OVERRUN == xi_get_last_error() ); } /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
void test_http_construct_request(void *data) { (void)(data); // simple test { const char expected[] = "GET /v2/feeds/128/datastreams/test.csv HTTP/1.1\r\n" "Host: " XI_HOST "\r\n" "User-Agent: " XI_USER_AGENT "\r\n" "Accept: */*\r\n" "X-ApiKey: apikey\r\n"; xi_feed_id_t feed_id = 128; const char* ret = http_construct_request_datastream( "GET", &feed_id, "test", "apikey" ); tt_assert( strcmp( expected, ret ) == 0 ); } // simple test2 { const char expected[] = "GET /v2/feeds/128/datastreams.csv HTTP/1.1\r\n" "Host: " XI_HOST "\r\n" "User-Agent: " XI_USER_AGENT "\r\n" "Accept: */*\r\n" "X-ApiKey: apikey\r\n"; xi_feed_id_t feed_id = 128; const char* ret = http_construct_request_datastream( "GET", &feed_id, 0, "apikey" ); tt_assert( strcmp( expected, ret ) == 0 ); } end: xi_set_err( XI_NO_ERR ); ; }
void test_parse_http_status(void* data) { (void)(data); // prepare structure http_response_t response; memset( &response, 0, sizeof( http_response_t ) ); // simplest { const char test_status1[] = "HTTP/1.1 200 OK\r\n" "Date: Sun, 14 Apr 2013 19:32:40 GMT\r\n"; const char* ret = parse_http_status( &response, test_status1 ); tt_assert( ret != 0 ); tt_assert( response.http_version1 == 1 ); tt_assert( response.http_version2 == 1 ); tt_assert( response.http_status == 200 ); tt_assert( strcmp( response.http_status_string, "OK" ) == 0 ); tt_assert( ret == test_status1 + 17 ); } // simplest2 { const char test_status1[] = "HTTP/1.1 404 Not Found\r\n" "Date: Sun, 14 Apr 2013 19:32:40 GMT\r\n"; const char* ret = parse_http_status( &response, test_status1 ); tt_assert( ret != 0 ); tt_assert( response.http_version1 == 1 ); tt_assert( response.http_version2 == 1 ); tt_assert( response.http_status == 404 ); tt_assert( strcmp( response.http_status_string, "Not Found" ) == 0 ); tt_assert( ret == test_status1 + 24 ); } // clean memset( &response, 0, sizeof( http_response_t ) ); // malformed { const char test_status1[] = "HTTP1.1 200 OK\r\n" "Date: Sun, 14 Apr 2013 19:32:40 GMT\r\n"; const char* ret = parse_http_status( &response, test_status1 ); tt_assert( ret == 0 ); tt_assert( xi_get_last_error() == XI_HTTP_STATUS_PARSE_ERROR ); } // clean xi_set_err( XI_NO_ERR ); memset( &response, 0, sizeof( http_response_t ) ); // malformed2 { const char test_status1[] = "HTTP1.1 200 OK"; const char* ret = parse_http_status( &response, test_status1 ); tt_assert( ret == 0 ); tt_assert( xi_get_last_error() == XI_HTTP_STATUS_PARSE_ERROR ); } /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
void test_parse_http_header(void *data) { (void)(data); // prepare structure http_response_t response; memset( &response, 0, sizeof( http_response_t ) ); // simplest { const char test_header1[] = "Date: Sun, 14 Apr 2013 19:32:40 GMT\r\n"; const char* ret = parse_http_header( &response, test_header1 ); tt_assert( ret != 0 ); tt_assert( response.http_headers_size == 1 ); tt_assert( response.http_headers[ 0 ].header_type == XI_HTTP_HEADER_DATE ); tt_assert( strcmp( response.http_headers[ 0 ].name, "Date" ) == 0 ); tt_assert( strcmp( response.http_headers[ 0 ].value, "Sun, 14 Apr 2013 19:32:40 GMT" ) == 0 ); tt_assert( response.http_headers_checklist[ ( size_t ) XI_HTTP_HEADER_DATE ] == &response.http_headers[ 0 ] ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); // simplest2 { const char test_header1[] = "Content-Length: 0\r\n"; const char* ret = parse_http_header( &response, test_header1 ); tt_assert( ret != 0 ); tt_assert( response.http_headers_size == 1 ); tt_assert( response.http_headers[ 0 ].header_type == XI_HTTP_HEADER_CONTENT_LENGTH ); tt_assert( strcmp( response.http_headers[ 0 ].name, "Content-Length" ) == 0 ); tt_assert( strcmp( response.http_headers[ 0 ].value, "0" ) == 0 ); tt_assert( response.http_headers_checklist[ ( size_t ) XI_HTTP_HEADER_CONTENT_LENGTH ] == &response.http_headers[ 0 ] ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); // simplest3 { const char test_header1[] = "Imaginary-Header: 0\r\n"; const char* ret = parse_http_header( &response, test_header1 ); tt_assert( ret != 0 ); tt_assert( response.http_headers_size == 1 ); tt_assert( response.http_headers[ 0 ].header_type == XI_HTTP_HEADER_UNKNOWN ); tt_assert( strcmp( response.http_headers[ 0 ].name, "Imaginary-Header" ) == 0 ); tt_assert( strcmp( response.http_headers[ 0 ].value, "0" ) == 0 ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); // malformed { const char test_header1[] = "Date Sun, 14 Apr 2013 19-32-40 GMT\r\n"; const char* ret = parse_http_header( &response, test_header1 ); tt_assert( ret == 0 ); tt_assert( xi_get_last_error() == XI_HTTP_HEADER_PARSE_ERROR ); } memset( &response, 0, sizeof( http_response_t ) ); xi_set_err( XI_NO_ERR ); // malformed { const char test_header1[] = "Date: Sun, 14 Apr 2013 19:32:40 GMT"; const char* ret = parse_http_header( &response, test_header1 ); tt_assert( ret == 0 ); tt_assert( xi_get_last_error() == XI_HTTP_HEADER_PARSE_ERROR ); } /* Every test-case function needs to finish with an "end:" label and (optionally) code to clean up local variables. */ end: xi_set_err( XI_NO_ERR ); ; }
layer_state_t posix_asynch_io_layer_connect( layer_connectivity_t* context , const void* data , const layer_hint_t hint ) { XI_UNUSED( hint ); static uint16_t cs = 0; // local coroutine prereserved state xi_connection_data_t* connection_data = ( xi_connection_data_t* ) data; layer_t* layer = ( layer_t* ) context->self; posix_asynch_data_t* posix_asynch_data = ( posix_asynch_data_t* ) layer->user_data; BEGIN_CORO( cs ) xi_debug_format( "Connecting layer [%d] to the endpoint", layer->layer_type_id ); // socket specific data struct sockaddr_in name; struct hostent* hostinfo; // get the hostaddress hostinfo = gethostbyname( connection_data->address ); // if null it means that the address has not been founded if( hostinfo == NULL ) { xi_debug_logger( "Getting Host by name [failed]" ); xi_set_err( XI_SOCKET_GETHOSTBYNAME_ERROR ); goto err_handling; } xi_debug_logger( "Getting Host by name [ok]" ); // set the address and the port for further connection attempt memset( &name, 0, sizeof( struct sockaddr_in ) ); name.sin_family = AF_INET; name.sin_addr = *( ( struct in_addr* ) hostinfo->h_addr ); name.sin_port = htons( connection_data->port ); xi_debug_logger( "Connecting to the endpoint..." ); if( connect( posix_asynch_data->socket_fd, ( struct sockaddr* ) &name, sizeof( struct sockaddr ) ) == -1 ) { if( errno != EINPROGRESS ) { xi_debug_printf( "errno: %d", errno ); xi_debug_logger( "Connecting to the endpoint [failed]" ); xi_set_err( XI_SOCKET_CONNECTION_ERROR ); goto err_handling; } else { YIELD( cs, LAYER_STATE_WANT_WRITE ); // return here whenever we can write } } EXIT( cs, LAYER_STATE_OK ); err_handling: // cleanup the memory if( posix_asynch_data ) { close( posix_asynch_data->socket_fd ); } if( layer->user_data ) { XI_SAFE_FREE( layer->user_data ); } EXIT( cs, LAYER_STATE_ERROR ); END_CORO() }
layer_state_t posix_asynch_io_layer_init( layer_connectivity_t* context , const void* data , const layer_hint_t hint ) { XI_UNUSED( hint ); XI_UNUSED( data ); // PRECONDITIONS assert( context != 0 ); xi_debug_logger( "[posix_io_layer_init]" ); layer_t* layer = ( layer_t* ) context->self; posix_asynch_data_t* posix_asynch_data = xi_alloc( sizeof( posix_asynch_data_t ) ); XI_CHECK_MEMORY( posix_asynch_data ); layer->user_data = ( void* ) posix_asynch_data; xi_debug_logger( "Creating socket..." ); posix_asynch_data->socket_fd = socket( AF_INET, SOCK_STREAM, 0 ); if( posix_asynch_data->socket_fd == -1 ) { xi_debug_logger( "Socket creation [failed]" ); xi_set_err( XI_SOCKET_INITIALIZATION_ERROR ); return 0; } xi_debug_logger( "Setting socket non blocking behaviour..." ); int flags = fcntl( posix_asynch_data->socket_fd, F_GETFL, 0 ); if( flags == -1 ) { xi_debug_logger( "Socket non blocking behaviour [failed]" ); xi_set_err( XI_SOCKET_INITIALIZATION_ERROR ); goto err_handling; } if( fcntl( posix_asynch_data->socket_fd, F_SETFL, flags | O_NONBLOCK ) == -1 ) { xi_debug_logger( "Socket non blocking behaviour [failed]" ); xi_set_err( XI_SOCKET_INITIALIZATION_ERROR ); goto err_handling; } xi_debug_logger( "Socket creation [ok]" ); // POSTCONDITIONS assert( layer->user_data != 0 ); assert( posix_asynch_data->socket_fd != -1 ); return LAYER_STATE_OK; err_handling: // cleanup the memory if( posix_asynch_data ) { close( posix_asynch_data->socket_fd ); } if( layer->user_data ) { XI_SAFE_FREE( layer->user_data ); } return LAYER_STATE_ERROR; }