diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh deleted file mode 100644 index e38f353c..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh +++ /dev/null @@ -1,45 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent the state of a variable server websocket connection.) -**************************************************************************/ - -#ifndef WSSESSION_HH -#define WSSESSION_HH - -#include -#include -#include -#include "WebSocketSession.hh" -#include "VariableServerVariable.hh" - -class VariableServerSession : public WebSocketSession { - public: - VariableServerSession(struct mg_connection *nc); - ~VariableServerSession(); - void marshallData(); /* -- base */ - void sendMessage(); /* -- base */ - int handleMessage(std::string); /* -- base */ - - void setTimeInterval(unsigned int milliseconds); - void addVariable(char* vname); - void stageValues(); - void pause(); - void unpause(); - void clear(); - void exit(); - - static int bad_ref_int ; - - private: - int sendErrorMessage(const char* fmt, ... ); - REF2* make_error_ref(const char* in_name); - double stageTime; - bool dataStaged; - - std::vector sessionVariables; - bool cyclicSendEnabled; - long long nextTime; - long long intervalTimeTics; -}; - -WebSocketSession* makeVariableServerSession( struct mg_connection *nc ); -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh deleted file mode 100644 index 43ae82c5..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh +++ /dev/null @@ -1,34 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent Websocket variable server variable.) -LIBRARY DEPENDENCIES: - ( (../src/VariableServerVariable.o)) -**************************************************************************/ -#ifndef VARIABLE_SERVER_VARIABLE_HH -#define VARIABLE_SERVER_VARIABLE_HH - -#include -#include -#include -#include -#include - -#define MAX_ARRAY_LENGTH 4096 - -class VariableServerVariable { - - public: - VariableServerVariable( REF2* variableType); - ~VariableServerVariable(); - const char* getName(); - void stageValue(); - void writeValue( std::ostream& chkpnt_os ); - - private: - VariableServerVariable() {} - REF2 *varInfo; - void *address; - int size; - void *stageBuffer; - bool deref; - }; -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/WebSocketSession.hh b/trick_sims/Cannon/models/mongoose_httpd/include/WebSocketSession.hh deleted file mode 100644 index 0080ed48..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/WebSocketSession.hh +++ /dev/null @@ -1,26 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent Websocket connection.) -**************************************************************************/ -#ifndef WEB_SOCKET_SESSION_HH -#define WEB_SOCKET_SESSION_HH - -#include -#include - -class WebSocketSession { - public: - WebSocketSession(struct mg_connection *nc):connection(nc){}; - virtual ~WebSocketSession() {}; - - /** - When HTTP_Server::time_homogeneous is set, WebSocketSession::marshallData() is called from the main - sim thread in a "top_of_frame" job, so that all of the data can be staged at - the same sim-time, in other words it's time-homogeneous. - */ - virtual void marshallData()=0; - virtual void sendMessage()=0; - virtual int handleMessage(std::string)=0; - - struct mg_connection* connection; -}; -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/http_GET_handlers.hh b/trick_sims/Cannon/models/mongoose_httpd/include/http_GET_handlers.hh deleted file mode 100644 index 13a2748b..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/http_GET_handlers.hh +++ /dev/null @@ -1,14 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent Websocket variable server connection.) -LIBRARY DEPENDENCIES: - ( (../src/http_GET_handlers.o)) -**************************************************************************/ -#ifndef HANDLE_HTTP_GET_HANDLERS_HH -#define HANDLE_HTTP_GET_HANDLERS_HH - -#include - -void handle_HTTP_GET_vs_connections(struct mg_connection *nc, struct http_message *hm); -void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *hm); - -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/http_server.hh b/trick_sims/Cannon/models/mongoose_httpd/include/http_server.hh deleted file mode 100644 index c75908a2..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/http_server.hh +++ /dev/null @@ -1,63 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent the state and initial conditions of an http server.) -LIBRARY DEPENDENCIES: - ( (../src/http_server.cpp)) -**************************************************************************/ -#ifndef HTTP_SERVER_H -#define HTTP_SERVER_H - -#include -#include -#include -#include -#include "../include/WebSocketSession.hh" - -typedef void (*httpMethodHandler)(struct mg_connection *, struct http_message *); -typedef WebSocketSession* (*WebSocketSessionMaker)(struct mg_connection *nc); - -class HTTP_Server { - public: - const char* port; - const char* document_root; - struct mg_mgr mgr; /* ** mongoose */ - struct mg_connection *listener; /* ** mongoose */ - pthread_t server_thread; /* ** */ - bool shutting_down; - - std::map< std::string, httpMethodHandler> httpGETHandlerMap; /* ** */ - pthread_mutex_t httpGETHandlerMapLock; /* ** */ - - std::map< std::string, WebSocketSessionMaker> WebSocketSessionMakerMap; /* ** */ - pthread_mutex_t WebSocketSessionMakerMapLock; /* ** */ - - std::map webSocketSessionMap; /* ** */ - pthread_mutex_t webSocketSessionMapLock; /* ** */ - - pthread_mutex_t serviceLock; /* ** */ - struct mg_serve_http_opts http_server_options; /* ** */ - struct mg_bind_opts bind_opts; /* ** */ - pthread_cond_t serviceConnections; /* ** */ - bool service_websocket; - bool time_homogeneous; - bool sessionDataMarshalled; - - // Trick Job-functions - int http_default_data(); - int http_init(); - int http_top_of_frame(); - int http_shutdown(); - - void installWebSocketSessionMaker(std::string name, WebSocketSessionMaker maker); - void installHTTPGEThandler(std::string handlerName, httpMethodHandler handler); - - // These are internals, and should not be considered public. They are not private only - // because they need to be callable from the servers event handler. - void sendWebSocketSessionMessages(struct mg_connection *nc); - void handleWebSocketClientMessage(struct mg_connection *nc, std::string msg); - void addWebSocketSession(struct mg_connection *nc, WebSocketSession* session); - void deleteWebSocketSession(struct mg_connection *nc); - WebSocketSession* makeWebSocketSession(struct mg_connection *nc, std::string name); - void handleHTTPGETrequest(struct mg_connection *nc, http_message *hm, std::string handlerName); - void marshallWebSocketSessionData(); -}; -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/simpleJSON.hh b/trick_sims/Cannon/models/mongoose_httpd/include/simpleJSON.hh deleted file mode 100644 index b8c4a1e1..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/include/simpleJSON.hh +++ /dev/null @@ -1,21 +0,0 @@ -/************************************************************************* -PURPOSE: (Represent Websocket variable server connection.) -LIBRARY DEPENDENCIES: - ( (../src/WSSession.o)) -**************************************************************************/ -#ifndef SIMPLEJSON_HH -#define SIMPLEJSON_HH - -#include - -class Member { - public: - const char* key; - const char* valText; - int type; - Member(const char *k, const char *v, int t); -}; - -std::vector parseJSON( const char *json_s); - -#endif diff --git a/trick_sims/Cannon/models/mongoose_httpd/mongoose_httpd.sm b/trick_sims/Cannon/models/mongoose_httpd/mongoose_httpd.sm deleted file mode 100644 index d1e21029..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/mongoose_httpd.sm +++ /dev/null @@ -1,23 +0,0 @@ -/************************TRICK HEADER************************* -PURPOSE: - (HTTP Server) -LIBRARY DEPENDENCIES: - ((src/http_server.cpp)) -*************************************************************/ -##include "mongoose_httpd/include/http_server.hh" - -class HttpSimObject : public Trick::SimObject { - - public: - HTTP_Server server ; - - HttpSimObject() { - ("default_data") server.http_default_data() ; - ("initialization") server.http_init() ; - ("freeze") server.http_top_of_frame() ; - ("top_of_frame") server.http_top_of_frame() ; - ("shutdown") server.http_shutdown() ; - } -}; - -HttpSimObject http ; diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp deleted file mode 100644 index ab39a765..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/************************************************************************ -PURPOSE: (Represent the state and initial conditions of an http server) -LIBRARY DEPENDENCIES: - ((simpleJSON.o) - (VariableServerVariable.o) - ) -**************************************************************************/ -#include -#include -#include -#include // for setprecision -#include -#include "trick/memorymanager_c_intf.h" -#include "trick/input_processor_proto.h" -#include "trick/exec_proto.h" -#include "../include/VariableServerSession.hh" -#include "../include/simpleJSON.hh" - -// CONSTRUCTOR -VariableServerSession::VariableServerSession( struct mg_connection *nc ) : WebSocketSession(nc) { - intervalTimeTics = exec_get_time_tic_value(); // Default time interval is one second. - nextTime = 0; - cyclicSendEnabled = false; -} - -// DESTRUCTOR -VariableServerSession::~VariableServerSession() { - clear(); -} - -/* Base class virtual function: marshallData - When HTTP_Server::time_homogeneous is set, WebSocketSession::marshallData() is - called from the main sim thread in a "top_of_frame" job, to ensure that all of - the data is staged at the same sim-time, in other words that it's time-homogeneous. -*/ -/* VariableServerSession::marshallData() conditionally stages message data when - sim_time has reached the next integer multiple of intervalTimeTics - (The specified period between messages). -*/ -void VariableServerSession::marshallData() { - long long simulation_time_tics = exec_get_time_tics(); - if ( cyclicSendEnabled && ( simulation_time_tics >= nextTime )) { - stageValues(); - nextTime = (simulation_time_tics - (simulation_time_tics % intervalTimeTics) + intervalTimeTics); - } -} - -/* Base class virtual function: sendMessage - if data is staged/marshalled, then compose and send a message containing that data. - */ -void VariableServerSession::sendMessage() { - std::vector::iterator it; - std::stringstream ss; - - if (dataStaged) { - ss << "{ \"msg_type\" : \"values\",\n"; - ss << " \"time\" : " << std::setprecision(16) << stageTime << ",\n"; - ss << " \"values\" : [\n"; - - for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) { - if (it != sessionVariables.begin()) ss << ",\n"; - (*it)->writeValue(ss); - } - ss << "]}" << std::endl; - std::string tmp = ss.str(); - const char * message = tmp.c_str(); - mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message)); - dataStaged = false; - } -} - -// Base class virtual function. -int VariableServerSession::handleMessage(std::string client_msg) { - - int status = 0; - std::vector members = parseJSON(client_msg.c_str()); - std::vector::iterator it; - std::string cmd; - std::string var_name; - std::string pycode; - int period; - - for (it = members.begin(); it != members.end(); it++ ) { - if (strcmp((*it)->key, "cmd") == 0) { - cmd = (*it)->valText; - } else if (strcmp((*it)->key, "var_name") == 0) { - var_name = (*it)->valText; - } else if (strcmp((*it)->key, "period") == 0) { - period = atoi((*it)->valText); - } else if (strcmp((*it)->key, "pycode") == 0) { - pycode = (*it)->valText; - } - } - - if (cmd.empty()) { - printf ("No \"cmd\" member found in client message.\n"); - status = 1; - } else if (cmd == "var_add") { - addVariable( strdup( var_name.c_str())); - } else if (cmd == "var_cycle") { - setTimeInterval(period); - } else if (cmd == "var_pause") { - pause(); - } else if (cmd == "var_unpause") { - unpause(); - } else if (cmd == "var_send") { - // var_send responses are not guarenteed to be time-consistent. - stageValues(); - sendMessage(); - } else if (cmd == "var_clear") { - clear(); - } else if (cmd == "var_exit") { - //TODO - // nc->flags |= MG_F_SEND_AND_CLOSE; - } else if (cmd == "python") { - // Remove carriage-returns from pycode. - pycode.erase(std::remove(pycode.begin(), pycode.end(), '\r'), pycode.end()); - // Call the Trick input processor. - ip_parse(pycode.c_str()); - } else { - sendErrorMessage("Unknown Command: \"%s\".\n", cmd.c_str()); - status = 1; - } - return status; -} - -void VariableServerSession::setTimeInterval(unsigned int milliseconds) { - // CONSIDER: should we compare this with the realtime frame, and limit accordingly. - intervalTimeTics = exec_get_time_tic_value() * milliseconds / 1000; -} - -void VariableServerSession::addVariable(char* vname){ - REF2 * new_ref ; - new_ref = ref_attributes(vname); - if ( new_ref == NULL ) { - sendErrorMessage("Variable Server could not find variable %s.\n", vname); - new_ref = make_error_ref(vname); - } else if ( new_ref->attr ) { - if ( new_ref->attr->type == TRICK_STRUCTURED ) { - sendErrorMessage("Variable Server: var_add cant add \"%s\" because its a composite variable.\n", vname); - free(new_ref); - new_ref = make_error_ref(vname); - - } else if ( new_ref->attr->type == TRICK_STL ) { - sendErrorMessage("Variable Server: var_add cant add \"%s\" because its an STL variable.\n", vname); - free(new_ref); - new_ref = make_error_ref(vname); - } - } else { - sendErrorMessage("Variable Server: BAD MOJO - Missing ATTRIBUTES."); - free(new_ref); - new_ref = make_error_ref(vname); - } - - if ( new_ref != NULL ) { - // This REF2 object will "belong" to the VariableServerSessionVariable, so it has - // the right and responsibility to free() it in its destructor. - VariableServerVariable *sessionVariable = new VariableServerVariable( new_ref ) ; - sessionVariables.push_back( sessionVariable ) ; - } -} - -void VariableServerSession::stageValues() { - stageTime = (double)exec_get_time_tics() / exec_get_time_tic_value(); - std::vector::iterator it; - for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) { - (*it)->stageValue(); - } - dataStaged = true; -} - -void VariableServerSession::pause() { cyclicSendEnabled = false; } - -void VariableServerSession::unpause() { cyclicSendEnabled = true; } - -void VariableServerSession::clear() { - std::vector::iterator it; - it = sessionVariables.begin(); - while (it != sessionVariables.end()) { - delete *it; - it = sessionVariables.erase(it); - } -} - -void VariableServerSession::exit() {} - -int VariableServerSession::bad_ref_int = 0 ; - -#define MAX_MSG_SIZE 4096 -int VariableServerSession::sendErrorMessage(const char* fmt, ... ) { - char errText[MAX_MSG_SIZE]; - char msgText[MAX_MSG_SIZE]; - va_list args; - - errText[0]=0; - msgText[0]=0; - - va_start(args, fmt); - (void) vsnprintf(errText, MAX_MSG_SIZE, fmt, args); - va_end(args); - - sprintf(msgText, "{ \"msg_type\" : \"error\",\n" - " \"error\" : \"%s\"}\n", errText); - - mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, msgText, strlen(msgText)); - return (0); -} - -REF2* VariableServerSession::make_error_ref(const char* in_name) { - REF2* new_ref; - new_ref = (REF2*)calloc(1, sizeof(REF2)); - new_ref->reference = strdup(in_name) ; - new_ref->units = NULL ; - new_ref->address = (char *)&bad_ref_int ; - new_ref->attr = (ATTRIBUTES*)calloc(1, sizeof(ATTRIBUTES)) ; - new_ref->attr->type = TRICK_NUMBER_OF_TYPES ; - new_ref->attr->units = (char *)"--" ; - new_ref->attr->size = sizeof(int) ; - return new_ref; -} - -// WebSocketSessionMaker function for a VariableServerSession. -WebSocketSession* makeVariableServerSession( struct mg_connection *nc ) { - return new VariableServerSession(nc); -} diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerVariable.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerVariable.cpp deleted file mode 100644 index 4bfa50e7..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerVariable.cpp +++ /dev/null @@ -1,184 +0,0 @@ -#include "trick/memorymanager_c_intf.h" // for get_size. -#include "../include/VariableServerVariable.hh" -#include // for fpclassify -#include // for setprecision - -VariableServerVariable::VariableServerVariable(REF2 * ref ) { - varInfo = ref; - address = varInfo->address; - size = varInfo->attr->size ; - deref = false; - - TRICK_TYPE string_type = varInfo->attr->type ; - - if ( varInfo->num_index == varInfo->attr->num_index ) { - // single value - } else if ( varInfo->attr->index[varInfo->attr->num_index - 1].size != 0 ) { - // Constrained array - for ( int i = varInfo->attr->num_index-1; i > varInfo->num_index-1 ; i-- ) { - size *= varInfo->attr->index[i].size ; - } - } else { - // Unconstrained array - if ((varInfo->attr->num_index - varInfo->num_index) > 1 ) { - printf("Variable Server Error: var_add(%s) requests more than one dimension of dynamic array.\n", varInfo->reference); - printf("Data is not contiguous so returned values are unpredictable.\n") ; - } - if ( varInfo->attr->type == TRICK_CHARACTER ) { - string_type = TRICK_STRING ; - deref = true; - } else if ( varInfo->attr->type == TRICK_WCHAR ) { - string_type = TRICK_WSTRING ; - } else { - deref = true ; - size *= get_size((char*)address) ; - } - } - // handle strings: set a max buffer size, the copy size may vary so will be set in copy_sim_data - if (( string_type == TRICK_STRING ) || ( string_type == TRICK_WSTRING )) { - size = MAX_ARRAY_LENGTH ; - } - stageBuffer = calloc(size, 1) ; -} - -VariableServerVariable::~VariableServerVariable() { - if (varInfo != NULL) free( varInfo ); -} - - -const char* VariableServerVariable::getName() { - return varInfo->reference; -} - -static void write_quoted_str( std::ostream& os, const char* s) { - int ii; - int len = strlen(s); - os << "\"" ; - for (ii=0 ; ii bytes from
to staging_point. - - if ( varInfo->attr->type == TRICK_STRING ) { - if (address == NULL) { - size = 0 ; - } else { - size = strlen((char*)varInfo->address) + 1 ; - } - } - - if (address != NULL) { - memcpy(stageBuffer, address, size); - } -} - -void VariableServerVariable::writeValue( std::ostream& outs ) { - - switch(varInfo->attr->type) { - case TRICK_UNSIGNED_CHARACTER: - outs << std::dec << (int)*(unsigned char*)stageBuffer ; - break; - case TRICK_BOOLEAN: - if (*(bool*)stageBuffer) { - outs << "\"true\"" ; - } else { - outs << "\"false\"" ; - } - break; - case TRICK_CHARACTER: - if (isprint( *(char*)stageBuffer) ) { - outs << "'" << *(char*)stageBuffer << "'" ; - } else { - unsigned int ch = *(unsigned char*)stageBuffer; - outs << "'\\x" << std::hex << ch << "'" ; - } - break; - case TRICK_WCHAR: - outs << std::dec << *(wchar_t*)stageBuffer; - break; - case TRICK_SHORT: - outs << std::dec << *(short*)stageBuffer; - break; - case TRICK_UNSIGNED_SHORT: - outs << std::dec << *(unsigned short*)stageBuffer; - break; - case TRICK_INTEGER: - outs << std::dec << *(int*)stageBuffer; - break; - case TRICK_UNSIGNED_INTEGER: - outs << std::dec << *(unsigned int*)stageBuffer; - break; - case TRICK_LONG: - outs << std::dec << *(long*)stageBuffer; - break; - case TRICK_UNSIGNED_LONG: - outs << std::dec << *(unsigned long*)stageBuffer; - break; - case TRICK_FLOAT: - if (fpclassify( *(float*)stageBuffer) != FP_NAN) { - outs << std::setprecision(8) << *(float*)stageBuffer; - } else { - outs << "NAN"; - } - break; - case TRICK_DOUBLE: - if (fpclassify( *(double*)stageBuffer) != FP_NAN) { - outs << std::setprecision(16) << *(double*)stageBuffer; - } else { - outs << "NAN"; - } - break; -// case TRICK_BITFIELD: { -// int sbf = 0; -// src_addr = (char*)stageBuffer + offset * (size_t)attr->size; -// if (attr->size == sizeof(int)) { -// sbf = extract_bitfield_any( *(int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else if (attr->size == sizeof(short)) { -// sbf = extract_bitfield_any( *(short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else if (attr->size == sizeof(char)) { -// sbf = extract_bitfield_any( *(char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else { -// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n" -// "Unsupported bitfield size (%d) bytes.\n", attr->size) ; -// } -// outs << std::dec << sbf; -// } break; -// case TRICK_UNSIGNED_BITFIELD: { -// int bf = 0; -// src_addr = (char*)stageBuffer + offset * (size_t)attr->size; -// if (attr->size == sizeof(int)) { -// bf = extract_unsigned_bitfield_any( *(unsigned int*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else if (attr->size == sizeof(short)) { -// bf = extract_unsigned_bitfield_any( *(unsigned short*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else if (attr->size == sizeof(char)) { -// bf = extract_unsigned_bitfield_any( *(unsigned char*)src_addr, attr->size, attr->index[0].start, attr->index[0].size); -// } else { -// message_publish(MSG_ERROR, "Checkpoint Agent INTERNAL ERROR:\n" -// "Unsupported bitfield size (%d) bytes.\n", attr->size) ; -// } -// outs << std::dec << bf; -// } break; - case TRICK_LONG_LONG: - outs << std::dec << *(long long*)stageBuffer; - break; - case TRICK_UNSIGNED_LONG_LONG: - outs << std::dec << *(unsigned long long*)stageBuffer; - break; - case TRICK_STRING: - write_quoted_str(outs, (*(std::string*)stageBuffer).c_str()); - break; - default: - outs << "\"Error\""; // ERROR - break; - } -} diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/http_GET_handlers.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/http_GET_handlers.cpp deleted file mode 100644 index 1de3fdc8..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/src/http_GET_handlers.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/************************************************************************* -PURPOSE: ( HTTP-GET-method-handlers ) -LIBRARY DEPENDENCIES: - ( (../src/http_GET_handlers.o)) -**************************************************************************/ - -#include -#include "../include/http_GET_handlers.hh" - -#include "trick/VariableServer.hh" -extern Trick::VariableServer * the_vs ; - -#include "trick/MemoryManager.hh" -extern Trick::MemoryManager* trick_MM; - -// In the Trick HTTP Server, a HTTP GET request whose URI starts with the API_PREFIX -// is processed by a http-handler-function of the following form: -// -// void HTTP_METHOD_HANDLER( struct mg_connection *, struct http_message *); -// -// The purpose of these functions are generally to produce dynamically generated -// HTTP responses, like JSON. These handler-functions are installed into the HTTP_Server -// with the member-function .install_API_GET_handler. For example: -// -// http.server.install_API_GET_handler("vs_connections", &handle_HTTP_GET_vs_connections); -// -// installs the function handle_HTTP_GET_vs_connections() with the key "vs_connections". -// So if, for example the host and port of the webserver is "localhost:8888", and the API_PREFIX is "/api/v1/", -// then loading the URL "localhost:8888/api/v1/vs_connections" in your browser will cause -// handle_HTTP_GET_vs_connections() to run and return its response, which in this case is a JSON object -// describing the variable server connections. - - -// Send a JSON object to the given mongoose HTTP connection that describes the -// Variable Server Connections. -void handle_HTTP_GET_vs_connections(struct mg_connection *nc, struct http_message *hm) { - mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); - std::stringstream ss; - ss << *the_vs << std::endl; - std::string someJSON = ss.str(); - mg_printf_http_chunk(nc, "%s", someJSON.c_str()); - mg_send_http_chunk(nc, "", 0); -} - -static int getIntegerQueryValue(struct http_message *hm, const char* key, int defaultVal) { - char value_text[100]; - if ( mg_get_http_var(&(hm->query_string), key, value_text, sizeof(value_text)) > 0) { - return atoi(value_text); - } else { - return defaultVal; - } -} - -// Send a JSON object to the given mongoose HTTP connection that contains information -// about a range of memory allocations in the Trick Memory Manager. -void handle_HTTP_GET_alloc_info(struct mg_connection *nc, struct http_message *hm) { - int start = getIntegerQueryValue(hm, "start", 0); - int count = getIntegerQueryValue(hm, "count", 10); - mg_printf(nc, "%s", "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"); - std::stringstream ss; - trick_MM->write_JSON_alloc_list(ss, start, count); - std::string someJSON = ss.str(); - mg_printf_http_chunk(nc, "%s", someJSON.c_str()); - mg_send_http_chunk(nc, "", 0); -} diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp deleted file mode 100644 index 6f2a922a..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp +++ /dev/null @@ -1,421 +0,0 @@ -/************************************************************************ -PURPOSE: (Represent the state and initial conditions of an http server) -LIBRARY DEPENDENCIES: - ((VariableServerSession.o) - (http_GET_handlers.o)) -**************************************************************************/ -#include // for mkdir() -#include // for symlink(), access() -#include // for getenv() -#include // for opendir(), readdir() -#include -#include -#include "../include/http_server.hh" -#include "../include/http_GET_handlers.hh" -#include "../include/VariableServerSession.hh" -#include -#include -static const struct mg_str s_get_method = MG_MK_STR("GET"); -static const struct mg_str s_put_method = MG_MK_STR("PUT"); -static const struct mg_str s_delete_method = MG_MK_STR("DELETE"); -static const struct mg_str http_api_prefix = MG_MK_STR("/api/http/"); -static const struct mg_str ws_api_prefix = MG_MK_STR("/api/ws/"); - -static const char * style_css = - "h1 {" - "font-family: fantasy, cursive, serif;" - "font-size: 32px;" - "margin-left: 1em;" - "}" - "h2 {" - "font-family: sans-serif;" - "font-size: 18px;" - "margin-left: 1em;" - "}" - "a {" - "font-family: sans-serif;" - "font-size: 16px;" - "}" - "div.header { background-image: linear-gradient(#afafff, white); }"; - -static const char * index_html = - "\n" - "\n" - "\n" - "\n" - "Trick Simulation\n" - "
\n" - "\n" - "\n" - "\n" - "

SIM_cannon_numeric

\n" - "
\n" - "\n" - "\n" - "
\n" - "\n" - "
\n" - "\n" - "\n" - "n"; - -static int confirmDocumentRoot ( std::string documentRoot ) { - - if ( access( documentRoot.c_str(), F_OK ) != -1 ) { - std::cout << "Trick Webserver: Document root \"" << documentRoot - << "\" already exists." << std::endl; - } else { - std::cout << "Trick Webserver: Document root \"" << documentRoot - << "\" doesn't exist so, we'll create it." - << std::endl; - - char* trick_home = getenv("TRICK_HOME"); - std::string trickHome = std::string(trick_home); - - if (trick_home != NULL) { - if ( mkdir( documentRoot.c_str(), 0700) == 0) { - - std::string styleFilePath = documentRoot + "/style.css"; - std::fstream style_fs (styleFilePath, std::fstream::out); - style_fs << style_css << std::endl; - style_fs.close(); - - std::string appsDirPath = documentRoot + "/apps"; - if ( mkdir( appsDirPath.c_str(), 0700) == 0) { - DIR *dr; - struct dirent * dir_entry; - std::string trickAppsDirPath = trickHome + "/trick_source/web/apps"; - if ( (dr = opendir(trickAppsDirPath.c_str())) != NULL) { - while (( dir_entry = readdir(dr)) != NULL) { - std::string fName = std::string( dir_entry->d_name); - std::string sPath = trickAppsDirPath + '/' + fName; - std::string dPath = appsDirPath + '/' + fName; - symlink(sPath.c_str(), dPath.c_str()); - } - } - } else { - std::cout << "Failed to create \"" << appsDirPath << "\"." << std::endl; - return 1; - } - - std::string imagesDirPath = documentRoot + "/images"; - if ( mkdir( imagesDirPath.c_str(), 0700) == 0) { - DIR *dr; - struct dirent * dir_entry; - std::string trickImagesDirPath = trickHome + "/trick_source/web/images"; - if ( (dr = opendir(trickImagesDirPath.c_str())) != NULL) { - while (( dir_entry = readdir(dr)) != NULL) { - std::string fName = std::string( dir_entry->d_name); - std::string sPath = trickImagesDirPath + '/' + fName; - std::string dPath = imagesDirPath + '/' + fName; - symlink(sPath.c_str(), dPath.c_str()); - } - } - } else { - std::cout << "Failed to create \"" << imagesDirPath << "\"." << std::endl; - return 1; - } - - std::string indexFilePath = documentRoot + "/index.html"; - std::fstream index_fs (indexFilePath, std::fstream::out); - index_fs << index_html << std::endl; - index_fs.close(); - - } else { - std::cout << "Failed to create documentRoot." << std::endl; - return 1; - } - } else { - std::cout << "TRICK_HOME is not set.\n" << std::endl; - return 1; - } - } - return 0; -} - -static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { - - http_message *hm = (struct http_message *)ev_data; - HTTP_Server* httpServer = (HTTP_Server *)nc->user_data; - - switch(ev) { - case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { // Process new websocket connection. - std::string uri(hm->uri.p, hm->uri.len); - std::cout << "WEBSOCKET_REQUEST: URI = \"" << uri << "\"" << std::endl; - if (mg_str_starts_with(hm->uri, ws_api_prefix)) { - std::string wsType (hm->uri.p + ws_api_prefix.len, hm->uri.len - ws_api_prefix.len); - WebSocketSession* session = httpServer->makeWebSocketSession(nc, wsType); - if (session != NULL) { - httpServer->addWebSocketSession(nc, session); - std::cout << "WEBSOCKET[" << (void*)nc << "] OPENED. URI=\"" << uri << "\"." << std::endl; - } else { - nc->flags |= MG_F_SEND_AND_CLOSE; - std::cout << "ERROR: No such web socket interface: \"" << uri << "\"." << std::endl; - } - } else { - std::cout << "ERROR: WEBSOCKET_REQUEST URI does not start with API prefix." << std::endl; - } - } break; - case MG_EV_WEBSOCKET_FRAME: { // Process websocket messages from the client (web browser). - struct websocket_message *wm = (struct websocket_message *) ev_data; - std::string msg ((char*)wm->data, wm->size); - std::cout << "WEBSOCKET[" << (void*)nc << "] RECIEVED: " << msg << std::endl; - if (nc->flags & MG_F_IS_WEBSOCKET) { - httpServer->handleWebSocketClientMessage(nc, msg); - } - } break; - case MG_EV_CLOSE: { // Process closed websocket connection. - if (nc->flags & MG_F_IS_WEBSOCKET) { - httpServer->deleteWebSocketSession(nc); - std::cout << "WEBSOCKET[" << (void*)nc << "] CLOSED." << std::endl; - } - } break; - case MG_EV_POLL: { - // The MG_EV_POLL event is sent to all connections for each invocation of mg_mgr_poll(), - // called periodically by the threaded function connectionAttendant() [below] when it is - // signaled (serviceConnections) from the http_top_of_frame job. - // This is when we send websocket messages to the client (web browser). - if (nc->flags & MG_F_IS_WEBSOCKET) { - httpServer->sendWebSocketSessionMessages(nc); - } - } break; - case MG_EV_HTTP_REQUEST: { // Process HTTP requests. - std::string uri(hm->uri.p, hm->uri.len); - std::cout << "HTTP_REQUEST: URI = \"" << uri << "\"" << std::endl; - if (mg_str_starts_with(hm->uri, http_api_prefix)) { - if (mg_strcmp(hm->method, s_get_method)==0) { - std::string handlerName (hm->uri.p + http_api_prefix.len, hm->uri.len - http_api_prefix.len); - httpServer->handleHTTPGETrequest(nc, hm, handlerName); - } else if (mg_strcmp(hm->method, s_put_method)==0) { - mg_http_send_error(nc, 405, "PUT method not allowed."); - } else if (mg_strcmp(hm->method, s_delete_method)==0) { - mg_http_send_error(nc, 405, "DELETE method not allowed."); - } - } else { - // Serve the files in the document-root directory, as specified by the URI. - mg_serve_http(nc, (struct http_message *) ev_data, httpServer->http_server_options); - } - } break; - default: { - } break; - } -} - -// ========================================================================= -// This function runs in its own pthread to operate the webserver. -// ========================================================================= -static void* connectionAttendant (void* arg) { - HTTP_Server *S = (HTTP_Server*)arg; - while(1) { - pthread_mutex_lock(&S->serviceLock); - // Wait here until the serviceConnections condition is signaled by the top_of_frame job. - while (!S->service_websocket && !S->shutting_down) { - pthread_cond_wait(&S->serviceConnections, &S->serviceLock); - } - if (S->shutting_down) { - pthread_mutex_unlock(&S->serviceLock); - return NULL; - } else { - if (!S->sessionDataMarshalled) { - S->marshallWebSocketSessionData(); - } - // mg_mgr_poll returns the number of connections that still need to be serviced. - while(mg_mgr_poll(&S->mgr, 50)); - } - S->service_websocket= false; - pthread_mutex_unlock(&S->serviceLock); - } - return NULL; -} - -// Install a WebSocketSessionMaker with a name (key) by which it can be retrieved. -void HTTP_Server::installWebSocketSessionMaker(std::string name, WebSocketSessionMaker maker) { - pthread_mutex_lock(&WebSocketSessionMakerMapLock); - WebSocketSessionMakerMap.insert(std::pair(name, maker)); - pthread_mutex_unlock(&WebSocketSessionMakerMapLock); -} - -// Lookup and call the WebSocketSessionMaker function by name, end execute it to create and return -// (a pointer to) a WebSocketSession. -WebSocketSession* HTTP_Server::makeWebSocketSession(struct mg_connection *nc, std::string name) { - std::map::iterator iter; - iter = WebSocketSessionMakerMap.find(name); - if (iter != WebSocketSessionMakerMap.end()) { - WebSocketSessionMaker maker = iter->second; - return maker(nc); - } else { - return NULL; - mg_http_send_error(nc, 404, "No such API."); - } -} - -// Install an httpMethodHandler with a name, the key by which it can be retrieved. -void HTTP_Server::installHTTPGEThandler(std::string handlerName, httpMethodHandler handler) { - pthread_mutex_lock(&httpGETHandlerMapLock); - httpGETHandlerMap.insert(std::pair(handlerName, handler)); - pthread_mutex_unlock(&httpGETHandlerMapLock); -} - -/* Lookup the appropriate httpMethodHandler by name, and execute it for the - given connection and http_message. */ -void HTTP_Server::handleHTTPGETrequest(struct mg_connection *nc, http_message *hm, std::string handlerName) { - std::map::iterator iter; - iter = httpGETHandlerMap.find(handlerName); - if (iter != httpGETHandlerMap.end()) { - httpMethodHandler handler = iter->second; - handler(nc, hm); - } else { - mg_http_send_error(nc, 404, "No such API."); - } -} - -/* Tell each of the sessions to marshall any data that they have to send. */ -void HTTP_Server::marshallWebSocketSessionData() { - std::map::iterator iter; - pthread_mutex_lock(&webSocketSessionMapLock); - for (iter = webSocketSessionMap.begin(); iter != webSocketSessionMap.end(); iter++ ) { - WebSocketSession* session = iter->second; - session->marshallData(); - } - sessionDataMarshalled = true; - pthread_mutex_unlock(&webSocketSessionMapLock); -} - -// Find the session that goes with the given websocket connection, -// and tell it to send any messages it may have, to the client (web browser). -void HTTP_Server::sendWebSocketSessionMessages(struct mg_connection *nc) { - - std::map::iterator iter; - pthread_mutex_lock(&webSocketSessionMapLock); - iter = webSocketSessionMap.find(nc); - if (iter != webSocketSessionMap.end()) { - WebSocketSession* session = iter->second; - session->sendMessage(); - } - sessionDataMarshalled = false; - pthread_mutex_unlock(&webSocketSessionMapLock); -} - -/* Delete the WebSocketSession associated with the given connection-pointer, - and erase its pointer from the webSocketSessionMap. */ -void HTTP_Server::deleteWebSocketSession(struct mg_connection *nc) { - std::map::iterator iter; - iter = webSocketSessionMap.find(nc); - if (iter != webSocketSessionMap.end()) { - WebSocketSession* session = iter->second; - delete session; - webSocketSessionMap.erase(iter); - } -} - -// Lookup the WebSocketSession associated with the given connection-pointer, and pass -// the given message to it. -void HTTP_Server::handleWebSocketClientMessage(struct mg_connection *nc, std::string msg) { - std::map::iterator iter; - iter = webSocketSessionMap.find(nc); - if (iter != webSocketSessionMap.end()) { - WebSocketSession* session = iter->second; - session->handleMessage(msg); - } -} - -// Install a WebSocketSession with a connection-pointer, the key by which it can be retrieved. -void HTTP_Server::addWebSocketSession(struct mg_connection *nc, WebSocketSession* session) { - pthread_mutex_lock(&webSocketSessionMapLock); - webSocketSessionMap.insert( std::pair(nc, session) ); - pthread_mutex_unlock(&webSocketSessionMapLock); -} - -// ========================================================================= -// Trick Sim Interface Functions -// ========================================================================= - -// Trick "default_data" job. -int HTTP_Server::http_default_data() { - port = "8888"; - //port = "0"; - document_root = "www"; - time_homogeneous = false; - service_websocket = false; - shutting_down = false; - sessionDataMarshalled = false; - - installHTTPGEThandler("vs_connections", &handle_HTTP_GET_vs_connections); - installHTTPGEThandler("alloc_info", &handle_HTTP_GET_alloc_info); - installWebSocketSessionMaker("VariableServer", &makeVariableServerSession); - - return 0; -} - -// Trick "initialization" job. -int HTTP_Server::http_init() { - http_server_options.document_root = document_root; - http_server_options.enable_directory_listing = "yes"; - - confirmDocumentRoot( std::string(document_root)); - - mg_mgr_init( &mgr, NULL ); - - memset(&bind_opts, 0, sizeof(bind_opts)); - bind_opts.user_data = this; - listener = mg_bind_opt( &mgr, port, ev_handler, bind_opts); - - // Determine the ACTUAL listen port as opposed to the requested port. - // Note that if we specify port = "0" in the mg_bind_opt() call, then - // a port number will be chosen for us, and we have to find out what it actually is. - char buf[32]; - mg_conn_addr_to_str( listener, buf, 32, MG_SOCK_STRINGIFY_PORT); - port = strdup(buf); - - if (listener != NULL) { - std::cout << "Trick Webserver: Listening on port = " << port << ".\n" - << "Trick Webserver: Document root = \"" << document_root << "\"" - << std::endl; - } else { - std::cerr << "Trick Webserver: ERROR: Failed to create listener.\n" - << "Perhaps another program is already using port " << port << "." - << std::endl; - return 1; - } - mg_set_protocol_http_websocket( listener ); - pthread_cond_init(&serviceConnections, NULL); - pthread_create( &server_thread, NULL, connectionAttendant, (void*)this ); - return 0; -} - -int HTTP_Server::http_top_of_frame() { - if (listener != NULL) { - if (time_homogeneous) { - /* Have all of the sessions stage their data in a top_of_frame job, so - that it's time-homogeneous. */ - marshallWebSocketSessionData(); - } - // Signal the server thread to construct and send the values-message to the client. - service_websocket= true; - pthread_cond_signal( &serviceConnections ); - } - return 0; -} - -int HTTP_Server::http_shutdown() { - if (listener != NULL) { - std::cout << "Trick Webserver: Shutting down on port " << port << "." << std::endl; - shutting_down = true; - - // Send the serviceConnections signal one last time so the connectionAttendant thread can quit. - pthread_cond_signal( &serviceConnections ); - pthread_join(server_thread, NULL); - } - return 0; -} diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/simpleJSON.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/simpleJSON.cpp deleted file mode 100644 index 92aafebb..00000000 --- a/trick_sims/Cannon/models/mongoose_httpd/src/simpleJSON.cpp +++ /dev/null @@ -1,216 +0,0 @@ -#include -#include -#include -#include -#include "../include/simpleJSON.hh" - -class LexicalAnalyzer { -public: - enum Lexeme { - END_OF_INPUT, - ERROR, - LEFT_BRACE, - RIGHT_BRACE, - LEFT_SQUARE_BRACKET, - RIGHT_SQUARE_BRACKET, - COLON, - COMMA, - STRING, - INTEGER - }; - - LexicalAnalyzer(const char*); - int next_lexeme(); - char* getTokenText(); - -private: - const char * s; - const char * p; - const char * vs; - size_t vlen; - char getch(); - void ungetch() ; - LexicalAnalyzer(){} -}; - -LexicalAnalyzer::LexicalAnalyzer(const char* str) { - s = str; - p = str; - vs = NULL; - vlen = 0; -} - -char LexicalAnalyzer::getch() { - char ch; - if ((ch = *p) != 0) { p++; } - return ch; -} - -void LexicalAnalyzer::ungetch() { - if (p > s) { p--; } -} - -char* LexicalAnalyzer::getTokenText() { - if (vlen > 0) { - return strndup(vs, vlen); - } else { - return NULL; - } -} - -int LexicalAnalyzer::next_lexeme() { - int state = 0; - vlen = 0; - char ch; - while ((ch = getch()) != 0) { - switch (state) { - case 0 : { // Initial state. - if (ch == '{') { - return LEFT_BRACE ; - } else if (ch == '}') { - return RIGHT_BRACE ; - } else if (ch == '[') { - return LEFT_SQUARE_BRACKET ; - } else if (ch == ']') { - return RIGHT_SQUARE_BRACKET ; - } else if (ch == ':') { - return COLON ; - } else if (ch == ',') { - return COMMA ; - } else if ( ch == '"') { - state = 1; - vs = p; - } else if ( isdigit(ch) ) { - ungetch(); - state = 2; - vs = p; - } else if (isspace(ch)) { - state = 0; - } - } break; - case 1 : { // String literal accumulation state. - while ((ch != 0 ) && (ch != '"')) - ch = getch(); - if (ch == '"') { - vlen = p-vs-1 ; - return STRING ; - } else { - return ERROR ; - } - } break; - case 2 : { // Integer literal accumulation state. - while ((ch != 0 ) && (isdigit(ch))) - ch = getch(); - ungetch(); - vlen = p-vs; - return INTEGER ; - } break; - default: - return ERROR ; - } - } - return END_OF_INPUT; -} - -const char *token_description(int token) { - const char *text; - switch (token) { - case LexicalAnalyzer::END_OF_INPUT : text = "END_OF_INPUT"; break; - case LexicalAnalyzer::ERROR : text = "ERROR"; break; - case LexicalAnalyzer::LEFT_BRACE : text = "LEFT_BRACE"; break; - case LexicalAnalyzer::RIGHT_BRACE : text = "RIGHT_BRACE"; break; - case LexicalAnalyzer::LEFT_SQUARE_BRACKET : text = "LEFT_SQUARE_BRACKET"; break; - case LexicalAnalyzer::RIGHT_SQUARE_BRACKET : text = "RIGHT_SQUARE_BRACKET"; break; - case LexicalAnalyzer::COLON : text = "COLON"; break; - case LexicalAnalyzer::COMMA : text = "COMMA"; break; - case LexicalAnalyzer::STRING : text = "STRING"; break; - case LexicalAnalyzer::INTEGER : text = "INTEGER"; break; - default : text = "**UNKNOWN**"; break; - } - return text; -} - -Member::Member(const char *k, const char *v, int t) { - key=k; - valText=v; - type=t; -} - -Member* parseJSON_member(LexicalAnalyzer &lexan) { - - const char* key; - const char* valText; - int type; - - int token; - token = lexan.next_lexeme(); - if ( token == LexicalAnalyzer::STRING ) { - key = lexan.getTokenText(); - } else { - std::cout << "ERROR: Expected STRING. Found \"" << token_description(token) << "\"." << std::endl; - return NULL; - } - token = lexan.next_lexeme(); - if ( token != LexicalAnalyzer::COLON ) { - std::cout << "ERROR: Expected COLON. Found \"" << token_description(token) << "\"." << std::endl; - token_description(token); - delete key; - return NULL; - } - token = lexan.next_lexeme(); - if (( token == LexicalAnalyzer::STRING) || ( token == LexicalAnalyzer::INTEGER )) { - valText = lexan.getTokenText(); - type = token; - } else { - std::cout << "ERROR: Expected STRING or INTEGER. Found \"" << token_description(token) << "." << std::endl; - token_description(token); - return NULL; - } - Member *member = new Member(key, valText, type); - return member; -} - -std::vector parseJSON( const char *json_s) { - - std::vector members; - Member* member; - int token; - bool okiedokey = true; - LexicalAnalyzer lexan(json_s); - token = lexan.next_lexeme(); - if ( token == LexicalAnalyzer::LEFT_BRACE ) { - member = parseJSON_member(lexan); - if (member != NULL) { - members.push_back(member); - token = lexan.next_lexeme(); - while ( okiedokey && (token == LexicalAnalyzer::COMMA) ) { - member = parseJSON_member(lexan); - if (member != NULL) { - members.push_back(member); - } else { - okiedokey = false; - } - token = lexan.next_lexeme(); - } - } else { - okiedokey = false; - } - if ( token != LexicalAnalyzer::RIGHT_BRACE ) { - std::cout << "ERROR: Expected RIGHT_BRACE. Found \"" << token_description(token) << "\"." << std::endl; - token_description(token); - okiedokey = false; - } - } else { - std::cout << "ERROR: Expected LEFT_BRACE. Found \"" << token_description(token) << "\"." << std::endl; - okiedokey = false; - } - if (okiedokey == false) { - std::vector::iterator it; - it = members.begin(); - while (it != members.end()) { - delete *it; - it = members.erase(it); - } - } - return members; -}