/* Virginia Tech Cognitive Radio Open Source Systems * Virginia Tech, 2009 * * LICENSE INFORMATION GOES HERE */ /* Inter-component communication handled by sockets and FD's. * Server support has been completely implemented and tested. * * Services are stored in a SQLite DB by the ID of the CE that registered them. Service * support has been completely implemented and tested. * * Missions are loaded from an XML file, connected with services provided by components, * and run. See the documentation for the "PerformActiveMission" below for important * info. */ //TODO Add nested conditional support //TODO Verify update functionality //TODO Better shutdown //TODO Verify Deregister services //TODO printf's #include #include #include #include #include #include "vtcross/common.h" #include "components.h" #include "vtcross/containers.h" #include "vtcross/debug.h" #include "vtcross/error.h" #include "vtcross/socketcomm.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tinyxml/tinyxml.h" #include "tinyxml/tinystr.h" #include "sqlite3.h" typedef struct services_s *services_DB; typedef struct data_s *data_DB; using namespace std; struct services_s { char filename[64]; char tablename[64]; char command[2048]; sqlite3 *db; unsigned int num_columns; }; struct data_s { char filename[64]; char tablename[64]; char command[2048]; sqlite3 *db; unsigned int num_columns; }; services_DB _services_DB; data_DB _data_DB; const char *_SML_Config; //Callback function used internally by some of the SQLite3 commands int callback(void *notUsed, int argc, char **argv, char **azColName){ int i; for(i=0; icommand, "drop table "); strcat(_services_DB->command, _services_DB->tablename); int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "ServiceManagementLayer::Destructor services 'drop table' error: %s\n", errorMsg); strcpy(_services_DB->command, "vacuum"); rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "ServiceManagementLayer::Destructor services 'vacuum' error: %s\n", errorMsg); free(_services_DB); strcpy(_data_DB->command, "drop table "); strcat(_data_DB->command, _data_DB->tablename); rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "ServiceManagementLayer::Destructor data 'drop table' error: %s\n", errorMsg); strcpy(_data_DB->command, "vacuum"); rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "ServiceManagementLayer::Destructor data 'vacuum' error: %s\n", errorMsg); free(_data_DB); } //Note that sizes of CE_List, miss, and service are hardcoded for now. //Also, their sizes are hardcoded into the code in various places; a fix for a future version. ServiceManagementLayer::ServiceManagementLayer(const char* SML_Config, \ const char* serverName, const char* serverPort, int16_t clientPort) { LOG("Creating Service Management Layer.\n"); _SML_Config = SML_Config; SMLport = clientPort; ConnectToShell(serverName, serverPort); CE_List = (CE_Reg *) malloc(10*sizeof(struct CE_Reg)); CE_List = new CE_Reg[10]; miss = new Mission[10]; for(int i = 0; i < 10; i++) miss[i].services = new Service[20]; Current_ID = 0; LoadConfiguration(SML_Config, miss); CreateServicesDB(); CreateDataDB(); } /* CALLED BY: constructor * INPUTS: * OUTPUTS: * * DESCRIPTION: Create and initialize a DB to hold the services registered by components */ void ServiceManagementLayer::CreateServicesDB() { sqlite3_stmt *ppStmt; /* OUT: Statement handle */ const char *pzTail; /* OUT: Pointer to unused portion of zSql */ _services_DB = (services_DB) malloc(sizeof(struct services_s)); // char *errorMsg; // create database // copy filename strcpy(_services_DB->filename, "Services_Table"); // execute create database command // database handle //_services_DB->db = NULL; sqlite3_open(_services_DB->filename, &(_services_DB->db)); char* cols[] = {(char *)"ID_Num", (char *)"Service_Name"}; // create table // copy tablename strcpy(_services_DB->tablename, "Services"); sprintf(_services_DB->command, "DROP TABLE IF EXISTS Services;"); int rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, 128, &ppStmt, &pzTail); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc); rc = sqlite3_step(ppStmt); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'step' error\n"); // number of columns in the table _services_DB->num_columns = 2; // generate command strcpy(_services_DB->command, "CREATE TABLE "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, "("); strcat(_services_DB->command, cols[0]); strcat(_services_DB->command, " INT, "); strcat(_services_DB->command, cols[1]); strcat(_services_DB->command, " TEXT"); strcat(_services_DB->command, ");"); // execute create table command rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, 128, &ppStmt, &pzTail); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc); rc = sqlite3_step(ppStmt); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'step' error\n"); } /* CALLED BY: constructor * INPUTS: * OUTPUTS: * * DESCRIPTION: Create and initialize a DB to hold the data sent by components */ void ServiceManagementLayer::CreateDataDB() { _data_DB = (data_DB) malloc(sizeof(struct data_s)); //char *errorMsg; sqlite3_stmt *ppStmt; /* OUT: Statement handle */ const char *pzTail; /* OUT: Pointer to unused portion of zSql */ // create database // copy filename strcpy(_data_DB->filename, "Data_Table"); // execute create database command // database handle //_services_DB->db = NULL; sqlite3_open(_data_DB->filename, &(_data_DB->db)); char* cols[] = {(char *)"Tag", (char *)"Data"}; // create table // copy tablename strcpy(_data_DB->tablename, "Data"); sprintf(_data_DB->command, "DROP TABLE IF EXISTS Data;"); int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, 128, &ppStmt, &pzTail); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc); rc = sqlite3_step(ppStmt); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateServicesDB 'step' error\n"); // number of columns in the table _data_DB->num_columns = 2; // generate command strcpy(_data_DB->command, "CREATE TABLE "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, "("); strcat(_data_DB->command, cols[0]); //First column is the name of the data (coresponding to the name of the output/input pair) //It is the primary key so any subsequent data with the same name will replace the row strcat(_data_DB->command, " TEXT PRIMARY KEY ON CONFLICT REPLACE, "); strcat(_data_DB->command, cols[1]); strcat(_data_DB->command, " TEXT"); strcat(_data_DB->command, ");"); // execute create table command rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, 128, &ppStmt, &pzTail); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateDataDB 'prepare_stmt' error %d\n", rc); rc = sqlite3_step(ppStmt); if( rc!=SQLITE_OK && rc!=101 ) printf("ServiceManagementLayer::CreateDataDB 'step' error\n"); } /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: Sends a message identifying this component as an SML to the Shell */ void ServiceManagementLayer::SendComponentType() { SendMessage(shellSocketFD, "response_sml"); LOG("SML responded to GetRemoteComponentType query.\n"); } /* CALLED BY: constructor * INPUTS: |serverName| the IPv4 name of the server (127.0.0.1 for localhost) * |serverPort| the port on the server to connect to * OUTPUTS: * * DESCRIPTION: Connecting to the shell takes 2 steps * 1) Establish a client socket for communication * 2) Run the initial Registration/handshake routine */ void ServiceManagementLayer::ConnectToShell(const char* serverName, \ const char* serverPort) { shellSocketFD = ClientSocket(serverName, serverPort); RegisterComponent(); } /* CALLED BY: StartSMLServer * INPUTS: |ID| The ID number of the CE that has a message wating * OUTPUTS: * * DESCRIPTION: Called whenever a socket is identified as being ready for communication * This funciton reads the message and calls the appropriate helper */ void ServiceManagementLayer::MessageHandler(int32_t ID) { char buffer[256]; memset(buffer, 0, 256); int32_t _FD; if(ID != -1) _FD = CE_List[ID].FD; else _FD = shellSocketFD; ReadMessage(_FD, buffer); //printf("MH_buffer = %s\n", buffer); //--------Policy Engine Stuff - no policy engine support in this version-------// //printf("********* %s **********\n", buffer); // TODO // If we send integer op codes rather than strings, this process will be // MUCH faster since instead of donig string compares we can simply // switch on the integer value... /*if(strcmp(buffer, "register_service") == 0) { if(strcmp(buffer, "policy_geo") == 0) { } else if(strcmp(buffer, "policy_time") == 0) { } else if(strcmp(buffer, "policy_spectrum") == 0) { } else if(strcmp(buffer, "policy_spacial") == 0) { } } else if(strcmp(buffer, "deregister_service") == 0) { if(strcmp(buffer, "policy_geo") == 0) { } else if(strcmp(buffer, "policy_time") == 0) { } else if(strcmp(buffer, "policy_spectrum") == 0) { } else if(strcmp(buffer, "policy_spacial") == 0) { } }*/ //Go down the list to call the appropriate function if(strcmp(buffer, "query_component_type") == 0) { SendComponentType(); } else if(strcmp(buffer, "reset_sml") == 0) { Reset(); } else if(strcmp(buffer, "shutdown_sml") == 0) { Shutdown(); } else if(strcmp(buffer, "register_engine_cognitive") == 0) { RegisterCognitiveEngine(ID); } else if(strcmp(buffer, "register_service") == 0) { ReceiveServices(ID); } else if(strcmp(buffer, "send_component_type") == 0) { SendComponentType(); } else if(strcmp(buffer, "list_services") == 0) { ListServices(); } else if(strcmp(buffer, "set_active_mission") == 0) { SetActiveMission(); } else if(strcmp(buffer, "request_optimization") == 0) { PerformActiveMission(); } else if(strcmp(buffer, "deregister_engine_cognitive") == 0) { DeregisterCognitiveEngine(ID); } else if(strcmp(buffer, "deregister_service") == 0) { DeregisterServices(ID); } } //TODO Finish /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: Deregisters the component from the Shell. */ void ServiceManagementLayer::Shutdown() { DeregisterComponent(); } //TODO Finish /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: Deregisters the component from the Shell */ void ServiceManagementLayer::Reset() { DeregisterComponent(); ReloadConfiguration(); } /* CALLED BY: ConnectToShell * INPUTS: * OUTPUTS: * * DESCRIPTION: Sends the registration message to the Shell */ void ServiceManagementLayer::RegisterComponent() { SendMessage(shellSocketFD, "register_sml"); LOG("ServiceManagementLayer:: Registration message sent.\n"); //printf("SSFD = %d\n", shellSocketFD); } /* CALLED BY: Shutdown * INPUTS: * OUTPUTS: * * DESCRIPTION: Closes the client socket with the shell, sends a deregstration message */ void ServiceManagementLayer::DeregisterComponent() { SendMessage(shellSocketFD, "deregister_sml"); LOG("ServiceManagementLayer:: Deregistration message sent.\n"); shutdown(shellSocketFD, 2); close(shellSocketFD); shellSocketFD = -1; LOG("ServiceManagementLayer:: Shell socket closed.\n"); } /* CALLED BY: RegisterCognitiveEngine * INPUTS: |ID| The ID number of the component where the data is to be transfered to * OUTPUTS: * * DESCRIPTION: Streams config data directly from the shell to the CE, and checks * for an "ack" message from the CE after every sent message * to know when to stop communication. */ //Modified to check the incoming message buffer rather than the outgoing message buffer to avoid a portion of the delay void ServiceManagementLayer::TransferRadioConfiguration(int32_t ID) { //printf("transRadConfig\n"); struct timeval selTimeout; fd_set sockSet; int32_t rc = 1; char buffer[256]; //Send data until the CE sends an ACK message back while(rc!=0){ memset(buffer, 0, 256); //Receive data from Shell ReadMessage(shellSocketFD, buffer); //printf("buffer = %s\n", buffer); //Send data to CE SendMessage(CE_List[ID].FD, buffer); FD_ZERO(&sockSet); FD_SET(shellSocketFD, &sockSet); selTimeout.tv_sec = 0; selTimeout.tv_usec = 50000; //Check if there is a message on the shell ready to be processed rc=select(shellSocketFD + 1, &sockSet, NULL, NULL, &selTimeout); } memset(buffer, 0, 256); ReadMessage(CE_List[ID].FD, buffer); SendMessage(shellSocketFD, buffer); //printf("transfer done!\n"); } /* CALLED BY: RegisterCognitiveEngine * INPUTS: |ID| The ID number of the component where the data is to be transfered to * OUTPUTS: * * DESCRIPTION: Simmilar to TransferRadioConfig, just with Experience data */ //Modified to check the incoming message buffer rather than the outgoing message buffer to avoid a portion of the delay void ServiceManagementLayer::TransferExperience(int32_t ID) { struct timeval selTimeout; fd_set sockSet; int32_t rc = 1; char buffer[256]; //Send data until the CE sends an ACK message back while(rc!=0){ //printf("transfering...\n"); memset(buffer, 0, 256); //Receive data from Shell ReadMessage(shellSocketFD, buffer); //printf("buffer = %s\n", buffer); //Send data to CE SendMessage(CE_List[ID].FD, buffer); FD_ZERO(&sockSet); FD_SET(shellSocketFD, &sockSet); selTimeout.tv_sec = 0; selTimeout.tv_usec = 50000; //Check if there is a message on the shell ready to be processed rc=select(shellSocketFD + 1, &sockSet, NULL, NULL, &selTimeout); } memset(buffer, 0, 256); //printf("done trans exp!\n"); ReadMessage(CE_List[ID].FD, buffer); SendMessage(shellSocketFD, buffer); } /* CALLED BY: MessageHandler * INPUTS: |ID| The ID number of the component where service is located * OUTPUTS: * * DESCRIPTION: Inserts a service into the DB with the ID of the component where it exists */ void ServiceManagementLayer::ReceiveServices(int32_t ID) { char buffer[256]; memset(buffer, 0, 256); ReadMessage(CE_List[ID].FD, buffer); char* cols[] = {(char *)"ID_Num", (char *)"Service_Name"}; //printf("RS_buffer = %s\n", buffer); // generate command strcpy(_services_DB->command, "insert into "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, " ("); strcat(_services_DB->command, cols[0]); strcat(_services_DB->command, ", "); strcat(_services_DB->command, cols[1]); strcat(_services_DB->command, ") "); strcat(_services_DB->command, " values("); sprintf(_services_DB->command, "%s%d", _services_DB->command, ID); strcat(_services_DB->command, ", '"); strcat(_services_DB->command, buffer); strcat(_services_DB->command, "');"); //printf("search command: %s\n", _services_DB->command); // execute add command char *errorMsg; int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "ServiceManagementLayer::RecieveServices DB Error %s\n", errorMsg); /*sprintf(outBuffer, "SML: Registering service '%s' from component number '%d'", buffer, ID); LOG(outBuffer);*/ } /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: This method associates the services that components provide with the services that are requested in the mission * Each service in the mission is given the ID and FD of a component that has registered to provide that service * Deregistration is okay until this method is called without a reload, but if deregistration occurs after this * method is called it needs to be called again even if other engines also provide the services */ void ServiceManagementLayer::SetActiveMission() { char buffer[256]; memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); uint32_t missID = atoi(buffer); for(activeMission = 0; activeMission < 10; activeMission++) { //Find the active mission by comparing mission ID's if(miss[activeMission].missionID == missID) break; } LOG("ServiceManagementLayer:: Received Set Active Mission command: %i.\n",missID); //For each service in the mission for(uint16_t i = 0; i < miss[activeMission].numServices; i++) { //Check whether the current service is an actual service or a conditional if(miss[activeMission].services[i].name.compare("if") && miss[activeMission].services[i].name.compare("dowhile") && \ miss[activeMission].services[i].name.compare("shell")){ //If it is a service, search the database of registered services to find the ID of the component that registered it strcpy(_services_DB->command, "select "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, ".* from "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, " where Service_Name=="); sprintf(_services_DB->command, "%s'%s';", _services_DB->command, miss[activeMission].services[i].name.c_str()); sqlite3_stmt * pStatement; int rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) miss[activeMission].services[i].componentID = sqlite3_column_int(pStatement, 0); else { printf("services_DB:: Mission requires service %s not provided by any connected component.\n",miss[activeMission].services[i].name.c_str()); rc=31337; } } else { printf("services_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_services_DB->command); } //printf("s_name=%s\n",miss[activeMission].services[i].name.c_str()); sqlite3_finalize(pStatement); miss[activeMission].services[i].socketFD = CE_List[miss[activeMission].services[i].componentID].FD; //Set the FD and ID of the service to refer to the component where the service exists } //Nothing to be done for conditionals at this stage } SendMessage(shellSocketFD, "ack"); LOG("ServiceManagementLayer:: Done setting active mission.\n"); //printf("\nhere ---%d, %d---\n", miss[activeMission].services[0].componentID, miss[activeMission].services[1].componentID); } /* CALLED BY: PerformActiveMission * INPUTS: |sourceID| ID of the service that is being processed * OUTPUTS: * * DESCRIPTION: This is a helper method for the "PerformActiveMission" function * NOTE: This function has changed durrastically from the previous implementation * Takes an ID of a service * For that service, finds inputs in DB and forwords those on to the engine after sending comm-starting messages * Afterwords, listenes for the outputs so that it can store those in the database for future services or the overall output */ void ServiceManagementLayer::TransactData(int32_t sourceID) { // LOG("ServiceManagementLayer:: Data transaction occuring.\n"); char buffer[256]; std::string data; char* cols[] = {(char *)"Tag", (char *)"Data"}; int i = 0; fd_set sockSet; char *token; struct timeval selTimeout; //Send a message directly to the shell //printf("name = %s\n", miss[activeMission].services[sourceID].name.c_str()); if(miss[activeMission].services[sourceID].name.find("shell")!=string::npos) { //printf("caught shell\n"); //If the name on the output doesn't start with "~", search the DB to find the output that should be returned if(miss[activeMission].services[sourceID].output[0].find("~") == string::npos){ // printf("taken1\n"); memset(buffer, 0 , 256); strcpy(_data_DB->command, "select "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, miss[activeMission].services[sourceID].output[0].c_str()); sqlite3_stmt * pStatement; int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data.append((const char*) sqlite3_column_text(pStatement, 1)); else { //TODO could do shell output here if not in DB data.append("1@"); data.append(miss[activeMission].services[sourceID].output[0]); data.append("@"); data.append(miss[activeMission].services[sourceID].output[0]); data.append("@"); //printf("data = %s\n", data.c_str()); printf("data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); token = strtok((char *)data.c_str(), "@"); SendMessage(shellSocketFD, token); token = strtok(NULL, "@"); while(token){ SendMessage(shellSocketFD, token); token = strtok(NULL, "@"); } } //printf("done shell\n"); // LOG("ServiceManagementLayer:: Finished with data transaction.\n"); return; } //If this is a service command and not a shell command... //Transmission starting messages SendMessage(miss[activeMission].services[sourceID].socketFD, "request_optimization_service"); SendMessage(miss[activeMission].services[sourceID].socketFD, miss[activeMission].services[sourceID].name.c_str()); //Find and load the input data while(i < 5 && !miss[activeMission].services[sourceID].input[i].empty()){ //printf("pulling input data out of DB for ID#=%d\n", sourceID); strcpy(_data_DB->command, "select "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); char temp[100]; strcpy(temp, miss[activeMission].services[sourceID].input[i].c_str()); char *temp2 = strtok(temp, "+"); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, temp2); sqlite3_stmt * pStatement; int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data.append((const char*) sqlite3_column_text(pStatement, 1)); else { printf("data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); char *data_ch = (char *) data.c_str(); int32_t numStatements = 0; temp2 = strtok(NULL, "+"); while(temp2){ numStatements++; temp2 = strtok(NULL, "+"); } //printf("here1%d\n", numStatements); char temp4[10]; memset(temp4, 0, 10); sprintf(temp4, "%d", numStatements); //Tokenize the data and pass it along //printf("here2 %s\n", temp4); if(strstr(miss[activeMission].services[sourceID].input[i].c_str(), "+")){ SendMessage(miss[activeMission].services[sourceID].socketFD, temp4); token = strtok(data_ch, "@"); } else{ token = strtok(data_ch, "@"); SendMessage(miss[activeMission].services[sourceID].socketFD, token); } token = strtok(NULL, "@"); //Either have to send whole block of memory or just one piece while(token){ if(strstr(miss[activeMission].services[sourceID].input[i].c_str(), token)) { //printf("1tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token); SendMessage(miss[activeMission].services[sourceID].socketFD, token); token = strtok(NULL, "@"); SendMessage(miss[activeMission].services[sourceID].socketFD, token); } else if(!strstr(miss[activeMission].services[sourceID].input[i].c_str(), "+")) { //printf("t not detected tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token); SendMessage(miss[activeMission].services[sourceID].socketFD, token); token = strtok(NULL, "@"); SendMessage(miss[activeMission].services[sourceID].socketFD, token); } else{ //printf("3tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token); token = strtok(NULL, "@");} token = strtok(NULL, "@"); } //printf("done\n"); //printf("done pulling input data out of DB for ID#=%d\n", sourceID); i++; data.clear(); } int32_t j = 0; FD_ZERO(&sockSet); FD_SET(miss[activeMission].services[sourceID].socketFD, &sockSet); //TODO neccessary? selTimeout.tv_sec = 5; selTimeout.tv_usec = 0; //Use select command to force wait for processing to finish select(miss[activeMission].services[sourceID].socketFD + 1, &sockSet, NULL, NULL, &selTimeout); //printf("done\n"); //TODO rewrite part of data on output? //TODO true false format? while(j < 5 && !miss[activeMission].services[sourceID].output[j].empty()){ int rc; memset(buffer, 0, 256); ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer); // printf("waiting\n"); data.append(buffer); data.append("@"); int t = atoi(buffer); //printf("%d\n", t); for(int k = 0; k < t; k++){ //Read the data incrementally and deliminate it with the "@" symbol memset(buffer, 0, 256); ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer); if(!strcmp(buffer, "TF")){ ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer); data.append(buffer); data.append("@"); } else{ data.append(buffer); data.append("@"); memset(buffer, 0, 256); ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer); data.append(buffer); data.append("@"); } } //printf("SML: putting output data into DB for ID#=%d\n", sourceID); strcpy(_data_DB->command, "insert or replace into "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " ("); strcat(_data_DB->command, cols[0]); strcat(_data_DB->command, ", "); strcat(_data_DB->command, cols[1]); strcat(_data_DB->command, ") "); strcat(_data_DB->command, " values('"); strcat(_data_DB->command, miss[activeMission].services[sourceID].output[j].c_str()); strcat(_data_DB->command, "', '"); strcat(_data_DB->command, data.c_str()); strcat(_data_DB->command, "');"); char *errorMsg; rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); //printf("S: done putting ouptut data into DB for ID#='%d', data=%s\n", sourceID, data.c_str()); j++; data.clear(); } //printf("done transact data!\n"); // LOG("ServiceManagementLayer:: Finished with data transaction.\n"); /*printf("\n\n\n"); // generate commandi strcpy(_data_DB->command, "select "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ";"); // execute print (select all) command char *errorMsg; int rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); printf("database %s, table %s:\n", _data_DB->filename, _data_DB->tablename); printf("\n\n\n");*/ } /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: This function works by first sending the inputs from the shell to the appropriate components * The first service should begin immeadiately, as should any others who have all of their input paramaters * When they complete, the output path is found and the data is transfered as it becomes available * Presumably at this point the second function has all of it's paramaters, so it begins to compute, and the cycle repeats * * * Rules for active missions (currently) * -Five inputs/outputs per service and per mission * -All ordering constraints have been relaxed in this version; all data is stored locally and only sent when requested * -If support fully implemented - up to three levels * -While support still a work in progress * -IMPORTANT: DB uses '@' to seperate individual statements; using '@' in the data stream will result in incorrect behavior */ //IF-IF-IF //WHILE void ServiceManagementLayer::PerformActiveMission() { uint16_t i = 0; std::string data_param, data_obsv, data; std::string input; std::string check; char buffer[256]; char buffer1[256]; char *token; int rc; char *errorMsg; char* cols[] = {(char *)"Tag", (char *)"Data"}; //Get the inputs memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); LOG("ServiceManagementLayer:: Received PerformActiveMission command.\n"); int32_t t = atoi(buffer); /* Receive Set of Observables */ for(int32_t m = 0; m < t; m++) { //printf("data=%s\n", data_obsv.c_str()); memset(buffer1, 0, 256); ReadMessage(shellSocketFD, buffer1); strcpy(_data_DB->command, "insert into "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " ("); strcat(_data_DB->command, cols[0]); strcat(_data_DB->command, ", "); strcat(_data_DB->command, cols[1]); strcat(_data_DB->command, ") "); memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); sprintf(_data_DB->command, "%s values('%s', '1@%s@%s", _data_DB->command, buffer1, buffer1, buffer); strcat(_data_DB->command, "');"); rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); } /* Receive Set of Parameters */ memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); t=atoi(buffer); for(int m = 0; m < t; m++) { //printf("data=%s\n", data_obsv.c_str()); memset(buffer1, 0, 256); ReadMessage(shellSocketFD, buffer1); strcpy(_data_DB->command, "insert into "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " ("); strcat(_data_DB->command, cols[0]); strcat(_data_DB->command, ", "); strcat(_data_DB->command, cols[1]); strcat(_data_DB->command, ") "); memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); sprintf(_data_DB->command, "%s values('%s', '1@%s@%s');", _data_DB->command, buffer1, buffer1, buffer); rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); } while(i < 5 && !miss[activeMission].input[i].empty()){ //New data being added to DB //printf("inserting data from shell\n"); memset(buffer1, 0, 256); ReadMessage(shellSocketFD, buffer1); t=atoi(buffer1); //printf("t=%d\n", t); for(int m = 0; m < t; m++) { data.append("@"); memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); data.append(buffer); data.append("@"); memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); data.append(buffer); } //printf("here %s\n", data.c_str()); strcpy(_data_DB->command, "insert into "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " ("); strcat(_data_DB->command, cols[0]); strcat(_data_DB->command, ", "); strcat(_data_DB->command, cols[1]); strcat(_data_DB->command, ") "); strcat(_data_DB->command, " values('"); strcat(_data_DB->command, miss[activeMission].input[i].c_str()); sprintf(_data_DB->command, "%s', '%s%s');", _data_DB->command, buffer1, data.c_str()); char *errorMsg; rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); //printf("SML: finished adding data from shell on input %d\n", i); i++; data.clear(); } //Useful for spotchecking what's in the database /*printf("\n\n\n"); // generate commandi strcpy(_data_DB->command, "select "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ";"); // execute print (select all) command rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); printf("database %s, table %s:\n", _data_DB->filename, _data_DB->tablename); printf("\n\n\n");*/ // printf("done\n"); i=0; int32_t numstatements[3] = {0,0,0}; while(i < miss[activeMission].numServices) { if(miss[activeMission].services[i].name.compare("if")==0) { //printf("L0:if detected\n"); input.clear(); check.clear(); int t; for(t = 0; t < 5; t++){ if(!miss[activeMission].services[i].output[t].empty()){ //printf("i-numstmts-1 = %d\n", i-numstatements[0]-1); input=miss[activeMission].services[i-numstatements[0]-1].output[t]; strcpy(_data_DB->command, "SELECT "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str()); sqlite3_stmt * pStatement; rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data = (const char *) sqlite3_column_text(pStatement, 1); else { printf("1 data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); //printf("data=%s\n", data.c_str()); token = strtok((char *)data.c_str(), "@"); token = strtok(NULL, "@"); token = strtok(NULL, "@"); //printf("data=%s\n", token); break; } } //printf("L0:--- %s %s---\n", miss[activeMission].services[i].output[t].c_str(), token); //TODO change to strstr if(strstr(miss[activeMission].services[i].output[t].c_str(), token)){ //printf("L0:if taken\n"); for(uint16_t k = i+1; k <= i+miss[activeMission].services[i].num_conds; k++){ //printf("transacting data for k=%d\n", k); //printf("%s---%d\n", miss[activeMission].services[k].name.c_str(), k); if(miss[activeMission].services[k].name.compare("if")==0){ //printf("L1:if detected\n"); input.clear(); check.clear(); for(t = 0; t < 5; t++){ if(!miss[activeMission].services[k].output[t].empty()){ //printf("i-numstmts = %d\n", i-numstatements-1); input=miss[activeMission].services[k-numstatements[1]-1].output[t]; strcpy(_data_DB->command, "SELECT "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str()); sqlite3_stmt * pStatement; rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data = (const char *) sqlite3_column_text(pStatement, 1); else { printf("1 data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); //printf("data=%s\n", data.c_str()); token = strtok((char *)data.c_str(), "@"); token = strtok(NULL, "@"); token = strtok(NULL, "@"); //printf("data=%s\n", token); break; } } //printf("L1:--- %s %s---\n", miss[activeMission].services[k].output[t].c_str(), token); //TODO change to strstr if(strstr(miss[activeMission].services[k].output[t].c_str(), token)){ //printf("L1:if taken\n"); for(uint16_t j = k+1; j <= k+miss[activeMission].services[k].num_conds; j++){ //printf("transacting data for k=%d\n", k); //printf("%s---%d\n", miss[activeMission].services[j].name.c_str(), j); if(miss[activeMission].services[j].name.compare("if")==0){ //printf("L2:if detected\n"); input.clear(); check.clear(); for(t = 0; t < 5; t++){ if(!miss[activeMission].services[j].output[t].empty()){ //printf("i-numstmts = %d\n", i-numstatements-1); input=miss[activeMission].services[j-numstatements[2]-1].output[t]; strcpy(_data_DB->command, "SELECT "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str()); sqlite3_stmt * pStatement; rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data = (const char *) sqlite3_column_text(pStatement, 1); else { printf("1 data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); //printf("data=%s\n", data.c_str()); token = strtok((char *)data.c_str(), "@"); token = strtok(NULL, "@"); token = strtok(NULL, "@"); //printf("data=%s\n", token); break; } } //printf("L2:--- %s %s---\n", miss[activeMission].services[j].output[t].c_str(), token); //TODO change to strstr if(strstr(miss[activeMission].services[j].output[t].c_str(), token)){ //printf("L1:if taken\n"); for(uint16_t l = j+1; l <= j+miss[activeMission].services[j].num_conds; l++){ //printf("transacting data for k=%d\n", k); TransactData(l); } } else //printf("L2: if not taken\n"); numstatements[2] +=miss[activeMission].services[j].num_conds+1; j+=miss[activeMission].services[j].num_conds; //printf("doneif %d, %d, %d\n", numstatements, miss[activeMission].services[i].num_conds, i); } else{ //printf("NO L2 COND!\n"); numstatements[2]=0; TransactData(j); } } } else //printf("L1: if not taken\n"); numstatements[1] +=miss[activeMission].services[k].num_conds+1; k+=miss[activeMission].services[k].num_conds; //printf("doneif %d, %d, %d\n", numstatements, miss[activeMission].services[i].num_conds, i); } else if(miss[activeMission].services[k].name.compare("dowhile")==0){ //printf("while detected\n"); while(true){ uint16_t m; for(uint16_t m = k+1; m <= k+miss[activeMission].services[k].num_conds; m++){ TransactData(m); printf("transact! %d\n", m); } data.clear(); printf("L1:while detected %d, %d\n", miss[activeMission].services[k].num_conds, k); input.clear(); check.clear(); int t; for(t = 0; t < 5; t++){ if(!miss[activeMission].services[k-1].output[t].empty()){ input=miss[activeMission].services[m].output[t]; strcpy(_data_DB->command, "SELECT "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str()); sqlite3_stmt * pStatement; rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data = (const char *) sqlite3_column_text(pStatement, 1); else { printf("1 data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); //printf("data=%s\n", data.c_str()); token = strtok((char *)data.c_str(), "@"); token = strtok(NULL, "@"); token = strtok(NULL, "@"); //printf("data=%s\n", token); break; } } printf("L1:--- %s %s---\n", miss[activeMission].services[k].output[t].c_str(), token); if(strstr(miss[activeMission].services[k].output[t].c_str(), token)){ printf("L1:do it again!\n"); } else break; } k+=miss[activeMission].services[k].num_conds; //printf("donewhile\n"); } else{ //printf("NO L1 COND!\n"); numstatements[1]=0; TransactData(k); } //numstatements[0] +=miss[activeMission].services[i].num_conds+1; //i+=miss[activeMission].services[i].num_conds; //printf("doneif %d, %d, %d\n", numstatements, miss[activeMission].services[i].num_conds, i); } } // else //printf("LO if not taken\n"); numstatements[0] +=miss[activeMission].services[i].num_conds+1; i+=miss[activeMission].services[i].num_conds; //printf("doneif %d, %d, %d\n", numstatements, miss[activeMission].services[i].num_conds, i); } else if(miss[activeMission].services[i].name.compare("dowhile")==0) { numstatements[0]=0; //printf("while detected\n"); while(true){ uint16_t k; for(k = i+1; k <= i+miss[activeMission].services[i].num_conds; k++){ TransactData(k); } data.clear(); //printf("L0:while detected %d, %d\n", k, miss[activeMission].services[i].num_conds); input.clear(); check.clear(); int t; for(t = 0; t < 5; t++){ if(!miss[activeMission].services[i].output[t].empty()){ input=miss[activeMission].services[k-1].output[t]; //printf("input=%s\n", input.c_str()); strcpy(_data_DB->command, "SELECT "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str()); sqlite3_stmt * pStatement; rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data = (const char *) sqlite3_column_text(pStatement, 1); else { printf("1 data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } sqlite3_finalize(pStatement); //printf("data=%s\n", data.c_str()); token = strtok((char *)data.c_str(), "@"); token = strtok(NULL, "@"); token = strtok(NULL, "@"); //printf("data=%s\n", token); break; } } //printf("L0:--- %s %s---\n", miss[activeMission].services[i].output[t].c_str(), token); if(strstr(miss[activeMission].services[i].output[t].c_str(), token)){ //printf("L0:while taken again!\n"); } else break; } i+=miss[activeMission].services[i].num_conds; //printf("doneif\n"); } else{ numstatements[0]=0; //printf("L0 Neither if nor while\n"); TransactData(i);} i++; //printf("i=%d\n", i); } i=0; data.clear(); //get the ouptuts while(i < 5 && !miss[activeMission].output[i].empty()){ //printf("sending output data to shell\n"); strcpy(_data_DB->command, "select "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, ".* from "); strcat(_data_DB->command, _data_DB->tablename); strcat(_data_DB->command, " where Tag=="); sprintf(_data_DB->command, "%s'%s';", _data_DB->command, miss[activeMission].output[i].c_str()); sqlite3_stmt * pStatement; int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL); if (rc == SQLITE_OK){ if (sqlite3_step(pStatement) == SQLITE_ROW) data.append((const char*) sqlite3_column_text(pStatement, 1)); else { printf("data_DB:: Data not yet in DB.\n"); rc=31337; } } else { printf("services_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command); } //printf("here %s\n", data.c_str()); sqlite3_finalize(pStatement); char *data_ch = (char *) data.c_str(); char *token = strtok(data_ch, "@"); SendMessage(shellSocketFD, token); token = strtok(NULL, "@"); while(token){ SendMessage(shellSocketFD, token); //printf("token1 = %s\n", token); token = strtok(NULL, "@"); SendMessage(shellSocketFD, token); //printf("token2 = %s\n", token); token = strtok(NULL, "@"); } i++; data.clear(); } LOG("ServiceManagementLayer:: Done sending output data to shell from PerformActiveMission.\n"); } /* CALLED BY: MessageHandler * INPUTS: * OUTPUTS: * * DESCRIPTION: Print a list of the services currently registered and the ID's of the components that registered them */ void ServiceManagementLayer::ListServices() { // generate commandi strcpy(_services_DB->command, "select "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, ".* from "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, ";"); // execute print (select all) command char *errorMsg; int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); printf("database %s, table %s:\n", _services_DB->filename, _services_DB->tablename); } /* CALLED BY: Reset * INPUTS: * OUTPUTS: * * DESCRIPTION: Clear and reinitialize the mission array, then reload the configuration file */ void ServiceManagementLayer::ReloadConfiguration() { LOG("ServiceManagementLayer:: Reloading Configuration.\n"); free(miss); miss = new Mission[10]; for(int i = 0; i < 10; i++) miss[i].services = new Service[20]; LoadConfiguration(_SML_Config, miss); } /* CALLED BY: constructor * INPUTS: |SML_Config| Address (either relitive or full) of the XML file containing mission data * |mList| Mission array to be modified * OUTPUTS: * * DESCRIPTION: IMPORTANT - See formatting instructions for correct parsing of data * Can currently handle 5 inputs and 5 outputs per service, but easily expandable * Also, can handle two layer of nested conditional statements, but could * be expanded to meet additional needs. * * Components assigned to mission during "set active mission" stage so that * components can still continue to register after the configuration is loaded */ void ServiceManagementLayer::LoadConfiguration(const char *SML_Config, Mission* &mList) { TiXmlElement *pMission; TiXmlElement *pService; TiXmlElement *pChild0, *pChild1, *pChild2, *pChild3, *pChild4; TiXmlHandle hRoot(0); printf("ServiceManagementLayer:: Loading Configuration.\n"); TiXmlDocument doc("."); doc.LoadFile(SML_Config); bool loadOkay = doc.LoadFile(); if(!loadOkay) printf("Loading SML configuration failed: %s\n", SML_Config); TiXmlHandle hDoc(&doc); pMission = hDoc.FirstChildElement().Element(); if(!pMission) printf("No valid root!"); hRoot = TiXmlHandle(pMission); pService = pMission->FirstChildElement(); int32_t mission_num = 0; //Iterate through the missions for(pChild0 = pMission->FirstChildElement(); pChild0 ; \ pChild0 = pChild0->NextSiblingElement()) { int32_t service_num = 0; uint16_t cond_array[] = {0, 0, 0}; //printf("mission_num = %d\n", mission_num); //memset(cond_array, 0, 2); for(pChild1 = pChild0->FirstChildElement(); pChild1; \ pChild1 = pChild1->NextSiblingElement()) { int32_t conditional_0 = service_num; for(pChild2 = pChild1->FirstChildElement(); \ pChild2; pChild2 = pChild2->NextSiblingElement()) { service_num++; int32_t conditional_1 = service_num; for(pChild3 = pChild2->FirstChildElement(); \ pChild3; pChild3 = pChild3->NextSiblingElement()) { service_num++; int32_t conditional_2 = service_num; for(pChild4 = pChild3->FirstChildElement(); \ pChild4; pChild4 = pChild4->NextSiblingElement()) { service_num++; if(pChild4->Attribute("name")) mList[mission_num].services[service_num].name = pChild4->Attribute("name"); else mList[mission_num].services[service_num].name = pChild4->Value(); if(pChild4->Attribute("input1")) mList[mission_num].services[service_num].input[0] = pChild4->Attribute("input1"); if(pChild4->Attribute("input2")) mList[mission_num].services[service_num].input[1] = pChild4->Attribute("input2"); if(pChild4->Attribute("input3")) mList[mission_num].services[service_num].input[2] = pChild4->Attribute("input3"); if(pChild4->Attribute("input4")) mList[mission_num].services[service_num].input[3] = pChild4->Attribute("input4"); if(pChild4->Attribute("input5")) mList[mission_num].services[service_num].input[4] = pChild4->Attribute("input5"); if(pChild4->Attribute("output1")) mList[mission_num].services[service_num].output[0] = pChild4->Attribute("output1"); if(pChild4->Attribute("output2")) mList[mission_num].services[service_num].output[1] = pChild4->Attribute("output2"); if(pChild4->Attribute("output3")) mList[mission_num].services[service_num].output[2] = pChild4->Attribute("output3"); if(pChild4->Attribute("output4")) mList[mission_num].services[service_num].output[3] = pChild4->Attribute("output4"); if(pChild4->Attribute("output5")) mList[mission_num].services[service_num].output[4] = pChild4->Attribute("output5"); cond_array[2]++; } if(!strcmp(pChild3->Value(), "shell") || conditional_2 != service_num) { mList[mission_num].services[conditional_2].name = pChild3->Value(); } else{ mList[mission_num].services[service_num].name = pChild3->Attribute("name"); } if(pChild3->Attribute("input1")) mList[mission_num].services[conditional_2].input[0] = pChild3->Attribute("input1"); if(pChild3->Attribute("input2")) mList[mission_num].services[conditional_2].input[1] = pChild3->Attribute("input2"); if(pChild3->Attribute("input3")) mList[mission_num].services[conditional_2].input[2] = pChild3->Attribute("input3"); if(pChild3->Attribute("input4")) mList[mission_num].services[conditional_2].input[3] = pChild3->Attribute("input4"); if(pChild3->Attribute("input5")) mList[mission_num].services[conditional_2].input[4] = pChild3->Attribute("input5"); if(pChild3->Attribute("output1")) mList[mission_num].services[conditional_2].output[0] = pChild3->Attribute("output1"); if(pChild3->Attribute("output2")) mList[mission_num].services[conditional_2].output[1] = pChild3->Attribute("output2"); if(pChild3->Attribute("output3")) mList[mission_num].services[conditional_2].output[2] = pChild3->Attribute("output3"); if(pChild3->Attribute("output4")) mList[mission_num].services[conditional_2].output[3] = pChild3->Attribute("output4"); if(pChild3->Attribute("output5")) mList[mission_num].services[conditional_2].output[4] = pChild3->Attribute("output5"); mList[mission_num].services[conditional_2].num_conds = cond_array[2]; cond_array[1]+=cond_array[2]+1; //printf("cond_array[2]%d\n", cond_array[2]); cond_array[2] = 0; } if(!strcmp(pChild2->Value(), "shell") || conditional_1 != service_num) { mList[mission_num].services[conditional_1].name = pChild2->Value(); } else{ mList[mission_num].services[service_num].name = pChild2->Attribute("name"); } if(pChild2->Attribute("input1")) mList[mission_num].services[conditional_1].input[0] = pChild2->Attribute("input1"); if(pChild2->Attribute("input2")) mList[mission_num].services[conditional_1].input[1] = pChild2->Attribute("input2"); if(pChild2->Attribute("input3")) mList[mission_num].services[conditional_1].input[2] = pChild2->Attribute("input3"); if(pChild2->Attribute("input4")) mList[mission_num].services[conditional_1].input[3] = pChild2->Attribute("input4"); if(pChild2->Attribute("input5")) mList[mission_num].services[conditional_1].input[4] = pChild2->Attribute("input5"); if(pChild2->Attribute("output1")) mList[mission_num].services[conditional_1].output[0] = pChild2->Attribute("output1"); if(pChild2->Attribute("output2")) mList[mission_num].services[conditional_1].output[1] = pChild2->Attribute("output2"); if(pChild2->Attribute("output3")) mList[mission_num].services[conditional_1].output[2] = pChild2->Attribute("output3"); if(pChild2->Attribute("output4")) mList[mission_num].services[conditional_1].output[3] = pChild2->Attribute("output4"); if(pChild2->Attribute("output5")) mList[mission_num].services[conditional_1].output[4] = pChild2->Attribute("output5"); mList[mission_num].services[conditional_1].num_conds = cond_array[1]; cond_array[0]+=cond_array[1]+1; //printf("cond_array[1]%d\n", cond_array[1]); cond_array[1] = 0; } if(!strcmp(pChild1->Value(), "shell") || conditional_0 != service_num) { mList[mission_num].services[conditional_0].name = pChild1->Value(); } else{ mList[mission_num].services[conditional_0].name = pChild1->Attribute("name"); } //printf("name=%s\n", mList[mission_num].services[conditional_0].name.c_str()); if(pChild1->Attribute("input1")) mList[mission_num].services[conditional_0].input[0] = pChild1->Attribute("input1"); if(pChild1->Attribute("input2")) mList[mission_num].services[conditional_0].input[1] = pChild1->Attribute("input2"); if(pChild1->Attribute("input3")) mList[mission_num].services[conditional_0].input[2] = pChild1->Attribute("input3"); if(pChild1->Attribute("input4")) mList[mission_num].services[conditional_0].input[3] = pChild1->Attribute("input4"); if(pChild1->Attribute("input5")) mList[mission_num].services[conditional_0].input[4] = pChild1->Attribute("input5"); if(pChild1->Attribute("output1")) mList[mission_num].services[conditional_0].output[0] = pChild1->Attribute("output1"); if(pChild1->Attribute("output2")) mList[mission_num].services[conditional_0].output[1] = pChild1->Attribute("output2"); if(pChild1->Attribute("output3")) mList[mission_num].services[conditional_0].output[2] = pChild1->Attribute("output3"); if(pChild1->Attribute("output4")) mList[mission_num].services[conditional_0].output[3] = pChild1->Attribute("output4"); if(pChild1->Attribute("output5")) mList[mission_num].services[service_num].output[4] = pChild1->Attribute("output4"); mList[mission_num].services[conditional_0].num_conds = cond_array[0]; cond_array[0] = 0; service_num++; } //for(int i = 0; i < service_num; i++) //printf("ttt%d\n", mList[mission_num].services[i].num_conds); mList[mission_num].numServices = service_num; mList[mission_num].name = pChild0->Attribute("name"); mList[mission_num].missionID = atoi(pChild0->Attribute("id")); if(pChild0->Attribute("input1")) mList[mission_num].input[0] = pChild0->Attribute("input1"); if(pChild0->Attribute("input2")) mList[mission_num].input[1] = pChild0->Attribute("input2"); if(pChild0->Attribute("input3")) mList[mission_num].input[2] = pChild0->Attribute("input3"); if(pChild0->Attribute("input4")) mList[mission_num].input[3] = pChild0->Attribute("input4"); if(pChild0->Attribute("input5")) mList[mission_num].input[4] = pChild0->Attribute("input4"); if(pChild0->Attribute("output1")) mList[mission_num].output[0] = pChild0->Attribute("output1"); if(pChild0->Attribute("output2")) mList[mission_num].output[1] = pChild0->Attribute("output2"); if(pChild0->Attribute("output3")) mList[mission_num].output[2] = pChild0->Attribute("output3"); if(pChild0->Attribute("output4")) mList[mission_num].output[3] = pChild0->Attribute("output4"); if(pChild0->Attribute("output5")) mList[mission_num].output[4] = pChild0->Attribute("output5"); //printf("mis, input1=%s, output1=%s\n", mList[mission_num].input[0].c_str(), mList[mission_num].output[0].c_str()); //printf("NUMSERVICES = %d\n", mList[mission_num].numServices); mission_num++; } } /* CALLED BY: MessageHandler * INPUTS: |ID| The ID number of the engine to be registered * OUTPUTS: * * DESCRIPTION: Sends a registration message onto the shell and sends the ACK back to the component */ void ServiceManagementLayer::RegisterCognitiveEngine(int32_t ID) { //LOG("SML::regcogeng"); SendMessage(shellSocketFD, "register_engine_cognitive"); // printf("SSFD = %d\n", shellSocketFD); LOG("ServiceManagementLayer:: CE registration message forwarded to shell.\n"); char buffer[256]; memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); //printf("ServiceManagementLayer::buffer = %s\n", buffer); SendMessage(CE_List[ID].FD, buffer); TransferRadioConfiguration(ID); memset(buffer, 0, 256); //printf("start trans exp\n"); TransferExperience(ID); memset(buffer, 0, 256); numberOfCognitiveEngines++; CE_Present = true; //printf("done registering CE!\n"); } /* CALLED BY: MessageHandler * INPUTS: |ID| The ID number of the engine to have it's services deregistered * OUTPUTS: * * DESCRIPTION: Deletes individual services from the DB * NOTE THAT this function only needs to be called if service deregistration is going * to be done at a different time than component deregistration; it is handled * more efficiently and directly during that deregistration process. */ void ServiceManagementLayer::DeregisterServices(int32_t ID) { char buffer[256]; memset(buffer, 0, 256); ReadMessage(CE_List[ID].FD, buffer); strcpy(_services_DB->command, "DELETE FROM "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, " WHERE ID_Num IN (SELECT"); sprintf(_services_DB->command, " %s %d",_services_DB->command, ID); strcat(_services_DB->command, " FROM "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, " WHERE Service_Name"); strcat(_services_DB->command, "=="); sprintf(_services_DB->command, "%s'%s');", _services_DB->command, buffer); char *errorMsg; int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); } /* CALLED BY: MessageHandler * INPUTS: |ID| The ID number of the engine to have it's services deregistered * OUTPUTS: * * DESCRIPTION: Deletes the contact info for the cognitive engine, forwards a deregistration message to the shell * Also, deletes the services from the DB */ void ServiceManagementLayer::DeregisterCognitiveEngine(int32_t ID) { LOG("ServiceManagementLayer:: CE deregistration message forwarded to shell.\n"); numberOfCognitiveEngines--; if(numberOfCognitiveEngines == 0) CE_Present = false; SendMessage(shellSocketFD, "deregister_engine_cognitive"); char buffer[256]; memset(buffer, 0, 256); ReadMessage(shellSocketFD, buffer); SendMessage(CE_List[ID].FD, buffer); if(strcmp("deregister_ack", buffer) != 0) { ERROR(1, "SML:: Failed to close CE socket\n"); } //Deregister the services strcpy(_services_DB->command, "DELETE FROM "); strcat(_services_DB->command, _services_DB->tablename); strcat(_services_DB->command, " WHERE "); strcat(_services_DB->command, "ID_Num"); strcat(_services_DB->command, "=="); sprintf(_services_DB->command, "%s%d;", _services_DB->command, ID); char *errorMsg; int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg); if( rc!=SQLITE_OK && rc!=101 ) fprintf(stderr, "SQL error: %s\n", errorMsg); CE_List[ID].FD = -1; CE_List[ID].ID_num = -1; LOG("Cognitive Radio Shell:: CE Socket closed for engine #%d.\n", ID); } /* CALLED BY: test class * INPUTS: * OUTPUTS: * * DESCRIPTION: Sets up a server socket and listens for communication on either that or the shell socket */ void ServiceManagementLayer::StartSMLServer() { //printf("Ready for CE Signal! (registration done)\n"); struct timeval selTimeout; int32_t running = 1; int32_t port, rc, new_sd = 1; int32_t desc_ready = 1; //If there is, call the MessageHandler with the Shell_Msg code of -1 fd_set sockSet, shellSet; cogEngSrv = CreateTCPServerSocket(SMLport); int32_t maxDescriptor = cogEngSrv; if(InitializeTCPServerPort(cogEngSrv) == -1) ERROR(1,"Error initializing primary port\n"); int i = 10000000; //TODO change to "running" if endpoint can be reached while (running) { i--; /* Zero socket descriptor vector and set for server sockets */ /* This must be reset every time select() is called */ FD_ZERO(&sockSet); FD_SET(cogEngSrv, &sockSet); for(uint16_t k = 0; k < Current_ID; k++){ if(CE_List[k].ID_num != -1) FD_SET(CE_List[k].FD, &sockSet); } //printf("k=%d, CID=%d\n", k, CE_List[k].FD); /* Timeout specification */ /* This must be reset every time select() is called */ selTimeout.tv_sec = 0; /* timeout (secs.) */ selTimeout.tv_usec = 0; /* 0 microseconds */ //Changed both to zero so that select will check messages from the shell instead of blocking //when there is no command from the CE's to be processed //Check if there is a message on the socket waiting to be read rc = select(maxDescriptor + 1, &sockSet, NULL, NULL, &selTimeout); //printf("rc=%d\n", rc); if(rc == 0){ //LOG("No echo requests for %i secs...Server still alive\n", timeout); FD_ZERO(&shellSet); FD_SET(shellSocketFD, &shellSet); selTimeout.tv_sec = 0; selTimeout.tv_usec = 0; //Check if there is a message on the shell socket ready to be processed select(shellSocketFD + 1, &shellSet, NULL, NULL, &selTimeout); //printf("rc2=%d\n", rc2); //If there is, call the MessageHandler with the Shell_Msg code of -1 if(FD_ISSET(shellSocketFD, &shellSet)){ //printf("shell_msg, %d\n", rc2); MessageHandler(-1);} } else { desc_ready = rc; for(port = 0; port <= maxDescriptor && desc_ready > 0; port++) { if(FD_ISSET(port, &sockSet)) { desc_ready -= 1; //Check if request is new or on an existing open descriptor if(port == cogEngSrv) { //If new, assign it a descriptor and give it an ID new_sd = AcceptTCPConnection(port); if(new_sd < 0) break; CE_List[Current_ID].FD = new_sd; CE_List[Current_ID].ID_num = Current_ID; MessageHandler(Current_ID); Current_ID++; FD_SET(new_sd,&sockSet); if(new_sd > maxDescriptor) maxDescriptor = new_sd; } else { //If old, figure out which ID it coresponds to and handle it accordingly for(uint16_t z = 0; z < Current_ID; z++) { if(CE_List[z].FD == port){ MessageHandler(z);} } } } } } } /* Close sockets */ close(cogEngSrv); //delete &cogEngSrv; return; }