root/vtcross/trunk/src/service_management_layer/ServiceManagementLayer.cpp @ 289

Revision 289, 59.9 KB (checked in by wrodgers, 15 years ago)

SML can now handle non-nested if statements in the format described by the XML. Nested conditionals and whiles soon to come

Line 
1/* Virginia Tech Cognitive Radio Open Source Systems
2 * Virginia Tech, 2009
3 *
4 * LICENSE INFORMATION GOES HERE
5 */
6
7/* Inter-component communication handled by sockets and FD's. 
8 * Server support has been completely implemented and tested.
9 *
10 * Services are stored in a SQLite DB by the ID of the CE that registered them.  Service
11 * support has been completely implemented and tested.
12 *
13 * Missions are loaded from an XML file, connected with services provided by components,
14 * and run.  See the documentation for the "PerformActiveMission" below for important
15 * info. 
16 */
17
18//TODO Add nested conditional support
19//TODO Verify update functionality
20//TODO Better shutdown
21//TODO Verify Deregister services
22//TODO printf's
23
24#include <stdlib.h>
25#include <string.h>
26#include <stdio.h>
27#include <cstring>
28#include <stdint.h>
29
30#include "vtcross/common.h"
31
32#include "components.h"
33#include "vtcross/containers.h"
34#include "vtcross/debug.h"
35#include "vtcross/error.h"
36#include "vtcross/socketcomm.h"
37#include <cstring>
38#include <stdint.h>
39#include <math.h>
40
41#include <arpa/inet.h>
42#include <iostream>
43#include <netinet/in.h>
44#include <netdb.h>
45#include <fcntl.h>
46#include <sys/ioctl.h>
47#include <sys/mman.h>
48#include <sys/socket.h>
49#include <sys/types.h>
50#include <sys/wait.h>
51
52#include "tinyxml/tinyxml.h"
53#include "tinyxml/tinystr.h"
54
55#include "sqlite3.h"
56
57typedef struct services_s *services_DB;
58typedef struct data_s *data_DB;
59
60using namespace std;
61
62struct services_s {
63    char filename[64];
64    char tablename[64];
65    char command[2048];
66    sqlite3 *db;
67    unsigned int num_columns;
68};
69
70struct data_s {
71    char filename[64];
72    char tablename[64];
73    char command[2048];
74    sqlite3 *db;
75    unsigned int num_columns;
76};
77
78services_DB _services_DB;
79data_DB _data_DB;
80const char *_SML_Config;
81
82//Callback function used internally by some of the SQLite3 commands
83int callback(void *notUsed, int argc, char **argv, char **azColName){
84    int i;
85    for(i=0; i<argc; i++){
86        printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
87    }
88    printf("\n");
89    return 0;
90}
91
92
93
94ServiceManagementLayer::ServiceManagementLayer()
95{
96    LOG("Creating Service Management Layer.\n");
97    shellSocketFD = -1;
98    numberOfCognitiveEngines = 0;
99    CE_Present = false;
100    cogEngSrv = 1;
101}
102
103//Free and clear the DB's associated with this SML in the destructor
104//Note that exiting with an error condition will cause SML to not be destructed,
105// resulting in the DB's staying in memory until the destructor is encountered in future executions
106ServiceManagementLayer::~ServiceManagementLayer()
107{
108    char *errorMsg;
109    strcpy(_services_DB->command, "drop table ");
110    strcat(_services_DB->command, _services_DB->tablename);
111    int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
112    if( rc!=SQLITE_OK && rc!=101 )
113        fprintf(stderr, "ServiceManagementLayer::Destructor services 'drop table' error: %s\n", errorMsg);
114    strcpy(_services_DB->command, "vacuum");
115    rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
116    if( rc!=SQLITE_OK && rc!=101 )
117        fprintf(stderr, "ServiceManagementLayer::Destructor services 'vacuum' error: %s\n", errorMsg);
118    free(_services_DB);
119
120    strcpy(_data_DB->command, "drop table ");
121    strcat(_data_DB->command, _data_DB->tablename);
122    rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
123    if( rc!=SQLITE_OK && rc!=101 )
124        fprintf(stderr, "ServiceManagementLayer::Destructor data 'drop table' error: %s\n", errorMsg);
125    strcpy(_data_DB->command, "vacuum");
126    rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
127    if( rc!=SQLITE_OK && rc!=101 )
128        fprintf(stderr, "ServiceManagementLayer::Destructor data 'vacuum' error: %s\n", errorMsg);
129    free(_data_DB);
130}
131
132//Note that sizes of CE_List, miss, and service are hardcoded for now.
133//Also, their sizes are hardcoded into the code in various places; a fix for a future version.
134ServiceManagementLayer::ServiceManagementLayer(const char* SML_Config, \
135        const char* serverName, const char* serverPort, int16_t clientPort)
136{
137    LOG("Creating Service Management Layer.\n");
138    _SML_Config = SML_Config;
139    SMLport = clientPort;
140
141    ConnectToShell(serverName, serverPort);
142    CE_List = (CE_Reg *) malloc(10*sizeof(struct CE_Reg));
143    CE_List = new CE_Reg[10];
144
145    miss = new Mission[10];
146    for(int i = 0; i < 10; i++)
147        miss[i].services = new Service[20];
148
149    Current_ID = 0;
150
151    LoadConfiguration(SML_Config, miss);
152    CreateServicesDB();
153    CreateDataDB();
154}
155
156/* CALLED BY: constructor
157 * INPUTS: <none>
158 * OUTPUTS: <none>
159 *
160 * DESCRIPTION: Create and initialize a DB to hold the services registered by components
161 */
162void
163ServiceManagementLayer::CreateServicesDB()
164{
165
166
167  sqlite3_stmt *ppStmt;  /* OUT: Statement handle */
168  const char *pzTail;     /* OUT: Pointer to unused portion of zSql */
169
170
171    _services_DB = (services_DB) malloc(sizeof(struct services_s));
172   // char *errorMsg;
173
174    // create database
175
176    // copy filename
177    strcpy(_services_DB->filename, "Services_Table");
178
179    // execute create database command
180    // database handle
181    //_services_DB->db = NULL;
182    sqlite3_open(_services_DB->filename, &(_services_DB->db));
183    char* cols[] = {(char *)"ID_Num", (char *)"Service_Name"};
184
185    // create table
186
187    // copy tablename
188    strcpy(_services_DB->tablename, "Services");
189    sprintf(_services_DB->command, "DROP TABLE IF EXISTS Services;");     
190
191    int rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, 128, &ppStmt, &pzTail);
192    if( rc!=SQLITE_OK && rc!=101 )
193        printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc);
194    rc = sqlite3_step(ppStmt);
195    if( rc!=SQLITE_OK && rc!=101 )
196        printf("ServiceManagementLayer::CreateServicesDB 'step' error\n");
197
198    // number of columns in the table
199    _services_DB->num_columns = 2;
200
201    // generate command
202    strcpy(_services_DB->command, "CREATE TABLE ");
203    strcat(_services_DB->command, _services_DB->tablename);
204    strcat(_services_DB->command, "(");
205    strcat(_services_DB->command, cols[0]);
206    strcat(_services_DB->command, " INT, ");
207    strcat(_services_DB->command, cols[1]);
208    strcat(_services_DB->command, " TEXT");
209    strcat(_services_DB->command, ");");
210
211    // execute create table command
212
213    rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, 128, &ppStmt, &pzTail);
214    if( rc!=SQLITE_OK && rc!=101 )
215        printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc);
216    rc = sqlite3_step(ppStmt);
217    if( rc!=SQLITE_OK && rc!=101 )
218        printf("ServiceManagementLayer::CreateServicesDB 'step' error\n");
219}
220
221/* CALLED BY: constructor
222 * INPUTS: <none>
223 * OUTPUTS: <none>
224 *
225 * DESCRIPTION: Create and initialize a DB to hold the data sent by components
226 */
227void
228ServiceManagementLayer::CreateDataDB()
229{
230    _data_DB = (data_DB) malloc(sizeof(struct data_s));
231    //char *errorMsg;
232  sqlite3_stmt *ppStmt;  /* OUT: Statement handle */
233  const char *pzTail;     /* OUT: Pointer to unused portion of zSql */
234
235    // create database
236
237    // copy filename
238    strcpy(_data_DB->filename, "Data_Table");
239    // execute create database command
240    // database handle
241    //_services_DB->db = NULL;
242    sqlite3_open(_data_DB->filename, &(_data_DB->db));
243    char* cols[] = {(char *)"Tag", (char *)"Data"};
244
245    // create table
246
247    // copy tablename
248    strcpy(_data_DB->tablename, "Data");
249    sprintf(_data_DB->command, "DROP TABLE IF EXISTS Data;");     
250
251    int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, 128, &ppStmt, &pzTail);
252    if( rc!=SQLITE_OK && rc!=101 )
253        printf("ServiceManagementLayer::CreateServicesDB 'prepare_stmt' error %d\n", rc);
254    rc = sqlite3_step(ppStmt);
255    if( rc!=SQLITE_OK && rc!=101 )
256        printf("ServiceManagementLayer::CreateServicesDB 'step' error\n");
257
258
259    // number of columns in the table
260    _data_DB->num_columns = 2;
261
262    // generate command
263    strcpy(_data_DB->command, "CREATE TABLE ");
264    strcat(_data_DB->command, _data_DB->tablename);
265    strcat(_data_DB->command, "(");
266    strcat(_data_DB->command, cols[0]);
267    //First column is the name of the data (coresponding to the name of the output/input pair)
268    //It is the primary key so any subsequent data with the same name will replace the row
269    strcat(_data_DB->command, " TEXT PRIMARY KEY ON CONFLICT REPLACE, ");
270    strcat(_data_DB->command, cols[1]);
271    strcat(_data_DB->command, " TEXT");
272    strcat(_data_DB->command, ");");
273
274    // execute create table command
275
276    rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, 128, &ppStmt, &pzTail);
277    if( rc!=SQLITE_OK && rc!=101 )
278        printf("ServiceManagementLayer::CreateDataDB 'prepare_stmt' error %d\n", rc);
279    rc = sqlite3_step(ppStmt);
280    if( rc!=SQLITE_OK && rc!=101 )
281        printf("ServiceManagementLayer::CreateDataDB 'step' error\n");
282}
283
284/* CALLED BY: MessageHandler
285 * INPUTS: <none>
286 * OUTPUTS: <none>
287 *
288 * DESCRIPTION: Sends a message identifying this component as an SML to the Shell
289 */
290void
291ServiceManagementLayer::SendComponentType()
292{
293    SendMessage(shellSocketFD, "response_sml");
294    LOG("SML responded to GetRemoteComponentType query.\n");
295}
296
297/* CALLED BY: constructor
298 * INPUTS: |serverName| the IPv4 name of the server (127.0.0.1 for localhost)
299 *         |serverPort| the port on the server to connect to
300 * OUTPUTS: <none>
301 *
302 * DESCRIPTION: Connecting to the shell takes 2 steps
303 * 1) Establish a client socket for communication
304 * 2) Run the initial Registration/handshake routine
305 */
306void
307ServiceManagementLayer::ConnectToShell(const char* serverName, \
308        const char* serverPort)
309{
310    shellSocketFD = ClientSocket(serverName, serverPort);
311    RegisterComponent();
312}
313
314/* CALLED BY: StartSMLServer
315 * INPUTS: |ID| The ID number of the CE that has a message wating
316 * OUTPUTS: <none>
317 *
318 * DESCRIPTION: Called whenever a socket is identified as being ready for communication
319 *              This funciton reads the message and calls the appropriate helper
320 */
321void
322ServiceManagementLayer::MessageHandler(int32_t ID)
323{
324    char buffer[256];   
325    memset(buffer, 0, 256); 
326    int32_t _FD; 
327   
328    if(ID != -1)
329        _FD = CE_List[ID].FD;
330    else
331        _FD = shellSocketFD;
332    ReadMessage(_FD, buffer);
333    //printf("MH_buffer = %s\n", buffer);
334   
335    //--------Policy Engine Stuff - no policy engine support in this version-------//
336
337    //printf("********* %s **********\n", buffer);
338    // TODO
339    // If we send integer op codes rather than strings, this process will be
340    // MUCH faster since instead of donig string compares we can simply
341    // switch on the integer value...
342    /*if(strcmp(buffer, "register_service") == 0) {
343        if(strcmp(buffer, "policy_geo") == 0) {
344        }
345        else if(strcmp(buffer, "policy_time") == 0) {
346        }
347        else if(strcmp(buffer, "policy_spectrum") == 0) {
348        }
349        else if(strcmp(buffer, "policy_spacial") == 0) {
350        }
351    }
352    else if(strcmp(buffer, "deregister_service") == 0) {
353        if(strcmp(buffer, "policy_geo") == 0) {
354        }
355        else if(strcmp(buffer, "policy_time") == 0) {
356        }
357        else if(strcmp(buffer, "policy_spectrum") == 0) {
358        }
359        else if(strcmp(buffer, "policy_spacial") == 0) {
360        }
361    }*/
362
363    //Go down the list to call the appropriate function
364    if(strcmp(buffer, "query_component_type") == 0) {
365        SendComponentType();
366    }
367    else if(strcmp(buffer, "reset_sml") == 0) {
368        Reset();
369    }
370    else if(strcmp(buffer, "shutdown_sml") == 0) {
371        Shutdown();
372    }
373    else if(strcmp(buffer, "register_engine_cognitive") == 0) {
374        RegisterCognitiveEngine(ID);
375    }
376    else if(strcmp(buffer, "register_service") == 0) {
377        ReceiveServices(ID);
378    }
379    else if(strcmp(buffer, "send_component_type") == 0) {
380        SendComponentType();
381    }
382    else if(strcmp(buffer, "list_services") == 0) {
383        ListServices();
384    }
385    else if(strcmp(buffer, "set_active_mission") == 0) {
386        SetActiveMission();
387    }
388    else if(strcmp(buffer, "request_optimization") == 0) {
389        PerformActiveMission();
390    }
391    else if(strcmp(buffer, "deregister_engine_cognitive") == 0) {
392        DeregisterCognitiveEngine(ID);
393    }
394    else if(strcmp(buffer, "deregister_service") == 0) {
395        DeregisterServices(ID);
396    }
397}
398
399//TODO Finish
400/* CALLED BY: MessageHandler
401 * INPUTS: <none>
402 * OUTPUTS: <none>
403 *
404 * DESCRIPTION: Deregisters the component from the Shell.
405 */
406void
407ServiceManagementLayer::Shutdown()
408{
409    DeregisterComponent();
410}
411
412//TODO Finish
413/* CALLED BY: MessageHandler
414 * INPUTS: <none>
415 * OUTPUTS: <none>
416 *
417 * DESCRIPTION: Deregisters the component from the Shell
418 */
419void
420ServiceManagementLayer::Reset()
421{
422    DeregisterComponent();
423    ReloadConfiguration();
424}
425
426/* CALLED BY: ConnectToShell
427 * INPUTS: <none>
428 * OUTPUTS: <none>
429 *
430 * DESCRIPTION: Sends the registration message to the Shell
431 */
432void
433ServiceManagementLayer::RegisterComponent()
434{
435    SendMessage(shellSocketFD, "register_sml");
436    LOG("ServiceManagementLayer:: Registration message sent.\n");
437    //printf("SSFD = %d\n", shellSocketFD);
438}
439
440/* CALLED BY: Shutdown
441 * INPUTS: <none>
442 * OUTPUTS: <none>
443 *
444 * DESCRIPTION: Closes the client socket with the shell, sends a deregstration message
445 */
446void
447ServiceManagementLayer::DeregisterComponent()
448{
449    SendMessage(shellSocketFD, "deregister_sml");
450    LOG("ServiceManagementLayer:: Deregistration message sent.\n");
451
452    shutdown(shellSocketFD, 2);
453    close(shellSocketFD);
454    shellSocketFD = -1;
455    LOG("ServiceManagementLayer:: Shell socket closed.\n");
456}
457
458
459/* CALLED BY: RegisterCognitiveEngine
460 * INPUTS: |ID| The ID number of the component where the data is to be transfered to
461 * OUTPUTS: <none>
462 *
463 * DESCRIPTION: Streams config data directly from the shell to the CE, and checks
464 * for an "ack" message from the CE after every sent message
465 * to know when to stop communication.
466 */
467
468//Modified to check the incoming message buffer rather than the outgoing message buffer to avoid a portion of the delay
469void
470ServiceManagementLayer::TransferRadioConfiguration(int32_t ID)
471{
472    //printf("transRadConfig\n");
473    struct timeval selTimeout;
474    fd_set sockSet;
475    int32_t rc = 1;
476    char buffer[256];
477    //Send data until the CE sends an ACK message back
478    while(rc!=0){
479        memset(buffer, 0, 256);
480        //Receive data from Shell
481        ReadMessage(shellSocketFD, buffer);
482        //printf("buffer = %s\n", buffer);
483        //Send data to CE
484        SendMessage(CE_List[ID].FD, buffer);
485        FD_ZERO(&sockSet);
486        FD_SET(shellSocketFD, &sockSet);
487        selTimeout.tv_sec = 0;
488        selTimeout.tv_usec = 50000;
489        //Check if there is a message on the shell ready to be processed
490        rc=select(shellSocketFD + 1, &sockSet, NULL, NULL, &selTimeout);
491    }
492    memset(buffer, 0, 256);
493    ReadMessage(CE_List[ID].FD, buffer);
494    SendMessage(shellSocketFD, buffer);
495    //printf("transfer done!\n");
496}
497
498
499/* CALLED BY: RegisterCognitiveEngine
500 * INPUTS: |ID| The ID number of the component where the data is to be transfered to
501 * OUTPUTS: <none>
502 *
503 * DESCRIPTION: Simmilar to TransferRadioConfig, just with Experience data
504 */
505
506//Modified to check the incoming message buffer rather than the outgoing message buffer to avoid a portion of the delay
507void
508ServiceManagementLayer::TransferExperience(int32_t ID)
509{
510    struct timeval selTimeout;
511    fd_set sockSet;
512    int32_t rc = 1;
513    char buffer[256];
514    //Send data until the CE sends an ACK message back
515    while(rc!=0){
516        //printf("transfering...\n");
517        memset(buffer, 0, 256);
518        //Receive data from Shell
519        ReadMessage(shellSocketFD, buffer);
520        //printf("buffer = %s\n", buffer);
521        //Send data to CE
522        SendMessage(CE_List[ID].FD, buffer);
523        FD_ZERO(&sockSet);
524        FD_SET(shellSocketFD, &sockSet);
525        selTimeout.tv_sec = 0;
526        selTimeout.tv_usec = 50000;
527        //Check if there is a message on the shell ready to be processed
528        rc=select(shellSocketFD + 1, &sockSet, NULL, NULL, &selTimeout);
529    }
530    memset(buffer, 0, 256);
531    //printf("done trans exp!\n");
532    ReadMessage(CE_List[ID].FD, buffer);
533    SendMessage(shellSocketFD, buffer);
534}
535
536/* CALLED BY: MessageHandler
537 * INPUTS: |ID| The ID number of the component where service is located
538 * OUTPUTS: <none>
539 *
540 * DESCRIPTION: Inserts a service into the DB with the ID of the component where it exists
541 */
542void
543ServiceManagementLayer::ReceiveServices(int32_t ID)
544{
545    char buffer[256];
546    memset(buffer, 0, 256);
547    ReadMessage(CE_List[ID].FD, buffer);
548    char* cols[] = {(char *)"ID_Num", (char *)"Service_Name"};
549    //printf("RS_buffer = %s\n", buffer);
550    // generate command
551    strcpy(_services_DB->command, "insert into ");
552    strcat(_services_DB->command, _services_DB->tablename);
553    strcat(_services_DB->command, " (");
554    strcat(_services_DB->command, cols[0]);
555    strcat(_services_DB->command, ", ");
556    strcat(_services_DB->command, cols[1]);
557    strcat(_services_DB->command, ") ");
558    strcat(_services_DB->command, " values(");
559    sprintf(_services_DB->command, "%s%d", _services_DB->command, ID);
560    strcat(_services_DB->command, ", '");
561    strcat(_services_DB->command, buffer);
562    strcat(_services_DB->command, "');");
563   
564    //printf("search command: %s\n", _services_DB->command);
565    // execute add command
566    char *errorMsg;
567    int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
568    if( rc!=SQLITE_OK && rc!=101 )
569        fprintf(stderr, "ServiceManagementLayer::RecieveServices DB Error %s\n", errorMsg);
570    /*sprintf(outBuffer, "SML: Registering service '%s' from component number '%d'", buffer, ID);
571    LOG(outBuffer);*/
572}
573
574/* CALLED BY: MessageHandler
575 * INPUTS: <none>
576 * OUTPUTS: <none>
577 *
578 * DESCRIPTION: This method associates the services that components provide with the services that are requested in the mission
579 * Each service in the mission is given the ID and FD of a component that has registered to provide that service
580 * Deregistration is okay until this method is called without a reload, but if deregistration occurs after this
581 * method is called it needs to be called again even if other engines also provide the services
582 */
583void
584ServiceManagementLayer::SetActiveMission()
585{
586    char buffer[256];
587    memset(buffer, 0, 256);
588    ReadMessage(shellSocketFD, buffer);
589    uint32_t missID = atoi(buffer);
590    for(activeMission = 0; activeMission < 10; activeMission++)
591    {
592        //Find the active mission by comparing mission ID's
593        if(miss[activeMission].missionID == missID)
594            break;
595    }
596
597    LOG("ServiceManagementLayer:: Received Set Active Mission command: %i.\n",missID);
598    //For each service in the mission
599    for(uint16_t i = 0; i < miss[activeMission].numServices; i++)
600    {   
601        //Check whether the current service is an actual service or a conditional
602        if(miss[activeMission].services[i].name.compare("if") && miss[activeMission].services[i].name.compare("while") && \
603           miss[activeMission].services[i].name.compare("shell")){
604            //If it is a service, search the database of registered services to find the ID of the component that registered it
605            strcpy(_services_DB->command, "select ");
606            strcat(_services_DB->command, _services_DB->tablename);
607            strcat(_services_DB->command, ".* from ");
608            strcat(_services_DB->command, _services_DB->tablename);
609            strcat(_services_DB->command, " where Service_Name==");
610            sprintf(_services_DB->command, "%s'%s';", _services_DB->command, miss[activeMission].services[i].name.c_str());
611       
612            sqlite3_stmt * pStatement;
613            int rc = sqlite3_prepare_v2(_services_DB->db, _services_DB->command, -1, &pStatement, NULL);
614            if (rc == SQLITE_OK){
615                if (sqlite3_step(pStatement) == SQLITE_ROW)
616                     miss[activeMission].services[i].componentID =  sqlite3_column_int(pStatement, 0);
617                else {
618                    printf("services_DB:: Mission requires service %s not provided by any connected component.\n",miss[activeMission].services[i].name.c_str());
619                    rc=31337;
620                }
621             } else {
622                printf("services_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_services_DB->command);
623            }
624                //printf("s_name=%s\n",miss[activeMission].services[i].name.c_str());
625            sqlite3_finalize(pStatement);
626            miss[activeMission].services[i].socketFD = CE_List[miss[activeMission].services[i].componentID].FD;
627            //Set the FD and ID of the service to refer to the component where the service exists
628        }
629        //Nothing to be done for conditionals at this stage
630    }
631 
632    SendMessage(shellSocketFD, "ack");
633    LOG("ServiceManagementLayer:: Done setting active mission.\n");
634    //printf("\nhere ---%d, %d---\n", miss[activeMission].services[0].componentID, miss[activeMission].services[1].componentID);
635}
636
637/* CALLED BY: PerformActiveMission
638 * INPUTS: |sourceID| ID of the service that is being processed
639 * OUTPUTS: <none>
640 *
641 * DESCRIPTION: This is a helper method for the "PerformActiveMission" function
642 * NOTE: This function has changed durrastically from the previous implementation
643 * Takes an ID of a service
644 * For that service, finds inputs in DB and forwords those on to the engine after sending comm-starting messages
645 * Afterwords, listenes for the outputs so that it can store those in the database for future services or the overall output
646 */
647void
648ServiceManagementLayer::TransactData(int32_t sourceID)
649{
650    LOG("ServiceManagementLayer:: Data transaction occuring.\n");
651    char buffer[256];
652    std::string data;
653    char* cols[] = {(char *)"Tag", (char *)"Data"};
654    int i = 0;
655    fd_set sockSet;
656    char *token;
657    struct timeval selTimeout;
658
659   //Send a message directly to the shell
660   //printf("name = %s\n", miss[activeMission].services[sourceID].name.c_str());
661   if(miss[activeMission].services[sourceID].name.find("shell")!=string::npos)
662   {
663        //printf("caught shell\n");
664        //If the name on the output doesn't start with "~", search the DB to find the output that should be returned
665        if(miss[activeMission].services[sourceID].output[0].find("~") == string::npos){
666           // printf("taken1\n");
667            memset(buffer, 0 , 256);
668            strcpy(_data_DB->command, "select ");
669            strcat(_data_DB->command, _data_DB->tablename);
670            strcat(_data_DB->command, ".* from ");
671            strcat(_data_DB->command, _data_DB->tablename);
672            strcat(_data_DB->command, " where Tag==");
673            sprintf(_data_DB->command, "%s'%s';", _data_DB->command, miss[activeMission].services[sourceID].output[0].c_str());
674            sqlite3_stmt * pStatement;
675            int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL);
676            if (rc == SQLITE_OK){
677                if (sqlite3_step(pStatement) == SQLITE_ROW)
678                    data.append((const char*) sqlite3_column_text(pStatement, 1));
679                else {
680                    //TODO could do shell output here if not in DB
681                    printf("data_DB:: Data not yet in DB.\n");
682                    rc=31337;
683                }
684            }
685            else {
686                printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command);
687            }
688            sqlite3_finalize(pStatement);
689            token = strtok((char *)data.c_str(), "@");
690            SendMessage(shellSocketFD, token);
691            token = strtok(NULL, "@");
692            while(token){
693                SendMessage(shellSocketFD, token);
694                token = strtok(NULL, "@");
695            }
696        }
697        //Otherwise, just return the value specified by output TODO (in 1 - <output name> - <output name> format)
698        else{
699            printf("taken2\n");
700            memset(buffer, 0, 256);
701            SendMessage(shellSocketFD, "1");
702            miss[activeMission].services[sourceID].output[0].erase(0);
703            SendMessage(shellSocketFD, miss[activeMission].services[sourceID].output[0].c_str());
704            SendMessage(shellSocketFD, miss[activeMission].services[sourceID].output[0].c_str());
705        }
706        //printf("done shell\n");
707        return;
708   }
709
710
711
712    //Transmission starting messages
713    SendMessage(miss[activeMission].services[sourceID].socketFD, "request_optimization_service");
714    SendMessage(miss[activeMission].services[sourceID].socketFD, miss[activeMission].services[sourceID].name.c_str());
715    //Find and load the input data
716    while(i < 5 && !miss[activeMission].services[sourceID].input[i].empty()){
717        //printf("pulling input data out of DB for ID#=%d\n", sourceID);
718        strcpy(_data_DB->command, "select ");
719        strcat(_data_DB->command, _data_DB->tablename);
720        strcat(_data_DB->command, ".* from ");
721        strcat(_data_DB->command, _data_DB->tablename);
722        strcat(_data_DB->command, " where Tag==");
723        char temp[100];
724        strcpy(temp, miss[activeMission].services[sourceID].input[i].c_str());
725        char *temp2 = strtok(temp, "+");
726        sprintf(_data_DB->command, "%s'%s';", _data_DB->command, temp2);
727        sqlite3_stmt * pStatement;
728        int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL);
729        if (rc == SQLITE_OK){
730            if (sqlite3_step(pStatement) == SQLITE_ROW)
731                 data.append((const char*) sqlite3_column_text(pStatement, 1));
732            else {
733                    printf("data_DB:: Data not yet in DB.\n");
734                    rc=31337;
735            }
736        }
737        else {
738            printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command);
739        }
740        sqlite3_finalize(pStatement);
741        char *data_ch = (char *) data.c_str();
742        int32_t numStatements = 0;
743        temp2 = strtok(NULL, "+");
744        while(temp2){
745            numStatements++;
746            temp2 = strtok(NULL, "+");
747        }
748        //printf("here1%d\n", numStatements);
749        char temp4[10];
750        memset(temp4, 0, 10);
751        sprintf(temp4, "%d", numStatements);
752        //Tokenize the data and pass it along
753        //printf("here2 %s\n", temp4);
754        if(strstr(miss[activeMission].services[sourceID].input[i].c_str(), "+")){
755            SendMessage(miss[activeMission].services[sourceID].socketFD, temp4);
756            token = strtok(data_ch, "@");
757        }
758        else{
759            token = strtok(data_ch, "@");
760            SendMessage(miss[activeMission].services[sourceID].socketFD, token);
761        }
762        token = strtok(NULL, "@");
763
764
765        //Either have to send whole block of memory or just one piece
766        while(token){
767            if(strstr(miss[activeMission].services[sourceID].input[i].c_str(), token))
768            {
769                //printf("1tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token);
770                SendMessage(miss[activeMission].services[sourceID].socketFD, token);
771                token = strtok(NULL, "@");
772                SendMessage(miss[activeMission].services[sourceID].socketFD, token);
773            }
774            else if(!strstr(miss[activeMission].services[sourceID].input[i].c_str(), "+"))
775            {
776                //printf("t not detected tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token);
777                SendMessage(miss[activeMission].services[sourceID].socketFD, token);
778                token = strtok(NULL, "@");
779                SendMessage(miss[activeMission].services[sourceID].socketFD, token);
780            }
781            else{
782                //printf("3tokenizing %s %s!\n", miss[activeMission].services[sourceID].input[i].c_str(), token);
783                token = strtok(NULL, "@");}
784            token = strtok(NULL, "@");
785        }
786        //printf("done\n");
787        //printf("done pulling input data out of DB for ID#=%d\n", sourceID);
788        i++;
789        data.clear();
790    }
791    int32_t j = 0;
792    FD_ZERO(&sockSet);
793    FD_SET(miss[activeMission].services[sourceID].socketFD, &sockSet);
794    //TODO neccessary?
795    selTimeout.tv_sec = 5;
796    selTimeout.tv_usec = 0;
797    //Use select command to force wait for processing to finish
798    select(miss[activeMission].services[sourceID].socketFD + 1, &sockSet, NULL, NULL, &selTimeout);
799        //printf("done\n");
800   //TODO rewrite part of data on output?
801   //TODO true false format?
802    while(j < 5 && !miss[activeMission].services[sourceID].output[j].empty()){
803        int rc;
804        memset(buffer, 0, 256);
805        ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer);
806       // printf("waiting\n");     
807        data.append(buffer);
808        data.append("@");
809        int t = atoi(buffer);
810        //printf("%d\n", t);
811        for(int k = 0; k < t; k++){
812            //Read the data incrementally and deliminate it with the "@" symbol
813            memset(buffer, 0, 256);
814            ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer);
815            if(!strcmp(buffer, "TF")){
816                ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer);
817                data.append(buffer);
818                data.append("@");
819            }
820            else{
821                data.append(buffer);
822                data.append("@");
823                memset(buffer, 0, 256);
824                ReadMessage(miss[activeMission].services[sourceID].socketFD, buffer);
825                data.append(buffer);
826                data.append("@");
827            }
828        }
829        //printf("SML: putting output data into DB for ID#=%d\n", sourceID);
830
831        strcpy(_data_DB->command, "insert or replace into ");
832        strcat(_data_DB->command, _data_DB->tablename);
833        strcat(_data_DB->command, " (");
834        strcat(_data_DB->command, cols[0]);
835        strcat(_data_DB->command, ", ");
836        strcat(_data_DB->command, cols[1]);
837        strcat(_data_DB->command, ") ");
838        strcat(_data_DB->command, " values('");
839        strcat(_data_DB->command, miss[activeMission].services[sourceID].output[j].c_str());
840        strcat(_data_DB->command, "', '");
841        strcat(_data_DB->command, data.c_str());
842        strcat(_data_DB->command, "');");
843        char *errorMsg;
844        rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
845        if( rc!=SQLITE_OK && rc!=101 )
846            fprintf(stderr, "SQL error: %s\n", errorMsg);
847        //printf("S: done putting ouptut data into DB for ID#='%d', data=%s\n", sourceID, data.c_str());
848        j++;
849        data.clear();
850    }
851    //printf("done transact data!\n");
852    LOG("ServiceManagementLayer:: Finished with data transaction.\n");
853
854
855    /*printf("\n\n\n");
856    // generate commandi
857    strcpy(_data_DB->command, "select ");
858    strcat(_data_DB->command, _data_DB->tablename);
859    strcat(_data_DB->command, ".* from ");
860    strcat(_data_DB->command, _data_DB->tablename);
861    strcat(_data_DB->command, ";");
862
863    // execute print (select all)  command   
864    char *errorMsg;
865    int rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
866    if( rc!=SQLITE_OK && rc!=101 )
867        fprintf(stderr, "SQL error: %s\n", errorMsg);
868    printf("database %s, table %s:\n", _data_DB->filename, _data_DB->tablename);
869    printf("\n\n\n");*/
870}
871
872
873
874/* CALLED BY: MessageHandler
875 * INPUTS: <none>
876 * OUTPUTS: <none>
877 *
878 * DESCRIPTION: This function works by first sending the inputs from the shell to the appropriate components
879 * The first service should begin immeadiately, as should any others who have all of their input paramaters
880 * When they complete, the output path is found and the data is transfered as it becomes available
881 * Presumably at this point the second function has all of it's paramaters, so it begins to compute, and the cycle repeats
882 * If the generated output is an overall output, it is sent on to the shell
883 * "if" and "while" statements are handled by setting up a faux service that has a true input, a false input, and a boolean flag
884 * If the true input is non-NULL and the flag is true, the statements execute
885 * Likewise, if the false input is non-NULL and the flag is false, the statements execute
886 * These flags are set during execution any time one of these faux services' inputs appear in an output statement 
887 * 
888 *
889 * Rules for active missions (currently)
890 * -Three inputs/outputs per service and per mission
891 * -Inputs simply define a path, so multiple variables can be transmitted over the same input
892 * -Each component that sends data must include the "output_finished" statement after each output is finished sending it's data
893 * -All ordering constraints have been relaxed in this version; all data is stored locally and only sent when requested
894 * -If support fully implemented
895 * -Conditions must be boolean flags
896 * -Flags are set by putting either the character string "true" or "false" on the buffer
897 * -IMPORTANT: DB uses '@' to seperate individual statements; using '@' in the data stream will result in incorrect behavior
898 */
899
900//IF-IF-IF
901//IF-IF-WHILE
902//IF-WHILE
903//WHILE
904void
905ServiceManagementLayer::PerformActiveMission()
906{
907    uint16_t i = 0;
908    std::string data_param, data_obsv, data;
909    std::string input;
910    std::string check;
911    char buffer[256];
912    char buffer1[256];
913    char *token;
914    int rc;
915    char *errorMsg;
916    char* cols[] = {(char *)"Tag", (char *)"Data"};
917    //Get the inputs
918    memset(buffer, 0, 256);
919    ReadMessage(shellSocketFD, buffer);
920    LOG("ServiceManagementLayer:: Received PerformActiveMission command.\n");
921
922    int32_t t = atoi(buffer);
923   // printf("****%d****\n", t);
924    for(int32_t m = 0; m < t; m++) {
925        //printf("data=%s\n", data_obsv.c_str());
926        memset(buffer1, 0, 256);
927        ReadMessage(shellSocketFD, buffer1);
928        strcpy(_data_DB->command, "insert into ");
929        strcat(_data_DB->command, _data_DB->tablename);
930        strcat(_data_DB->command, " (");
931        strcat(_data_DB->command, cols[0]);
932        strcat(_data_DB->command, ", ");
933        strcat(_data_DB->command, cols[1]);
934        strcat(_data_DB->command, ") ");
935        memset(buffer, 0, 256);
936        ReadMessage(shellSocketFD, buffer);
937        sprintf(_data_DB->command, "%s values('%s', '1@%s@%s", _data_DB->command, buffer1, buffer1, buffer);
938        strcat(_data_DB->command, "');");
939        rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
940        if( rc!=SQLITE_OK && rc!=101 )
941            fprintf(stderr, "SQL error: %s\n", errorMsg);
942    }
943
944
945    /*printf("\n\n\n");
946    // generate commandi
947    strcpy(_data_DB->command, "select ");
948    strcat(_data_DB->command, _data_DB->tablename);
949    strcat(_data_DB->command, ".* from ");
950    strcat(_data_DB->command, _data_DB->tablename);
951    strcat(_data_DB->command, ";");
952
953    // execute print (select all)  command 
954    rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
955    if( rc!=SQLITE_OK && rc!=101 )
956        fprintf(stderr, "SQL error: %s\n", errorMsg);
957    printf("database %s, table %s:\n", _data_DB->filename, _data_DB->tablename);
958    printf("\n\n\n");*/
959
960    /* Receive Set of Parameters */
961    memset(buffer, 0, 256);
962    ReadMessage(shellSocketFD, buffer);
963    t=atoi(buffer);
964    for(int k = 0; k < t; k++) {
965        //printf("data=%s\n", data_obsv.c_str());
966        memset(buffer1, 0, 256);
967        ReadMessage(shellSocketFD, buffer1);
968        strcpy(_data_DB->command, "insert into ");
969        strcat(_data_DB->command, _data_DB->tablename);
970        strcat(_data_DB->command, " (");
971        strcat(_data_DB->command, cols[0]);
972        strcat(_data_DB->command, ", ");
973        strcat(_data_DB->command, cols[1]);
974        strcat(_data_DB->command, ") ");
975        memset(buffer, 0, 256);
976        ReadMessage(shellSocketFD, buffer);
977        sprintf(_data_DB->command, "%s values('%s', '1@%s@%s", _data_DB->command, buffer1, buffer1, buffer);
978        strcat(_data_DB->command, "');");
979        rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
980        if( rc!=SQLITE_OK && rc!=101 )
981            fprintf(stderr, "SQL error: %s\n", errorMsg);
982    }
983
984
985    /*printf("\n\n\n");
986    // generate commandi
987    strcpy(_data_DB->command, "select ");
988    strcat(_data_DB->command, _data_DB->tablename);
989    strcat(_data_DB->command, ".* from ");
990    strcat(_data_DB->command, _data_DB->tablename);
991    strcat(_data_DB->command, ";");
992
993    // execute print (select all)  command 
994    rc = sqlite3_exec(_data_DB->db, _data_DB->command, callback, 0, &errorMsg);
995    if( rc!=SQLITE_OK && rc!=101 )
996        fprintf(stderr, "SQL error: %s\n", errorMsg);
997    printf("database %s, table %s:\n", _data_DB->filename, _data_DB->tablename);
998    printf("\n\n\n");*/
999
1000
1001
1002
1003   // printf("done\n");
1004    i=0;
1005    int32_t numstatements = 0;
1006    data.clear();
1007    while(i < miss[activeMission].numServices)
1008    {
1009        if(miss[activeMission].services[i].name.compare("if")==0)
1010        {
1011           //printf("L0:if detected\n");
1012            input.clear();
1013            check.clear();
1014            int t;
1015            for(t = 0; t < 5; t++){
1016                if(!miss[activeMission].services[i].output[t].empty()){
1017                    //printf("i-numstmts = %d\n", i-numstatements-1);
1018                    input=miss[activeMission].services[i-numstatements-1].output[t];
1019                    strcpy(_data_DB->command, "SELECT ");
1020                    strcat(_data_DB->command, _data_DB->tablename);
1021                    strcat(_data_DB->command, ".* from ");
1022                    strcat(_data_DB->command, _data_DB->tablename);
1023                    strcat(_data_DB->command, " where Tag==");
1024                    sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str());
1025                    sqlite3_stmt * pStatement;
1026                    rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL);
1027                    if (rc == SQLITE_OK){
1028                        if (sqlite3_step(pStatement) == SQLITE_ROW)
1029                             data = (const char *) sqlite3_column_text(pStatement, 1);
1030                        else {
1031                                printf("1 data_DB:: Data not yet in DB.\n");
1032                                rc=31337;
1033                        }
1034                    } else {
1035                        printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command);
1036                    }
1037                    sqlite3_finalize(pStatement);
1038                    //printf("data=%s\n", data.c_str());
1039                    token = strtok((char *)data.c_str(), "@");
1040                    token = strtok(NULL, "@");
1041                    token = strtok(NULL, "@");
1042                    //printf("data=%s\n", token);
1043                    break;
1044                }
1045            }
1046            //printf("L0:--- %s  %s---\n", miss[activeMission].services[i].output[t].c_str(), token);
1047            if(!miss[activeMission].services[i].output[t].compare(token)){
1048                //printf("L0:if taken\n");
1049                for(uint16_t k = i+1; k <= i+miss[activeMission].services[i].num_conds; k++){
1050                    //printf("transacting data for k=%d\n", k);
1051                    TransactData(k);
1052                }
1053            }
1054            numstatements +=miss[activeMission].services[i].num_conds+1;
1055            i+=miss[activeMission].services[i].num_conds;
1056            //printf("doneif %d, %d, %d\n", numstatements, miss[activeMission].services[i].num_conds, i);
1057        }
1058        else if(miss[activeMission].services[i].name.compare("while")==0)
1059        {
1060            numstatements=0;
1061            //printf("while detected\n");
1062            while(true){
1063                    data.clear();
1064                    printf("L0:if detected\n");
1065                    input.clear();
1066                    check.clear();
1067                    int t;
1068                    for(t = 0; t < 5; t++){
1069                        if(!miss[activeMission].services[i].output[t].empty()){
1070                            input=miss[activeMission].services[i-1].output[t];
1071                            strcpy(_data_DB->command, "SELECT ");
1072                            strcat(_data_DB->command, _data_DB->tablename);
1073                            strcat(_data_DB->command, ".* from ");
1074                            strcat(_data_DB->command, _data_DB->tablename);
1075                            strcat(_data_DB->command, " where Tag==");
1076                            sprintf(_data_DB->command, "%s'%s';", _data_DB->command, input.c_str());
1077                            sqlite3_stmt * pStatement;
1078                            rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL);
1079                            if (rc == SQLITE_OK){
1080                                if (sqlite3_step(pStatement) == SQLITE_ROW)
1081                                     data = (const char *) sqlite3_column_text(pStatement, 1);
1082                                else {
1083                                        printf("1 data_DB:: Data not yet in DB.\n");
1084                                        rc=31337;
1085                                }
1086                            } else {
1087                                printf("data_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command);
1088                            }
1089                            sqlite3_finalize(pStatement);
1090                            //printf("data=%s\n", data.c_str());
1091                            token = strtok((char *)data.c_str(), "@");
1092                            token = strtok(NULL, "@");
1093                            token = strtok(NULL, "@");
1094                            //printf("data=%s\n", token);
1095                            break;
1096                        }
1097                    }
1098                    printf("L0:--- %s  %s---\n", miss[activeMission].services[i].output[t].c_str(), token);
1099                    if(!miss[activeMission].services[i].output[t].compare(token)){
1100                        printf("L0:if taken\n");
1101                        for(uint16_t k = i+i; k <= i+miss[activeMission].services[i].num_conds; k++){
1102                            TransactData(k);
1103                        }
1104                    }
1105                    else
1106                        break;
1107            }
1108            i+=miss[activeMission].services[i].num_conds;
1109            //printf("doneif\n");
1110        }
1111        else{
1112            numstatements=0;
1113            //printf("L0 Neither if nor while\n");
1114            TransactData(i);}
1115        i++;
1116        //printf("i=%d\n", i);
1117    }
1118    i=0;
1119    data.clear();
1120    //get the ouptuts
1121    while(i < 5 && !miss[activeMission].output[i].empty()){
1122        //printf("sending output data to shell\n");
1123        strcpy(_data_DB->command, "select ");
1124        strcat(_data_DB->command, _data_DB->tablename);
1125        strcat(_data_DB->command, ".* from ");
1126        strcat(_data_DB->command, _data_DB->tablename);
1127        strcat(_data_DB->command, " where Tag==");
1128        sprintf(_data_DB->command, "%s'%s';", _data_DB->command, miss[activeMission].output[i].c_str());
1129        sqlite3_stmt * pStatement;
1130        int rc = sqlite3_prepare_v2(_data_DB->db, _data_DB->command, -1, &pStatement, NULL);
1131        if (rc == SQLITE_OK){
1132            if (sqlite3_step(pStatement) == SQLITE_ROW)
1133                 data.append((const char*) sqlite3_column_text(pStatement, 1));
1134            else {
1135                    printf("data_DB:: Data not yet in DB.\n");
1136                    rc=31337;
1137            }
1138        }
1139        else {
1140            printf("services_DB:: Error executing SQL statement. rc = %i\n%s\n",rc,_data_DB->command);
1141        }
1142        //printf("here %s\n", data.c_str());
1143        sqlite3_finalize(pStatement);
1144        char *data_ch = (char *) data.c_str();
1145        char *token = strtok(data_ch, "@");
1146        SendMessage(shellSocketFD, token);
1147        token = strtok(NULL, "@");
1148        while(token){
1149            SendMessage(shellSocketFD, token);
1150            //printf("token1 = %s\n", token);
1151            token = strtok(NULL, "@");
1152            SendMessage(shellSocketFD, token);
1153            //printf("token2 = %s\n", token);
1154            token = strtok(NULL, "@");
1155        }
1156        i++;
1157        data.clear();
1158    }
1159    LOG("ServiceManagementLayer:: Done sending output data to shell from PerformActiveMission.\n");
1160}
1161
1162
1163/* CALLED BY: MessageHandler
1164 * INPUTS: <none>
1165 * OUTPUTS: <none>
1166 *
1167 * DESCRIPTION: Print a list of the services currently registered and the ID's of the components that registered them
1168 */
1169void
1170ServiceManagementLayer::ListServices()
1171{
1172    // generate commandi
1173    strcpy(_services_DB->command, "select ");
1174    strcat(_services_DB->command, _services_DB->tablename);
1175    strcat(_services_DB->command, ".* from ");
1176    strcat(_services_DB->command, _services_DB->tablename);
1177    strcat(_services_DB->command, ";");
1178
1179    // execute print (select all)  command   
1180    char *errorMsg;
1181    int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
1182    if( rc!=SQLITE_OK && rc!=101 )
1183        fprintf(stderr, "SQL error: %s\n", errorMsg);
1184    printf("database %s, table %s:\n", _services_DB->filename, _services_DB->tablename);
1185}
1186
1187/* CALLED BY: Reset
1188 * INPUTS: <none>
1189 * OUTPUTS: <none>
1190 *
1191 * DESCRIPTION: Clear and reinitialize the mission array, then reload the configuration file
1192 */
1193void
1194ServiceManagementLayer::ReloadConfiguration()
1195{
1196    LOG("ServiceManagementLayer:: Reloading Configuration.\n");
1197    free(miss);
1198    miss = new Mission[10];
1199    for(int i = 0; i < 10; i++)
1200        miss[i].services = new Service[20];
1201    LoadConfiguration(_SML_Config, miss);
1202}
1203
1204/* CALLED BY: constructor
1205 * INPUTS: |SML_Config| Address (either relitive or full) of the XML file containing mission data
1206 *         |mList| Mission array to be modified
1207 * OUTPUTS: <none>
1208 *
1209 * DESCRIPTION: IMPORTANT - See formatting instructions for correct parsing of data
1210 * Can currently handle 3 inputs and 3 outputs per service, but easily expandable
1211 * Also, can handle one layer of nested conditional statements, but could
1212 * be expanded to meet additional needs.  Only support now is for straight bool flags,
1213 * but support could be added for more complex conditionals later.
1214 *
1215 * Components assigned to mission during "set active mission" stage so that
1216 * components can still continue to register after the configuration is loaded
1217 */
1218void
1219ServiceManagementLayer::LoadConfiguration(const char *SML_Config, Mission* &mList)
1220{
1221    TiXmlElement *pMission;
1222    TiXmlElement *pService;
1223    TiXmlElement *pChild0, *pChild1, *pChild2, *pChild3, *pChild4;
1224    TiXmlHandle hRoot(0);
1225    //printf("ServiceManagementLayer:: Loading Configuration.\n");
1226    TiXmlDocument doc(".");
1227    doc.LoadFile(SML_Config);
1228    bool loadOkay = doc.LoadFile();
1229    if(!loadOkay)
1230        printf("Loading SML configuration failed: %s\n", SML_Config);
1231
1232    TiXmlHandle hDoc(&doc);
1233   
1234    pMission = hDoc.FirstChildElement().Element();
1235
1236    if(!pMission)
1237        printf("No valid root!");
1238
1239    hRoot = TiXmlHandle(pMission);
1240    pService = pMission->FirstChildElement();
1241    int32_t mission_num = 0;
1242    //Iterate through the missions
1243    for(pChild0 = pMission->FirstChildElement(); pChild0 ; \
1244        pChild0 = pChild0->NextSiblingElement())
1245    {
1246        int32_t service_num = 0;
1247        uint16_t cond_array[] = {0, 0, 0};
1248        //printf("mission_num = %d\n", mission_num);
1249        //memset(cond_array, 0, 2);
1250       
1251        for(pChild1  = pChild0->FirstChildElement(); pChild1; \
1252            pChild1  = pChild1->NextSiblingElement())
1253        {
1254            int32_t conditional_0 = service_num;
1255            for(pChild2 = pChild1->FirstChildElement(); \
1256                pChild2; pChild2 = pChild2->NextSiblingElement())
1257            {
1258                service_num++;
1259                int32_t conditional_1 = service_num;
1260                for(pChild3 = pChild2->FirstChildElement(); \
1261                    pChild3; pChild3 = pChild3 ->NextSiblingElement())
1262                {
1263                    service_num++;
1264                    int32_t conditional_2 = service_num;
1265                        for(pChild4 = pChild3->FirstChildElement(); \
1266                            pChild4; pChild4 = pChild4 ->NextSiblingElement())
1267                        {
1268                            service_num++;
1269                            mList[mission_num].services[service_num].name = pChild4->Attribute("name");
1270                            if(pChild4->Attribute("input1"))
1271                                mList[mission_num].services[service_num].input[0] = pChild4->Attribute("input1");
1272                            if(pChild4->Attribute("input2"))
1273                                mList[mission_num].services[service_num].input[1] = pChild4->Attribute("input2");
1274                            if(pChild4->Attribute("input3"))
1275                                mList[mission_num].services[service_num].input[2] = pChild4->Attribute("input3");
1276                            if(pChild4->Attribute("input4"))
1277                                mList[mission_num].services[service_num].input[3] = pChild4->Attribute("input4");
1278                            if(pChild4->Attribute("input5"))
1279                                mList[mission_num].services[service_num].input[4] = pChild4->Attribute("input5");
1280                            if(pChild4->Attribute("output1"))
1281                                mList[mission_num].services[service_num].output[0] = pChild4->Attribute("output1");
1282                            if(pChild4->Attribute("output2"))
1283                                mList[mission_num].services[service_num].output[1] = pChild4->Attribute("output2");
1284                            if(pChild4->Attribute("output3"))
1285                                mList[mission_num].services[service_num].output[2] = pChild4->Attribute("output3");
1286                            if(pChild4->Attribute("output4"))
1287                                mList[mission_num].services[service_num].output[3] = pChild4->Attribute("output4");
1288                            if(pChild4->Attribute("output5"))
1289                                mList[mission_num].services[service_num].output[4] = pChild4->Attribute("output5");
1290                            cond_array[2]++;
1291                        }
1292                        if(!strcmp(pChild3->Value(), "shell") || conditional_2 != service_num) {
1293                            mList[mission_num].services[conditional_2].name = pChild3->Value();
1294                        }
1295                        else{
1296                            mList[mission_num].services[service_num].name = pChild3->Attribute("name");
1297                        }
1298                            if(pChild3->Attribute("input1"))
1299                                mList[mission_num].services[conditional_2].input[0] = pChild3->Attribute("input1");
1300                            if(pChild3->Attribute("input2"))
1301                                mList[mission_num].services[conditional_2].input[1] = pChild3->Attribute("input2");
1302                            if(pChild3->Attribute("input3"))
1303                                mList[mission_num].services[conditional_2].input[2] = pChild3->Attribute("input3");
1304                            if(pChild3->Attribute("input4"))
1305                                mList[mission_num].services[conditional_2].input[3] = pChild3->Attribute("input4");
1306                            if(pChild3->Attribute("input5"))
1307                                mList[mission_num].services[conditional_2].input[4] = pChild3->Attribute("input5");
1308                            if(pChild3->Attribute("output1"))
1309                                mList[mission_num].services[conditional_2].output[0] = pChild3->Attribute("output1");
1310                            if(pChild3->Attribute("output2"))
1311                                mList[mission_num].services[conditional_2].output[1] = pChild3->Attribute("output2");
1312                            if(pChild3->Attribute("output3"))
1313                                mList[mission_num].services[conditional_2].output[2] = pChild3->Attribute("output3");
1314                            if(pChild3->Attribute("output4"))
1315                                mList[mission_num].services[conditional_2].output[3] = pChild3->Attribute("output4");
1316                            if(pChild3->Attribute("output5"))
1317                                mList[mission_num].services[conditional_2].output[4] = pChild3->Attribute("output5");
1318                        mList[mission_num].services[conditional_2].num_conds = cond_array[2];
1319                        cond_array[1]+=cond_array[2]+1;
1320                        //printf("cond_array[2]%d\n", cond_array[2]);
1321                        cond_array[2] = 0;
1322
1323
1324                }
1325                //printf("here\n");
1326                if(!strcmp(pChild2->Value(), "shell") || conditional_1 != service_num) {
1327                    mList[mission_num].services[conditional_1].name = pChild2->Value();
1328                }
1329                else{
1330                    mList[mission_num].services[service_num].name = pChild2->Attribute("name");
1331                }
1332                if(pChild2->Attribute("input1"))
1333                    mList[mission_num].services[conditional_1].input[0] = pChild2->Attribute("input1");
1334                if(pChild2->Attribute("input2"))
1335                    mList[mission_num].services[conditional_1].input[1] = pChild2->Attribute("input2");
1336                    if(pChild2->Attribute("input3"))
1337                        mList[mission_num].services[conditional_1].input[2] = pChild2->Attribute("input3");
1338                    if(pChild2->Attribute("input4"))
1339                        mList[mission_num].services[conditional_1].input[3] = pChild2->Attribute("input4");
1340                    if(pChild2->Attribute("input5"))
1341                        mList[mission_num].services[conditional_1].input[4] = pChild2->Attribute("input5");
1342                    if(pChild2->Attribute("output1"))
1343                        mList[mission_num].services[conditional_1].output[0] = pChild2->Attribute("output1");
1344                    if(pChild2->Attribute("output2"))
1345                        mList[mission_num].services[conditional_1].output[1] = pChild2->Attribute("output2");
1346                    if(pChild2->Attribute("output3"))
1347                        mList[mission_num].services[conditional_1].output[2] = pChild2->Attribute("output3");
1348                    if(pChild2->Attribute("output4"))
1349                        mList[mission_num].services[conditional_1].output[3] = pChild2->Attribute("output4");
1350                    if(pChild2->Attribute("output5"))
1351                        mList[mission_num].services[conditional_1].output[4] = pChild2->Attribute("output5");
1352            //printf("2%s %s\n", mList[mission_num].services[conditional_1].output[0].c_str(), mList[mission_num].services[conditional_1].output[1].c_str());
1353
1354                mList[mission_num].services[conditional_1].num_conds = cond_array[1];
1355                cond_array[0]+=cond_array[1]+1;
1356                //printf("cond_array[1]%d\n", cond_array[1]);
1357                cond_array[1] = 0;
1358            }
1359           
1360            if(!strcmp(pChild1->Value(), "shell") || conditional_0 != service_num) {
1361                mList[mission_num].services[conditional_0].name = pChild1->Value();
1362            }
1363            else{
1364                mList[mission_num].services[conditional_0].name = pChild1->Attribute("name");
1365            }
1366                //printf("name=%s\n", mList[mission_num].services[conditional_0].name.c_str());
1367                if(pChild1->Attribute("input1"))
1368                    mList[mission_num].services[conditional_0].input[0] = pChild1->Attribute("input1");
1369                if(pChild1->Attribute("input2"))
1370                    mList[mission_num].services[conditional_0].input[1] = pChild1->Attribute("input2");
1371                if(pChild1->Attribute("input3"))
1372                    mList[mission_num].services[conditional_0].input[2] = pChild1->Attribute("input3");
1373                if(pChild1->Attribute("input4"))
1374                    mList[mission_num].services[conditional_0].input[3] = pChild1->Attribute("input4");
1375                if(pChild1->Attribute("input5"))
1376                    mList[mission_num].services[conditional_0].input[4] = pChild1->Attribute("input5");
1377                if(pChild1->Attribute("output1"))
1378                    mList[mission_num].services[conditional_0].output[0] = pChild1->Attribute("output1");
1379                if(pChild1->Attribute("output2"))
1380                    mList[mission_num].services[conditional_0].output[1] = pChild1->Attribute("output2");
1381                if(pChild1->Attribute("output3"))
1382                    mList[mission_num].services[conditional_0].output[2] = pChild1->Attribute("output3");
1383                if(pChild1->Attribute("output4"))
1384                    mList[mission_num].services[conditional_0].output[3] = pChild1->Attribute("output4");
1385                if(pChild1->Attribute("output5"))
1386                    mList[mission_num].services[service_num].output[4] = pChild1->Attribute("output4");
1387            //printf("1%s %s\n", mList[mission_num].services[conditional_0].output[0].c_str(), mList[mission_num].services[conditional_0].output[1].c_str());
1388            mList[mission_num].services[conditional_0].num_conds = cond_array[0];
1389            cond_array[0] = 0;
1390            service_num++;
1391        }
1392        //for(int i = 0; i < service_num; i++)
1393         //printf("ttt%d\n", mList[mission_num].services[i].num_conds);
1394       
1395        mList[mission_num].numServices = service_num;
1396        mList[mission_num].name = pChild0->Attribute("name");
1397        mList[mission_num].missionID = atoi(pChild0->Attribute("id"));
1398        if(pChild0->Attribute("input1"))
1399            mList[mission_num].input[0] = pChild0->Attribute("input1");
1400        if(pChild0->Attribute("input2"))
1401            mList[mission_num].input[1] = pChild0->Attribute("input2");
1402        if(pChild0->Attribute("input3"))
1403            mList[mission_num].input[2] = pChild0->Attribute("input3");
1404        if(pChild0->Attribute("input4"))
1405            mList[mission_num].input[3] = pChild0->Attribute("input4");
1406        if(pChild0->Attribute("input5"))
1407            mList[mission_num].input[4] = pChild0->Attribute("input4");
1408        if(pChild0->Attribute("output1"))
1409            mList[mission_num].output[0] = pChild0->Attribute("output1");
1410        if(pChild0->Attribute("output2"))
1411            mList[mission_num].output[1] = pChild0->Attribute("output2");
1412        if(pChild0->Attribute("output3"))
1413            mList[mission_num].output[2] = pChild0->Attribute("output3");
1414        if(pChild0->Attribute("output4"))
1415            mList[mission_num].output[3] = pChild0->Attribute("output4");
1416        if(pChild0->Attribute("output5"))
1417            mList[mission_num].output[4] = pChild0->Attribute("output5");
1418        //printf("mis, input1=%s, output1=%s\n", mList[mission_num].input[0].c_str(), mList[mission_num].output[0].c_str());
1419        //printf("NUMSERVICES = %d\n", mList[mission_num].numServices);
1420        mission_num++;
1421    }
1422}
1423
1424/* CALLED BY: MessageHandler
1425 * INPUTS: |ID| The ID number of the engine to be registered
1426 * OUTPUTS: <none>
1427 *
1428 * DESCRIPTION: Sends a registration message onto the shell and sends the ACK back to the component
1429 */
1430void
1431ServiceManagementLayer::RegisterCognitiveEngine(int32_t ID)
1432{
1433    //LOG("SML::regcogeng");
1434    SendMessage(shellSocketFD, "register_engine_cognitive");
1435
1436   // printf("SSFD = %d\n", shellSocketFD);
1437    LOG("ServiceManagementLayer:: CE registration message forwarded to shell.\n");
1438    char buffer[256];
1439    memset(buffer, 0, 256);
1440    ReadMessage(shellSocketFD, buffer);
1441    //printf("ServiceManagementLayer::buffer = %s\n", buffer);
1442    SendMessage(CE_List[ID].FD, buffer);
1443
1444    TransferRadioConfiguration(ID);
1445    memset(buffer, 0, 256);
1446    //printf("start trans exp\n");
1447    TransferExperience(ID);
1448    memset(buffer, 0, 256);
1449    numberOfCognitiveEngines++;
1450    CE_Present = true;
1451    //printf("done registering CE!\n");
1452}
1453
1454/* CALLED BY: MessageHandler
1455 * INPUTS: |ID| The ID number of the engine to have it's services deregistered
1456 * OUTPUTS: <none>
1457 *
1458 * DESCRIPTION: Deletes individual services from the DB
1459 * NOTE THAT this function only needs to be called if service deregistration is going
1460 * to be done at a different time than component deregistration; it is handled
1461 * more efficiently and directly during that deregistration process.
1462 */
1463void
1464ServiceManagementLayer::DeregisterServices(int32_t ID)
1465{
1466    char buffer[256];
1467    memset(buffer, 0, 256);
1468    ReadMessage(CE_List[ID].FD, buffer);
1469    strcpy(_services_DB->command, "DELETE FROM ");
1470    strcat(_services_DB->command, _services_DB->tablename);
1471    strcat(_services_DB->command, " WHERE ID_Num IN (SELECT");
1472    sprintf(_services_DB->command, " %s %d",_services_DB->command, ID);
1473    strcat(_services_DB->command, " FROM ");
1474    strcat(_services_DB->command, _services_DB->tablename);
1475    strcat(_services_DB->command, " WHERE Service_Name");
1476    strcat(_services_DB->command, "==");
1477    sprintf(_services_DB->command, "%s'%s');", _services_DB->command, buffer);
1478    char *errorMsg;
1479    int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
1480    if( rc!=SQLITE_OK && rc!=101 )
1481        fprintf(stderr, "SQL error: %s\n", errorMsg);
1482}
1483
1484/* CALLED BY: MessageHandler
1485 * INPUTS: |ID| The ID number of the engine to have it's services deregistered
1486 * OUTPUTS: <none>
1487 *
1488 * DESCRIPTION: Deletes the contact info for the cognitive engine, forwards a deregistration message to the shell
1489 * Also, deletes the services from the DB
1490 */
1491void
1492ServiceManagementLayer::DeregisterCognitiveEngine(int32_t ID)
1493{
1494    LOG("ServiceManagementLayer:: CE deregistration message forwarded to shell.\n");
1495
1496    numberOfCognitiveEngines--;
1497    if(numberOfCognitiveEngines == 0)
1498        CE_Present = false;
1499
1500    SendMessage(shellSocketFD, "deregister_engine_cognitive");
1501    char buffer[256];
1502    memset(buffer, 0, 256);
1503    ReadMessage(shellSocketFD, buffer);
1504    SendMessage(CE_List[ID].FD, buffer);
1505    if(strcmp("deregister_ack", buffer) != 0) {
1506        ERROR(1, "SML:: Failed to close CE socket\n");
1507    }
1508
1509    //Deregister the services
1510    strcpy(_services_DB->command, "DELETE FROM ");
1511    strcat(_services_DB->command, _services_DB->tablename);
1512    strcat(_services_DB->command, " WHERE ");
1513    strcat(_services_DB->command, "ID_Num");
1514    strcat(_services_DB->command, "==");
1515    sprintf(_services_DB->command, "%s%d;", _services_DB->command, ID);
1516    char *errorMsg;
1517    int rc = sqlite3_exec(_services_DB->db, _services_DB->command, callback, 0, &errorMsg);
1518    if( rc!=SQLITE_OK && rc!=101 )
1519        fprintf(stderr, "SQL error: %s\n", errorMsg);
1520
1521
1522    CE_List[ID].FD = -1;
1523    CE_List[ID].ID_num = -1;
1524
1525    LOG("Cognitive Radio Shell:: CE Socket closed for engine #%d.\n", ID);
1526}
1527
1528
1529/* CALLED BY: test class
1530 * INPUTS: <none>
1531 * OUTPUTS: <none>
1532 *
1533 * DESCRIPTION: Sets up a server socket and listens for communication on either that or the shell socket
1534 */
1535void
1536ServiceManagementLayer::StartSMLServer()
1537{
1538    //printf("Ready for CE Signal! (registration done)\n");
1539    struct timeval selTimeout;
1540    int32_t running = 1;
1541    int32_t port, rc, new_sd = 1;
1542    int32_t desc_ready = 1;
1543                //If there is, call the MessageHandler with the Shell_Msg code of -1
1544    fd_set sockSet, shellSet;
1545
1546    cogEngSrv = CreateTCPServerSocket(SMLport);
1547    int32_t maxDescriptor = cogEngSrv;
1548
1549    if(InitializeTCPServerPort(cogEngSrv) == -1)
1550        ERROR(1,"Error initializing primary port\n");
1551
1552    int i = 10000000;  //TODO change to "running" if endpoint can be reached
1553    while (running) {
1554        i--;
1555        /* Zero socket descriptor vector and set for server sockets */
1556        /* This must be reset every time select() is called */
1557        FD_ZERO(&sockSet);
1558        FD_SET(cogEngSrv, &sockSet);
1559        for(uint16_t k = 0; k < Current_ID; k++){
1560            if(CE_List[k].ID_num != -1)
1561                FD_SET(CE_List[k].FD, &sockSet);
1562        }
1563            //printf("k=%d, CID=%d\n", k, CE_List[k].FD);
1564
1565        /* Timeout specification */
1566        /* This must be reset every time select() is called */
1567        selTimeout.tv_sec = 0;       /* timeout (secs.) */
1568        selTimeout.tv_usec = 0;            /* 0 microseconds */
1569        //Changed both to zero so that select will check messages from the shell instead of blocking
1570        //when there is no command from the CE's to be processed
1571
1572        //Check if there is a message on the socket waiting to be read
1573        rc = select(maxDescriptor + 1, &sockSet, NULL, NULL, &selTimeout);
1574        //printf("rc=%d\n", rc);
1575        if(rc == 0){
1576            //LOG("No echo requests for %i secs...Server still alive\n", timeout);
1577       
1578            FD_ZERO(&shellSet);
1579            FD_SET(shellSocketFD, &shellSet);
1580            selTimeout.tv_sec = 0;
1581            selTimeout.tv_usec = 0;
1582            //Check if there is a message on the shell socket ready to be processed
1583            select(shellSocketFD + 1, &shellSet, NULL, NULL, &selTimeout);
1584            //printf("rc2=%d\n", rc2);
1585                //If there is, call the MessageHandler with the Shell_Msg code of -1
1586            if(FD_ISSET(shellSocketFD, &shellSet)){
1587                //printf("shell_msg, %d\n", rc2);
1588                MessageHandler(-1);}
1589        }
1590        else {
1591            desc_ready = rc;
1592            for(port = 0; port <= maxDescriptor && desc_ready > 0; port++) {
1593                if(FD_ISSET(port, &sockSet)) {
1594                    desc_ready -= 1;
1595
1596                    //Check if request is new or on an existing open descriptor
1597                    if(port == cogEngSrv) {
1598                        //If new, assign it a descriptor and give it an ID
1599                        new_sd = AcceptTCPConnection(port);
1600                         
1601                        if(new_sd < 0)
1602                            break;
1603
1604                        CE_List[Current_ID].FD = new_sd;
1605                        CE_List[Current_ID].ID_num = Current_ID;
1606                        MessageHandler(Current_ID);
1607                        Current_ID++;
1608       
1609                        FD_SET(new_sd,&sockSet);
1610                        if(new_sd > maxDescriptor)
1611                           maxDescriptor = new_sd;
1612                    }
1613                    else {
1614                        //If old, figure out which ID it coresponds to and handle it accordingly
1615                        for(uint16_t z = 0; z < Current_ID; z++)
1616                        {
1617                                if(CE_List[z].FD == port){
1618                                        MessageHandler(z);}
1619                        }
1620                    }
1621                }
1622            }
1623        }
1624    }       
1625
1626    /* Close sockets */
1627    close(cogEngSrv);
1628
1629    //delete &cogEngSrv;
1630    return;
1631}
Note: See TracBrowser for help on using the browser.