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

Revision 465, 66.2 KB (checked in by bhilburn, 15 years ago)

First step in revamping component architecture in preperation for fixing
the CBR implementation. Files only now include the declaration for the
component they need - not all of them.

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