From 63605da069d10ca25b38e6c74476ec43a6838392 Mon Sep 17 00:00:00 2001 From: "Penn, John M 047828115" Date: Wed, 21 Aug 2019 10:52:48 -0500 Subject: [PATCH] Comments and rearrangment for clarity. --- .../include/VariableServerSession.hh | 2 + .../include/VariableServerVariable.hh | 2 +- .../src/VariableServerSession.cpp | 226 ++++++++++-------- .../models/mongoose_httpd/src/http_server.cpp | 57 +++-- 4 files changed, 166 insertions(+), 121 deletions(-) diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh index d39805b8..4e0fa40b 100644 --- a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh +++ b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerSession.hh @@ -28,6 +28,7 @@ LIBRARY DEPENDENCIES: "values" : [] } **************************************************************************/ + #ifndef WSSESSION_HH #define WSSESSION_HH @@ -40,6 +41,7 @@ LIBRARY DEPENDENCIES: class VariableServerSession : public WebSocketSession { public: VariableServerSession(struct mg_connection *nc); + ~VariableServerSession(); void stageData(); /* -- base */ void sendMessage(); /* -- base */ int handleMessage(std::string); /* -- base */ diff --git a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh index 19753bd5..43ae82c5 100644 --- a/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh +++ b/trick_sims/Cannon/models/mongoose_httpd/include/VariableServerVariable.hh @@ -18,7 +18,7 @@ class VariableServerVariable { public: VariableServerVariable( REF2* variableType); - ~VariableServerVariable(); + ~VariableServerVariable(); const char* getName(); void stageValue(); void writeValue( std::ostream& chkpnt_os ); diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp index 920f7ef1..5f96e1f6 100644 --- a/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp +++ b/trick_sims/Cannon/models/mongoose_httpd/src/VariableServerSession.cpp @@ -12,51 +12,112 @@ LIBRARY DEPENDENCIES: #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 = LLONG_MAX; cyclicSendEnabled = false; } +// DESTRUCTOR +VariableServerSession::~VariableServerSession() { + clear(); +} + +// Base class virtual function. +void VariableServerSession::stageData() { + long long simulation_time_tics = exec_get_time_tics(); + if ( cyclicSendEnabled && ( simulation_time_tics >= nextTime )) { + stageVariableValues(); + } + nextTime = (simulation_time_tics - (simulation_time_tics % intervalTimeTics) + intervalTimeTics); +} + +// Base class virtual function. +void VariableServerSession::sendMessage() { + std::vector::iterator it; + std::stringstream ss; + + 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)); +} + +// 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; + const char *cmd; + const char *var_name; + 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); + } + } + + if (cmd == NULL) { + printf ("No \"cmd\" member found in client message.\n"); + status = 1; + } else if (strcmp(cmd, "var_add") == 0) { + addVariable( strdup(var_name) ); + } else if ( strcmp(cmd, "var_cycle") == 0 ) { + setTimeInterval(period); + } else if ( strcmp(cmd, "var_pause") == 0 ) { + pause(); + } else if ( strcmp(cmd, "var_unpause") == 0 ) { + unpause(); + } else if ( strcmp(cmd, "var_send") == 0 ) { + stageVariableValues(); + sendMessage(); + } else if ( strcmp(cmd, "var_clear") == 0 ) { + clear(); + } else if ( strcmp(cmd, "var_exit") == 0 ) { + //TODO + // nc->flags |= MG_F_SEND_AND_CLOSE; + } else { + sendErrorMessage("Unknown Command: \"%s\".\n", cmd); + status = 1; + } + return status; +} + +// #include "trick/input_processor_proto.h" +// for( ii = 0 , jj = 0 ; ii <= msg_len ; ii++ ) { +// if ( incoming_msg[ii] != '\r' ) { +// stripped_msg[jj++] = incoming_msg[ii] ; +// } +// } +// +// ip_parse(stripped_msg); /* returns 0 if no parsing error */ + + +// Remove characters from a string +// str.erase(std::remove(str.begin(), str.end(), '\r'), str.end()); + + + + void VariableServerSession::setTimeInterval(unsigned int milliseconds) { intervalTimeTics = exec_get_time_tic_value() * milliseconds / 1000; } -int VariableServerSession::bad_ref_int = 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; -} - -#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); -} - void VariableServerSession::addVariable(char* vname){ REF2 * new_ref ; new_ref = ref_attributes(vname); @@ -96,32 +157,6 @@ void VariableServerSession::stageVariableValues() { } } -void VariableServerSession::stageData() { - long long simulation_time_tics = exec_get_time_tics(); - if ( cyclicSendEnabled && ( simulation_time_tics >= nextTime )) { - stageVariableValues(); - } - nextTime = (simulation_time_tics - (simulation_time_tics % intervalTimeTics) + intervalTimeTics); -} - -void VariableServerSession::sendMessage() { - std::vector::iterator it; - std::stringstream ss; - - 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)); -} - void VariableServerSession::pause() { cyclicSendEnabled = false; } void VariableServerSession::unpause() { cyclicSendEnabled = true; } @@ -137,46 +172,37 @@ void VariableServerSession::clear() { void VariableServerSession::exit() {} -int VariableServerSession::handleMessage(std::string client_msg) { +int VariableServerSession::bad_ref_int = 0 ; - int status = 0; - std::vector members = parseJSON(client_msg.c_str()); - std::vector::iterator it; - const char *cmd; - const char *var_name; - int period; +#define MAX_MSG_SIZE 4096 +int VariableServerSession::sendErrorMessage(const char* fmt, ... ) { + char errText[MAX_MSG_SIZE]; + char msgText[MAX_MSG_SIZE]; + va_list args; - 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); - } - } + errText[0]=0; + msgText[0]=0; - if (cmd == NULL) { - printf ("No \"cmd\" member found in client message.\n"); - status = 1; - } else if (strcmp(cmd, "var_add") == 0) { - addVariable( strdup(var_name) ); - } else if ( strcmp(cmd, "var_cycle") == 0 ) { - setTimeInterval(period); - } else if ( strcmp(cmd, "var_pause") == 0 ) { - pause(); - } else if ( strcmp(cmd, "var_unpause") == 0 ) { - unpause(); - } else if ( strcmp(cmd, "var_send") == 0 ) { - stageVariableValues(); - sendMessage(); - } else if ( strcmp(cmd, "var_clear") == 0 ) { - clear(); - } else if ( strcmp(cmd, "var_exit") == 0 ) { - //TODO - } else { - sendErrorMessage("Unknown Command: \"%s\".\n", cmd); - status = 1; - } - return status; + 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; } diff --git a/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp b/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp index 0ecb6731..f54f447e 100644 --- a/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp +++ b/trick_sims/Cannon/models/mongoose_httpd/src/http_server.cpp @@ -14,6 +14,7 @@ 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 void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { http_message *hm = (struct http_message *)ev_data; @@ -51,8 +52,9 @@ static void ev_handler(struct mg_connection *nc, int ev, void *ev_data) { } 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]. - // Send websocket messages to the client (web browser). + // 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); } @@ -99,12 +101,15 @@ static void* connectionAttendant (void* arg) { 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); @@ -117,12 +122,15 @@ WebSocketSession* HTTP_Server::makeWebSocketSession(struct mg_connection *nc, st } } -void HTTP_Server::installHTTPGEThandler(std::string APIname, httpMethodHandler handler) { +// Install an httpMethodHandler with a name (key) by which it can be retrieved. +void HTTP_Server::installHTTPGEThandler(std::string handlerName, httpMethodHandler handler) { pthread_mutex_lock(&httpGETHandlerMapLock); - httpGETHandlerMap.insert(std::pair(APIname, handler)); + 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); @@ -134,9 +142,9 @@ void HTTP_Server::handleHTTPGETrequest(struct mg_connection *nc, http_message *h } } +// Find the session that goes with the given websocket connection, +// and tell it to send its values to the client (web browser). void HTTP_Server::sendWebSocketSessionMessages(struct mg_connection *nc) { - // Find the session that goes with the given websocket connection, - // and tell it to send its values to the client (web browser). std::map::iterator iter; iter = sessionMap.find(nc); if (iter != sessionMap.end()) { @@ -145,6 +153,8 @@ void HTTP_Server::sendWebSocketSessionMessages(struct mg_connection *nc) { } } +// Delete the WebSocketSession associated with the given connection-pointer, and +// erase its pointer from the sessionMap. void HTTP_Server::deleteWebSocketSession(struct mg_connection *nc) { std::map::iterator iter; iter = sessionMap.find(nc); @@ -154,6 +164,9 @@ void HTTP_Server::deleteWebSocketSession(struct mg_connection *nc) { sessionMap.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 = sessionMap.find(nc); @@ -163,36 +176,40 @@ void HTTP_Server::handleWebSocketClientMessage(struct mg_connection *nc, std::st } } +// Install a WebSocketSession with a connection-pointer (key) by which it can be retrieved. void HTTP_Server::addWebSocketSession(struct mg_connection *nc, WebSocketSession* session) { pthread_mutex_lock(&sessionMapLock); sessionMap.insert( std::pair(nc, session) ); pthread_mutex_unlock(&sessionMapLock); } -// ========================================================================= -// Trick Sim Interface Functions -// ========================================================================= - -int HTTP_Server::http_default_data() { - port = "8888"; - document_root = "www"; - shutting_down = false; - return 0; -} - +// WebSocketSessionMaker function for a VariableServerSession. static WebSocketSession* makeVariableServerSession( struct mg_connection *nc ) { return new VariableServerSession(nc); } -int HTTP_Server::http_init() { +// ========================================================================= +// Trick Sim Interface Functions +// ========================================================================= - http_server_options.document_root = document_root; - http_server_options.enable_directory_listing = "yes"; +// Trick "default_data" job. +int HTTP_Server::http_default_data() { + port = "8888"; + document_root = "www"; + shutting_down = false; installHTTPGEThandler("vs_connections", &handle_HTTP_GET_vs_connections); installHTTPGEThandler("alloc_info", &handle_HTTP_GET_alloc_info); installWebSocketSessionMaker("VariableServer", &makeVariableServerSession); //installWebSocketSessionMaker("VariableServer", [](struct mg_connection *nc) -> WebSocketSession* { return new VariableServerSession(nc); } ); + return 0; +} + +// Trick "initialization" job. +int HTTP_Server::http_init() { + + http_server_options.document_root = document_root; + http_server_options.enable_directory_listing = "yes"; mg_mgr_init( &mgr, NULL );