mirror of
https://github.com/nasa/trick.git
synced 2025-06-14 05:08:22 +00:00
Standardize directory names
Reorganized. Created a new top level include directory that will hold all of Trick's header files. Moved all of the Trick headers to this directory. Created a libexec directory that holds all of the executables that users don't need to execute directly. Changed all of the executables remaining in bin to start with "trick-". In the sim_services directories changed all source files to find the Trick headers in their new location. Since all of the include files are gone in sim_services, removed the src directories as well, moving all of the source files up a level. Moved the makefiles, docs, man, and other architecture independent files into a top level share directory. Renamed lib_${TRICK_HOST_CPU} to lib64 or lib depending on the platform we're currently on. refs #63
This commit is contained in:
@ -0,0 +1,315 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "trick/JSONVariableServerThread.hh"
|
||||
#include "trick/MemoryManager.hh"
|
||||
#include "trick/memorymanager_c_intf.h"
|
||||
#include "trick/exec_proto.h"
|
||||
#include "trick/PythonPrint.hh"
|
||||
#include "trick/tc_proto.h"
|
||||
#include "trick/TrickConstant.hh"
|
||||
|
||||
Trick::JSONVariableServerThread::JSONVariableServerThread(TCDevice * listen_dev) :
|
||||
Trick::ThreadBase("JSONVarServer") {
|
||||
|
||||
connection.disable_handshaking = TC_COMM_TRUE ;
|
||||
connection.blockio_type = TC_COMM_BLOCKIO ;
|
||||
|
||||
tc_accept(listen_dev, &connection);
|
||||
|
||||
// Save the hostname and port of the listen server
|
||||
hostname = listen_dev->hostname ;
|
||||
port = listen_dev->port ;
|
||||
|
||||
incoming_msg = new char[MAX_CMD_LEN] ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# delete the space for incominig_msg.
|
||||
-# These classes are always allocated... free the memory on the way out.
|
||||
*/
|
||||
Trick::JSONVariableServerThread::~JSONVariableServerThread() {
|
||||
delete [] incoming_msg ;
|
||||
delete this ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# Loop until the connection is broken or timed_out
|
||||
-# Call select to wait up to 15 seconds for a message.
|
||||
-# If a message is found, read it into the incoming_msg buffer
|
||||
-# Call parse_request on the incoming_msg buffer
|
||||
-# Disconnect the socket connection
|
||||
*/
|
||||
void * Trick::JSONVariableServerThread::thread_body() {
|
||||
|
||||
int nbytes = -1 ;
|
||||
socklen_t sock_size = sizeof(connection.remoteServAddr) ;
|
||||
fd_set rfds;
|
||||
struct timeval timeout_time = { 15, 0 };
|
||||
bool timed_out = false ;
|
||||
|
||||
while (! timed_out and nbytes != 0 ) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(connection.socket, &rfds);
|
||||
timeout_time.tv_sec = 15 ;
|
||||
select(connection.socket + 1, &rfds, NULL, NULL, &timeout_time);
|
||||
|
||||
if ( FD_ISSET(connection.socket, &rfds)) {
|
||||
nbytes = recvfrom( connection.socket, incoming_msg, MAX_CMD_LEN, 0 ,
|
||||
(struct sockaddr *)&connection.remoteServAddr, &sock_size ) ;
|
||||
//std::cout << "nbytes = " << nbytes << std::endl ;
|
||||
if (nbytes != 0 ) {
|
||||
//std::cout << incoming_msg << std::endl ;
|
||||
parse_request() ;
|
||||
}
|
||||
} else {
|
||||
timed_out = true ;
|
||||
}
|
||||
}
|
||||
tc_disconnect(&connection) ;
|
||||
//std::cout << "closed variable server connection" << std::endl ;
|
||||
|
||||
return NULL ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# scan the incoming message for the command and requested path
|
||||
-# start the return message with a "{"
|
||||
-# if both a command and request is present
|
||||
-# if the command is "GET"
|
||||
-# if the path is "/" call get_top_page
|
||||
-# else if the path starts with "/vars" call get_vars
|
||||
-# else if the path starts with "/commands" call get_commands
|
||||
-# else create an error message reply
|
||||
-# else if the command is "POST" do something at some point.
|
||||
-# else create an error message reply
|
||||
-# else create an error message reply
|
||||
-# close the return message with a "}"
|
||||
-# create the http header for the reply message
|
||||
-# call tc_write to send the reply message
|
||||
*/
|
||||
void Trick::JSONVariableServerThread::parse_request() {
|
||||
// Need to protect against buffer overflow
|
||||
char command[32] ;
|
||||
char path[512] ;
|
||||
std::stringstream ss ;
|
||||
std::stringstream body ;
|
||||
int ret ;
|
||||
|
||||
ret = sscanf(incoming_msg, "%s %s", command , path) ;
|
||||
|
||||
body << "{" << std::endl ;
|
||||
if ( ret == 2 ) {
|
||||
//std::cout << "command = " << command << std::endl ;
|
||||
//std::cout << "path = " << path << std::endl ;
|
||||
|
||||
if ( ! strcmp(command, "GET") ) {
|
||||
if ( ! strcmp(path, "/") ) {
|
||||
// send the top page
|
||||
ret = get_top_page(body) ;
|
||||
} else if ( ! strncmp(path, "/vars", 5)) {
|
||||
// get list of variables or value
|
||||
ret = get_vars(body, &path[5]) ;
|
||||
} else if ( ! strncmp(path, "/commands", 9)) {
|
||||
// get list of commands
|
||||
ret = get_commands(body, &path[9]) ;
|
||||
} else {
|
||||
ret = 404 ;
|
||||
body << " \"name\" : \"" << path << "\" ," << std::endl ;
|
||||
body << " \"message\" : \"Not Found\"" << std::endl ;
|
||||
}
|
||||
} else if ( ! strcmp( command, "POST") ) {
|
||||
//TODO: Allow setting variable values with POST.
|
||||
ret = 405 ;
|
||||
body << " \"verb\" : \"" << command << "\" ," << std::endl ;
|
||||
body << " \"message\" : \"Method not allowed\"" << std::endl ;
|
||||
} else {
|
||||
ret = 405 ;
|
||||
body << " \"verb\" : \"" << command << "\" ," << std::endl ;
|
||||
body << " \"message\" : \"Method not allowed\"" << std::endl ;
|
||||
}
|
||||
|
||||
} else {
|
||||
ret = 400 ;
|
||||
body << " \"message\" : \"Bad Request\"" << std::endl ;
|
||||
}
|
||||
body << "}" << std::endl ;
|
||||
|
||||
ss << "HTTP/1.1 " << ret ;
|
||||
switch (ret) {
|
||||
case 200:
|
||||
ss << " OK" ;
|
||||
break ;
|
||||
case 400:
|
||||
ss << " Bad Request" ;
|
||||
break ;
|
||||
case 404:
|
||||
ss << " Not Found" ;
|
||||
break ;
|
||||
case 405:
|
||||
ss << " Method Not Allowed" ;
|
||||
break ;
|
||||
default:
|
||||
ss << " Unknown" ;
|
||||
break ;
|
||||
}
|
||||
ss << std::endl ;
|
||||
ss << "Content-Type: application/json" << std::endl ;
|
||||
ss << "Content-Length: " << body.str().size() << std::endl << std::endl ;
|
||||
ss << body.str() ;
|
||||
//std::cout << ss.str() ;
|
||||
tc_write(&connection, (char *)ss.str().c_str() , ss.str().size()) ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# create top page contents and return success
|
||||
*/
|
||||
int Trick::JSONVariableServerThread::get_top_page( std::stringstream & body ) {
|
||||
body << " \"commands\": \"http://" << hostname << ":" << port << "/commands\"," << std::endl ;
|
||||
body << " \"vars\": \"http://" << hostname << ":" << port << "/vars\"" << std::endl ;
|
||||
return 200 ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# if the path is empty after /commands create commands top level page.
|
||||
-# else if the path is exec_get_sim_time return create a message with the sim time.
|
||||
-# else create an error message.
|
||||
*/
|
||||
int Trick::JSONVariableServerThread::get_commands( std::stringstream & body , char * path ) {
|
||||
int ret = 200 ;
|
||||
if ( path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0' ;
|
||||
}
|
||||
if ( path[0] == '\0' ) {
|
||||
body << " \"exec_get_sim_time\": \"exec_get_sim_time()\"" << std::endl ;
|
||||
} else if ( ! strcmp( path , "/exec_get_sim_time" ) ) {
|
||||
body << " \"sim_time\": \"" << exec_get_sim_time() << "\"" << std::endl ;
|
||||
} else {
|
||||
body << " \"message\" : \"Not Found\"" << std::endl ;
|
||||
ret = 404 ;
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
||||
/*
|
||||
@details
|
||||
-# if the path is empty after /vars
|
||||
-# loop through all allocations in the memory manager
|
||||
-# if the allocation has a name create an item in the reply message for that allocation.
|
||||
-# else
|
||||
-# convert "/" characters to "." in the path and strip trailing "/" characters.
|
||||
-# add converted variable name to the reply message.
|
||||
-# call ref_attributes to find the variable.
|
||||
-# if the variable exists
|
||||
-# if the variable type is a structure.
|
||||
-# loop through the attributes and add each of the struct/class variables as links in the reply message.
|
||||
-# else add the variables value and units to the reply message.
|
||||
-# add the description text to the reply message
|
||||
-# add the type information to the reply message
|
||||
-# add the type io specification to the reply message
|
||||
-# if the variable has dimensions add the dimension information to the reply message.
|
||||
-# else add an error message to the reply message
|
||||
*/
|
||||
int Trick::JSONVariableServerThread::get_vars( std::stringstream & body , char * path ) {
|
||||
|
||||
int ret = 200 ;
|
||||
|
||||
//std::cout << "get_vars " << path << std::endl ;
|
||||
if ( path[0] == '\0' ) {
|
||||
Trick::ALLOC_INFO_MAP_ITER aim_it ;
|
||||
bool first_item = true ;
|
||||
for ( aim_it = trick_MM->alloc_info_map_begin() ; aim_it != trick_MM->alloc_info_map_end() ; aim_it++ ) {
|
||||
ALLOC_INFO * alloc_info = (*aim_it).second ;
|
||||
if ( alloc_info->name != NULL and alloc_info->user_type_name != NULL ) {
|
||||
if ( first_item == true ) {
|
||||
first_item = false ;
|
||||
} else {
|
||||
body << " ," << std::endl ;
|
||||
}
|
||||
body << " \"" << alloc_info->name << "\" : \"" << alloc_info->user_type_name << "\"" ;
|
||||
}
|
||||
}
|
||||
body << std::endl ;
|
||||
} else {
|
||||
|
||||
//TODO: More path character translations for characters like "[]"
|
||||
|
||||
if ( path[strlen(path) - 1] == '/') {
|
||||
path[strlen(path) - 1] = '\0' ;
|
||||
}
|
||||
for ( unsigned int ii = 1 ; ii < strlen(path) ; ii++ ) {
|
||||
if ( path[ii] == '/') {
|
||||
path[ii] = '.' ;
|
||||
}
|
||||
}
|
||||
|
||||
body << " \"name\" : \"" << &path[1] << "\" ," << std::endl ;
|
||||
//std::cout << "getting var " << path << std::endl ;
|
||||
// skip leading "/"
|
||||
REF2 * ref = ref_attributes( &path[1] ) ;
|
||||
if ( ref != NULL and ref->attr != NULL ) {
|
||||
ret = 200 ;
|
||||
//std::cout << "num_index " << ref->num_index << std::endl ;
|
||||
if ( ref->attr->type == TRICK_STRUCTURED ) {
|
||||
ATTRIBUTES * attr = (ATTRIBUTES *)ref->attr->attr ;
|
||||
body << " \"links\" : [" << std::endl ;
|
||||
for ( int ii = 0 ; attr[ii].name[0] != '\0' ; ii++ ) {
|
||||
if ( ii != 0 ) {
|
||||
body << " ," << std::endl ;
|
||||
}
|
||||
body << " \"" << attr[ii].name << "\"" ;
|
||||
}
|
||||
body << std::endl << " ] ," << std::endl ;
|
||||
} else {
|
||||
body << " \"value\" : " ;
|
||||
Trick::PythonPrint::write_rvalue(body, ref->address, ref->attr, ref->num_index, 0, false, true) ;
|
||||
body << " ," << std::endl ;
|
||||
if ( ref->attr->units != NULL ) {
|
||||
body << " \"units\" : \"" << ref->attr->units << "\" ," << std::endl ;
|
||||
}
|
||||
}
|
||||
if ( ref->attr->des != NULL ) {
|
||||
body << " \"description\" : \"" << ref->attr->des << "\" ," << std::endl ;
|
||||
}
|
||||
body << " \"type_name\" : " ;
|
||||
if ( ref->attr->type_name != NULL ) {
|
||||
body << "\"" << ref->attr->type_name << "\" ," << std::endl ;
|
||||
} else {
|
||||
body << "\"(null)\" ," << std::endl ;
|
||||
}
|
||||
body << " \"type\" : " << ref->attr->type << " ," << std::endl ;
|
||||
body << " \"io\" : " << ref->attr->io ;
|
||||
if ( (ref->attr->num_index - ref->num_index) > 0 ) {
|
||||
body << " ," << std::endl ;
|
||||
body << " \"num_index\" : " << ref->attr->num_index - ref->num_index << " ," << std::endl ;
|
||||
body << " \"index\" : [" << std::endl ;
|
||||
for ( int ii = ref->num_index , jj = 0 ; ii < ref->attr->num_index ; ii++ , jj++ ) {
|
||||
if ( jj != 0 ) {
|
||||
body << " ," << std::endl ;
|
||||
}
|
||||
body << " {" << std::endl ;
|
||||
body << " \"size\" : " << ref->attr->index[ii].size << " ," << std::endl ;
|
||||
body << " \"start\" : " << ref->attr->index[ii].start << std::endl ;
|
||||
body << " }" ;
|
||||
}
|
||||
body << std::endl << " ]" << std::endl ;
|
||||
} else {
|
||||
body << std::endl ;
|
||||
}
|
||||
free(ref) ;
|
||||
} else {
|
||||
body << " \"message\" : \"Not Found\"" << std::endl ;
|
||||
ret = 404 ;
|
||||
}
|
||||
}
|
||||
return ret ;
|
||||
}
|
||||
|
Reference in New Issue
Block a user