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

Revision 282, 54.5 KB (checked in by wrodgers, 15 years ago)

Latest update of SML

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