Removed mongoose

This commit is contained in:
Caleb Herpin 2021-07-29 13:09:30 -05:00
parent dd25e9b832
commit 29e171da7a
17 changed files with 1 additions and 1692 deletions

4
.gitignore vendored
View File

@ -27,10 +27,6 @@ autom4te.cache
trick_test
gmon.out
*init_log.csv*
include/mongoose/
trick_source/web/HttpServer/mongoose.c
trick_source/web/HttpServer/mongoose.h
trick_source/web/HttpServer/obj/
trick_source/web/CivetServer/obj/
trick-offline
*sim_services_classes.resource

View File

@ -149,12 +149,6 @@ ifeq ($(USE_JAVA), 1)
all: java
endif
#ifeq ($(TRICK_MONGOOSE), 1)
#all: webserver
#icg_sim_serv: ${TRICK_HOME}/include/mongoose/mongoose.h
#ICG: ${TRICK_HOME}/include/mongoose/mongoose.h
#endif
ifeq ($(TRICK_CIVET), 1)
all: civetweb
icg_sim_serv: civetweb
@ -226,10 +220,6 @@ dp: ${TRICK_HOME}/trick_source/trick_utils/units
#-------------------------------------------------------------------------------
#
.PHONY: webserver
webserver: ${TRICK_LIB_DIR}/libmongoose.a ${TRICK_HOME}/include/mongoose/mongoose.h
$(MAKE) -C ${TRICK_HOME}/trick_source/web/HttpServer
CIVET_CLONE_DIR = civetweb_clone
@ -249,46 +239,7 @@ ${CIVET_CLONE_DIR}/libcivetweb.a: ${CIVET_CLONE_DIR}
${CIVET_CLONE_DIR}:
git clone https://github.com/civetweb/civetweb.git $@
cd $@ && git checkout tags/v1.14
#-------------------------------------------------------------------------------
mongoose.h:
curl --retry 4 -O https://raw.githubusercontent.com/cesanta/mongoose/6.16/mongoose.h
mongoose.c:
curl --retry 4 -O https://raw.githubusercontent.com/cesanta/mongoose/6.16/mongoose.c
${TRICK_LIB_DIR}/libmongoose.a: ${TRICK_HOME}/include/mongoose/mongoose.h | mongoose.o $(TRICK_LIB_DIR)
ar crs $@ mongoose.o
@ rm mongoose.o
@ rm -f mongoose.h
@ echo ; echo "Mongoose library compiled:" ; date
ifeq (${TRICK_OFFLINE}, 0)
mongoose.o: mongoose.h mongoose.c
$(CC) $(TRICK_CFLAGS) ${TRICK_SYSTEM_CXXFLAGS} -c -o mongoose.o mongoose.c
@ rm mongoose.c
${TRICK_HOME}/include/mongoose/mongoose.h: mongoose.h | ${TRICK_HOME}/include/mongoose
@ cp mongoose.h $@
else
# if trick-offline gets updated, we should rebuild libmongoose
${TRICK_LIB_DIR}/libmongoose.a: ${TRICK_HOME}/trick-offline/mongoose.h ${TRICK_HOME}/trick-offline/mongoose.c
mongoose.o: ${TRICK_HOME}/trick-offline/mongoose.h ${TRICK_HOME}/trick-offline/mongoose.c
$(CC) $(TRICK_CFLAGS) -c -I${TRICK_HOME}/trick-offline -o mongoose.o ${TRICK_HOME}/trick-offline/mongoose.c
${TRICK_HOME}/include/mongoose/mongoose.h: ${TRICK_HOME}/trick-offline/mongoose.h | ${TRICK_HOME}/include/mongoose
@ cp ${TRICK_HOME}/trick-offline/mongoose.h $@
endif
${TRICK_HOME}/include/mongoose:
@ mkdir $@
#-------------------------------------------------------------------------------
# 1.3 Build Trick's Java Tools

View File

@ -1,69 +0,0 @@
/*************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server.)
**************************************************************************/
#ifndef WEB_SERVER_H
#define WEB_SERVER_H
#ifdef USE_MONGOOSE
#include <string>
#include <map>
#include <pthread.h>
#ifndef SWIG
#include "mongoose/mongoose.h"
#endif
#include "trick/WebSocketSession.hh"
typedef void (*httpMethodHandler)(struct mg_connection *, struct http_message *);
typedef WebSocketSession* (*WebSocketSessionMaker)(struct mg_connection *nc);
class WebServer {
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;
bool enable;
bool debug;
std::map< std::string, httpMethodHandler> httpGETHandlerMap; /* ** */
pthread_mutex_t httpGETHandlerMapLock; /* ** */
std::map< std::string, WebSocketSessionMaker> WebSocketSessionMakerMap; /* ** */
pthread_mutex_t WebSocketSessionMakerMapLock; /* ** */
std::map<mg_connection*, WebSocketSession*> 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
#endif

View File

@ -99,11 +99,6 @@
#include "trick/lqueue.h"
#include "trick/lstack.h"
//#ifdef USE_MONGOOSE
//#include "trick/WebServer.hh"
//#include "trick/WebSocketSession.hh"
//#endif
#ifdef USE_CIVET
#include "trick/MyCivetServer.hh"
#include "trick/WebSocketSession.hh"

View File

@ -171,13 +171,6 @@ ifneq ($(GSL_HOME),)
TRICK_SYSTEM_CXXFLAGS += -D_HAVE_GSL
endif
#ifeq (${TRICK_MONGOOSE},1)
# TRICK_LIBS += -ltrickHTTP ${TRICK_LIB_DIR}/libmongoose.a
# TRICK_SWIG_FLAGS += -DUSE_MONGOOSE
# TRICK_SYSTEM_CXXFLAGS += -DUSE_MONGOOSE
# TRICK_ICG_EXCLUDE += :${TRICK_HOME}/include/mongoose
#endif
ifeq (${TRICK_MONGOOSE},1) #TODO: Make this use a civet flag instead of a mongoose flag
TRICK_CIVET=0
else

View File

@ -52,10 +52,6 @@ ifeq ($(USE_ER7_UTILS_CHECKPOINTHELPER), 1)
SWIG_DEFS += -DUSE_ER7_UTILS_CHECKPOINTHELPER
endif
#ifeq ($(TRICK_MONGOOSE), 1)
#SWIG_DEFS += -DUSE_MONGOOSE
#endif
ifeq ($(TRICK_CIVET), 1)
SWIG_DEFS += -DUSE_CIVET
endif

View File

@ -1,47 +0,0 @@
/*************************************************************************
PURPOSE: (Represent the state of a variable server websocket connection.)
**************************************************************************/
#ifndef WSSESSION_HH
#define WSSESSION_HH
#include <vector>
#include <string>
#include "mongoose/mongoose.h"
#include "trick/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, ... );
int sendSieMessage(void);
int sendUnitsMessage(const char* vname);
REF2* make_error_ref(const char* in_name);
double stageTime;
bool dataStaged;
std::vector<VariableServerVariable*> sessionVariables;
bool cyclicSendEnabled;
long long nextTime;
long long intervalTimeTics;
};
WebSocketSession* makeVariableServerSession( struct mg_connection *nc );
#endif

View File

@ -1,35 +0,0 @@
/*************************************************************************
PURPOSE: (Represent Websocket variable server variable.)
LIBRARY DEPENDENCIES:
( (../src/VariableServerVariable.o))
**************************************************************************/
#ifndef VARIABLE_SERVER_VARIABLE_HH
#define VARIABLE_SERVER_VARIABLE_HH
#include <time.h>
#include <vector>
#include "mongoose/mongoose.h"
#include <iostream>
#include <trick/reference.h>
#define MAX_ARRAY_LENGTH 4096
class VariableServerVariable {
public:
VariableServerVariable( REF2* variableType);
~VariableServerVariable();
const char* getName();
const char* getUnits();
void stageValue();
void writeValue( std::ostream& chkpnt_os );
private:
VariableServerVariable() {}
REF2 *varInfo;
void *address;
int size;
void *stageBuffer;
bool deref;
};
#endif

View File

@ -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 "mongoose/mongoose.h"
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

View File

@ -1,21 +0,0 @@
/*************************************************************************
PURPOSE: (Represent Websocket variable server connection.)
LIBRARY DEPENDENCIES:
( (../src/WSSession.o))
**************************************************************************/
#ifndef SIMPLEJSON_HH
#define SIMPLEJSON_HH
#include <vector>
class Member {
public:
const char* key;
const char* valText;
int type;
Member(const char *k, const char *v, int t);
};
std::vector<Member*> parseJSON( const char *json_s);
#endif

View File

@ -1,48 +0,0 @@
include ${TRICK_HOME}/share/trick/makefiles/Makefile.common
RM = rm -rf
CC = cc
CPP = c++
CURL = curl
MV = mv
CP = cp
MKDIR = mkdir
CFLAGS = -g -Wall
CPPFLAGS = -g -Wall -std=c++11
INCLUDE_DIRS = -Iinclude -I${TRICK_HOME}/include
OBJDIR = obj
LIBDIR = lib
INCDIR = include
#TRICK_LIB_DIR comes from Makefile.common
TRICK_HTTP_OBJS = \
${OBJDIR}/VariableServerSession.o \
${OBJDIR}/VariableServerVariable.o \
${OBJDIR}/http_GET_handlers.o \
${OBJDIR}/WebServer.o \
${OBJDIR}/simpleJSON.o
#############################################################################
## MODEL TARGETS ##
#############################################################################
all: ${TRICK_LIB_DIR}/libtrickHTTP.a
$(TRICK_HTTP_OBJS): $(OBJDIR)/%.o : src/%.cpp | $(OBJDIR)
$(CPP) $(CPPFLAGS) ${TRICK_SYSTEM_CXXFLAGS} ${INCLUDE_DIRS} -c $< -o $@
${TRICK_LIB_DIR}/libtrickHTTP.a: ${TRICK_HTTP_OBJS}
ar crs $@ ${TRICK_HTTP_OBJS}
# ---------------------------------------------------------------------------
${OBJDIR}:
mkdir -p ${OBJDIR}
clean:
${RM} *~
${RM} ${OBJDIR}

View File

@ -1,271 +0,0 @@
/************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server)
LIBRARY DEPENDENCIES:
((simpleJSON.o)
(VariableServerVariable.o)
)
**************************************************************************/
#include <string>
#include <iostream>
#include <sstream>
#include <iomanip> // for setprecision
#include <fstream>
#include <algorithm>
#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<VariableServerVariable*>::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<Member*> members = parseJSON(client_msg.c_str());
std::vector<Member*>::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 if (cmd == "sie") {
// send S_sie.json
sendSieMessage();
} else if (cmd == "units") {
// send S_sie.json
sendUnitsMessage(var_name.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<VariableServerVariable*>::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<VariableServerVariable*>::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);
}
int VariableServerSession::sendSieMessage(void) {
std::ifstream file("./S_sie.json");
std::stringstream ss;
ss << "{ \"msg_type\": \"sie\", \"data\": ";
ss << file.rdbuf();
file.close();
ss << "}";
std::string tmp = ss.str();
const char* message = tmp.c_str();
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message));
return 0;
}
int VariableServerSession::sendUnitsMessage(const char* vname) {
std::vector<VariableServerVariable*>::iterator it;
std::stringstream ss;
ss << "{ \"msg_type\": \"units\", \"var_name\": \"" << vname << "\", \"data\": \"";
for (it = sessionVariables.begin(); it != sessionVariables.end(); it++ ) {
if(!strcmp((*it)->getName(), vname)) {
ss << (
(
(
(*it)->getUnits() != NULL
) &&
(
(*it)->getUnits()[0] != '\0'
)
) ? (*it)->getUnits() : "--") << "\"}";
std::string tmp = ss.str();
const char* message = tmp.c_str();
mg_send_websocket_frame(connection, WEBSOCKET_OP_TEXT, message, strlen(message));
return 0;
}
}
sendErrorMessage("Variable Server: var_units cannot get units for \"%s\" because it must be added to the variable server first\n", vname);
return 0;
}

View File

@ -1,189 +0,0 @@
#include "trick/memorymanager_c_intf.h" // for get_size.
#include "../include/VariableServerVariable.hh"
#include <math.h> // for fpclassify
#include <iomanip> // 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;
}
const char* VariableServerVariable::getUnits() {
return varInfo->attr->units;
}
static void write_quoted_str( std::ostream& os, const char* s) {
int ii;
int len = strlen(s);
os << "\"" ;
for (ii=0 ; ii<len ; ii++) {
switch ((s)[ii]) {
case '\n': os << "\\n"; break;
case '\t': os << "\\t"; break;
case '\b': os << "\\b"; break;
case '\"': os << "\\\""; break;
default : os << s[ii] ; break;
}
}
os << "\"" ;
}
void VariableServerVariable::stageValue() {
// Copy <size> bytes from <address> 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;
}
}

View File

@ -1,425 +0,0 @@
/************************************************************************
PURPOSE: (Represent the state and initial conditions of an http server)
**************************************************************************/
#include <sys/stat.h> // for mkdir()
#include <unistd.h> // for symlink(), access()
#include <stdlib.h> // for getenv()
#include <dirent.h> // for opendir(), readdir()
#include <iostream>
#include <fstream>
#include "trick/WebServer.hh"
#include "../include/http_GET_handlers.hh"
#include "../include/VariableServerSession.hh"
#include <string.h>
#include <string>
#include "trick/message_proto.h"
#include "trick/message_type.h"
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 =
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\">\n"
"<title>Trick Simulation</title>\n"
"<div class=\"header\">\n"
"<table>\n"
"<th><img src=\"images/trick_icon.png\" height=\"64\" width=\"64\"></th>\n"
"<th><h1>Trick Simulation</h1></th>\n"
"</table>\n"
"</div>\n"
"</head>\n"
"<body>\n"
"<div style=\"background:#efefef\">\n"
"<ul>\n"
"<li><a href=\"http://github.com/nasa/trick\">Trick on GitHub</a></li>\n"
"<li><a href=\"http://github.com/nasa/trick/wiki/Tutorial\">Trick Tutorial</a></li>\n"
"<li><a href=\"http://github.com/nasa/trick/wiki/Documentation-Home\">Trick Documentation</a></li>\n"
"</ul>\n"
"</div>\n"
"<div style=\"background:#efefef\">\n"
"<ul>\n"
"<li><a href=\"/apps\">Applications</a></li>\n"
"</ul>\n"
"</div>\n"
"</body>\n"
"</html>";
static int confirmDocumentRoot ( std::string documentRoot ) {
if ( access( documentRoot.c_str(), F_OK ) != -1 ) {
message_publish(MSG_INFO, "Trick Webserver: Document root \"%s\" exists.\n", documentRoot.c_str());
} else {
message_publish(MSG_INFO, "Trick Webserver: Document root \"%s\" doesn't exist, so we'll create it.\n", documentRoot.c_str());
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 {
message_publish(MSG_ERROR, "Trick Webserver: Failed to create \"%s\".\n", appsDirPath.c_str());
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 {
message_publish(MSG_ERROR, "Trick Webserver: Failed to create \"%s\".\n", imagesDirPath.c_str());
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 {
message_publish(MSG_ERROR, "Trick Webserver: Failed to create \"%s\".\n", documentRoot.c_str());
return 1;
}
} else {
message_publish(MSG_ERROR, "Trick Webserver: TRICK_HOME is not set.\n");
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;
WebServer* httpServer = (WebServer *)nc->user_data;
bool debug = httpServer->debug;
switch(ev) {
case MG_EV_WEBSOCKET_HANDSHAKE_DONE: { // Process new websocket connection.
std::string uri(hm->uri.p, hm->uri.len);
if (debug) { message_publish(MSG_INFO,"Trick Webserver: WEBSOCKET_REQUEST: URI = \"%s\".\n", uri.c_str()); }
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);
if (debug) { message_publish(MSG_INFO, "Trick Webserver: WEBSOCKET[%p] OPENED. URI=\"%s\".\n", (void*)nc, uri.c_str()); }
} else {
nc->flags |= MG_F_SEND_AND_CLOSE;
message_publish(MSG_ERROR, "Trick Webserver: No such web socket interface: \"%s\".\n", uri.c_str());
}
} else {
message_publish(MSG_ERROR, "Trick Webserver: WEBSOCKET_REQUEST: URI does not start with API prefix.\n");
}
} 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);
if (debug) { message_publish(MSG_INFO, "Trick Webserver: WEBSOCKET[%p] RECIEVED: \"%s\".\n", (void*)nc, msg.c_str()); }
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);
if (debug) { message_publish(MSG_INFO,"Trick Webserver: WEBSOCKET[%p] CLOSED.\n", (void*)nc); }
}
} 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);
if (debug) { message_publish(MSG_INFO, "Trick Webserver: HTTP_REQUEST: URI = \"%s\".\n", uri.c_str()); }
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) {
WebServer *S = (WebServer*)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 WebServer::installWebSocketSessionMaker(std::string name, WebSocketSessionMaker maker) {
pthread_mutex_lock(&WebSocketSessionMakerMapLock);
WebSocketSessionMakerMap.insert(std::pair<std::string, WebSocketSessionMaker>(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* WebServer::makeWebSocketSession(struct mg_connection *nc, std::string name) {
std::map<std::string, WebSocketSessionMaker>::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 WebServer::installHTTPGEThandler(std::string handlerName, httpMethodHandler handler) {
pthread_mutex_lock(&httpGETHandlerMapLock);
httpGETHandlerMap.insert(std::pair<std::string, httpMethodHandler>(handlerName, handler));
pthread_mutex_unlock(&httpGETHandlerMapLock);
}
/* Lookup the appropriate httpMethodHandler by name, and execute it for the
given connection and http_message. */
void WebServer::handleHTTPGETrequest(struct mg_connection *nc, http_message *hm, std::string handlerName) {
std::map<std::string, httpMethodHandler>::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 WebServer::marshallWebSocketSessionData() {
std::map<mg_connection*, WebSocketSession*>::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 WebServer::sendWebSocketSessionMessages(struct mg_connection *nc) {
std::map<mg_connection*, WebSocketSession*>::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 WebServer::deleteWebSocketSession(struct mg_connection *nc) {
std::map<mg_connection*, WebSocketSession*>::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 WebServer::handleWebSocketClientMessage(struct mg_connection *nc, std::string msg) {
std::map<mg_connection*, WebSocketSession*>::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 WebServer::addWebSocketSession(struct mg_connection *nc, WebSocketSession* session) {
pthread_mutex_lock(&webSocketSessionMapLock);
webSocketSessionMap.insert( std::pair<mg_connection*, WebSocketSession*>(nc, session) );
pthread_mutex_unlock(&webSocketSessionMapLock);
}
// =========================================================================
// Trick Sim Interface Functions
// =========================================================================
// Trick "default_data" job.
int WebServer::http_default_data() {
port = "8888";
//port = "0";
document_root = "www";
time_homogeneous = false;
service_websocket = false;
shutting_down = false;
sessionDataMarshalled = false;
listener = NULL;
enable = false;
debug = 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 WebServer::http_init() {
if (enable) {
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) {
message_publish(MSG_INFO,"Trick Webserver: Listening on port %s.\n", port);
message_publish(MSG_INFO,"Trick Webserver: Document root = \"%s\"\n.", document_root);
} else {
message_publish(MSG_ERROR, "Trick Webserver: Failed to create listener.\n"
"Perhaps another program is already using port %s.\n", port);
return 1;
}
mg_set_protocol_http_websocket( listener );
pthread_cond_init(&serviceConnections, NULL);
pthread_create( &server_thread, NULL, connectionAttendant, (void*)this );
} else {
message_publish(MSG_INFO, "Trick Webserver: DISABLED. To enable, add "
"\"web.server.enable = True\" to your input file.\n");
}
return 0;
}
int WebServer::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 WebServer::http_shutdown() {
if (listener != NULL) {
message_publish(MSG_INFO,"Trick Webserver: Shutting down on port %s.\n", port);
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;
}

View File

@ -1,222 +0,0 @@
/************************************************************************
PURPOSE: (Represent the state and initial conditions for my server)
**************************************************************************/
#include <sys/stat.h> // for mkdir()
#include <unistd.h> // for symlink(), access()
#include <stdlib.h> // for getenv()
#include <dirent.h> // for opendir(), readdir()
#include <iostream>
#include <fstream>
#include "trick/MyCivetServer.hh"
#include <string.h>
#include <string>
#include "trick/message_proto.h"
#include "trick/message_type.h"
#include "trick/input_processor_proto.h"
#include "trick/exec_proto.h"
#include "../include/simpleJSON.hh"
#include "../include/VariableServerSession.hh"
#include "trick/WebSocketSession.hh"
#ifndef SWIG
#include "civet/CivetServer.h"
#endif
#include "handlers.cpp"
void MyCivetServer::deleteWebSocketSession(struct mg_connection * nc) {
std::map<mg_connection*, WebSocketSession*>::iterator iter;
iter = webSocketSessionMap.find(nc);
if (iter != webSocketSessionMap.end()) {
WebSocketSession* session = iter->second;
delete session;
webSocketSessionMap.erase(iter);
}
}
void* start_civet(void* obj)
{
MyCivetServer* server = (MyCivetServer*)obj;
mg_init_library(0);
struct mg_callbacks callbacks;
memset(&callbacks, 0, sizeof(callbacks));
std::string port = std::to_string(server->port);
const char*options[] = {
"listening_ports", port.c_str(), "document_root", "www", 0
};
server->ctx = mg_start(&callbacks, 0, options);
if (server->ctx == NULL) {
std::cout << "ERROR: Could not create server." << std::endl;
}
mg_set_request_handler(server->ctx, "/api/http/vs_connections", handle_HTTP_GET_vs_connections, NULL);
mg_set_request_handler(server->ctx, "/api/http/alloc_info", handle_HTTP_GET_alloc_info, NULL);
mg_set_websocket_handler(server->ctx, "/api/ws/VariableServer", ws_connect_handler, ws_ready_handler, ws_data_handler, ws_close_handler, obj);
}
WebSocketSession* MyCivetServer::makeWebSocketSession(mg_connection *nc, std::string name) {
std::map<std::string, WebSocketSessionMaker>::iterator iter;
iter = WebSocketSessionMakerMap.find(name);
if (iter != WebSocketSessionMakerMap.end()) {
WebSocketSessionMaker maker = iter->second;
return maker(nc);
} else {
return NULL;
mg_websocket_write(nc, MG_WEBSOCKET_OPCODE_TEXT, "ERROR: Could not create web socket session", 0);
}
}
int MyCivetServer::default_data() {
port = 8888;
enable = true;
debug = true;
sessionDataMarshalled = false;
pthread_mutex_lock(&WebSocketSessionMakerMapLock);
WebSocketSessionMakerMap.insert(std::pair<std::string, WebSocketSessionMaker>("VariableServer", makeVariableServerSession));
pthread_mutex_unlock(&WebSocketSessionMakerMapLock);
return 0;
}
void MyCivetServer::addWebSocketSession(struct mg_connection *nc, WebSocketSession* session) {
pthread_mutex_lock(&WebSocketSessionMapLock);
webSocketSessionMap.insert( std::pair<mg_connection*, WebSocketSession*>(nc, session) );
pthread_mutex_unlock(&WebSocketSessionMapLock);
}
void* main_loop(void* S) {
pthread_t civet_thread;
MyCivetServer* server = (MyCivetServer*) S;
bool messageSent;
int rc = pthread_create(&civet_thread, NULL, start_civet, S);
if (rc) {
std::cout << "Error:unable to create thread," << rc << std::endl;
exit(-1);
}
std::cout << "Starting main loop" << std::endl;
while(1) {
pthread_mutex_lock(&server->lock_loop);
if (!server->sessionDataMarshalled) {
server->marshallWebSocketSessionData();
}
std::map<mg_connection*, WebSocketSession*>::iterator iter;
messageSent = false;
pthread_mutex_lock(&server->WebSocketSessionMapLock);
for (iter = server->webSocketSessionMap.begin(); iter != server->webSocketSessionMap.end(); iter++ ) {
struct mg_connection* conn = iter->first;
WebSocketSession* session = iter->second;
session->sendMessage();
messageSent = true;
}
if (messageSent) {
server->sessionDataMarshalled = false;
}
pthread_mutex_unlock(&server->WebSocketSessionMapLock);
}
pthread_join(civet_thread, NULL);
}
int MyCivetServer::init() {
if (enable) {
int rc;
std::cout << "Init MyCivetServer..." << std::endl;
rc = pthread_create(&server_thread, NULL, main_loop, (void*)this);
if (rc) {
std::cout << "Error:unable to create thread," << rc << std::endl;
exit(-1);
}
std::cout << "Finished init. Server is now listening" << std::endl;
} else {
std::cout << "Not starting my server because it is not enabled." << std::endl;
}
return 0;
}
std::vector<std::string> split(std::string s, std::string delim) {
std::vector<std::string> values;
auto start = 0;
auto end = s.find(delim);
while (end != std::string::npos)
{
values.push_back(s.substr(start, end - start));
start = end + delim.length();
end = s.find(delim, start);
}
values.push_back(s.substr(start, end - start));
return values;
}
int MyCivetServer::http_top_of_frame() {
if (ctx != NULL) {
// marshallWebSocketSessionData(); //TODO: Only do this if time_homogenous is on.
unlockConnections();
}
return 0;
}
void MyCivetServer::unlockConnections() {
pthread_mutex_unlock(&lock_loop);
// std::map<mg_connection*, WebSocketSession*>::iterator iter;
// pthread_mutex_lock(&WebSocketSessionMapLock);
// for (iter = webSocketSessionMap.begin(); iter != webSocketSessionMap.end(); iter++ ) {
// WebSocketSession* session = iter->second;
// mg_unlock_connection(session->connection);
// }
// sessionDataMarshalled = true;
// pthread_mutex_unlock(&WebSocketSessionMapLock);
}
void MyCivetServer::sendWebSocketSessionMessages(struct mg_connection *nc) {
std::map<mg_connection*, WebSocketSession*>::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);
}
void MyCivetServer::marshallWebSocketSessionData() {
std::map<mg_connection*, WebSocketSession*>::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);
}
int MyCivetServer::shutdown() {
if (enable) {
std::cout << "Closing server." << std::endl;
mg_stop(ctx);
mg_exit_library();
// join();
}
return 0;
}
int MyCivetServer::join() {
pthread_join(server_thread, NULL);
return 0;
}

View File

@ -1,65 +0,0 @@
/*************************************************************************
PURPOSE: ( HTTP-GET-method-handlers )
LIBRARY DEPENDENCIES:
( (../src/http_GET_handlers.o))
**************************************************************************/
#include <sstream>
#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 <HTTP_Server-object>.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);
}

View File

@ -1,216 +0,0 @@
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#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<Member*> parseJSON( const char *json_s) {
std::vector<Member*> 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<Member*>::iterator it;
it = members.begin();
while (it != members.end()) {
delete *it;
it = members.erase(it);
}
}
return members;
}