Cleaning up C++ slave.
[iot2.git] / iotjava / iotruntime / cpp / iotslave / IoTSlave.cpp
1 #include <iostream>
2 #include <fstream>
3
4 #include "IoTSlave.hpp"
5
6 IoTSlave::IoTSlave(string _serverAddress, int _serverPort, string _objectName) {
7
8         serverAddress = _serverAddress;
9         serverPort = _serverPort;
10         objectName = _objectName;
11         socket = new TCPSocket(serverAddress, serverPort);
12         openFile(objectName);
13         writeToFile("IoTSlave object created! Connection established!");
14 }
15
16
17 IoTSlave::~IoTSlave() {
18
19         if (socket != NULL) {
20                 delete socket;
21                 socket = NULL;
22         }
23         /*if (objMainCls != NULL) {
24                 delete objMainCls;
25                 objMainCls = NULL;
26         }
27         if (objSkelCls != NULL) {
28                 delete objSkelCls;
29                 objSkelCls = NULL;
30         }*/
31         for (IoTSet<void*>* iotset : vecIoTSet) {
32                 delete iotset;
33                 iotset = NULL;
34         }
35         closeFile();
36 }
37
38
39 // Private helper functions
40 int* IoTSlave::byteToInt(int* result, char* bytes) {
41
42         int i = 0;
43         memcpy(&i, bytes, sizeof(int));
44         *result = be32toh(i);
45
46         return result;
47 }
48
49
50 char* IoTSlave::intToByteArray(int i, char* bytes) {
51
52         int iInvert = htobe32(i);
53         memcpy(bytes, &iInvert, sizeof(int));
54
55         return bytes;
56 }
57
58
59 void* IoTSlave::getObjectConverted(void* retObj, string object, string objectClass) {
60
61         // Returning new objects in heap - so we need to delete them afterwards
62         if (objectClass.compare(STRINGCLASS) == 0) {
63                 string* retStr = new string(object);
64                 retObj = retStr;
65         } else if (objectClass.compare(INTCLASS) == 0) {
66                 int* retInt = new int(atoi(object.c_str()));
67                 retObj = retInt;
68         } else  // return NULL if class is not identifiable
69                 return NULL;
70
71         return retObj;
72 }
73
74
75 // Factoring out iteration
76 char* IoTSlave::recvIter(char* recvBuffer, int recvLen) {
77
78     int bytesReceived = 0;              // Bytes read on each recv()
79     int totalBytesReceived = 0;         // Total bytes read
80
81         while (totalBytesReceived < recvLen) {
82                 // Receive up to the buffer size bytes from the sender
83                 if ((bytesReceived = (socket->recv(recvBuffer, RCVBUFSIZE))) <= 0) {
84                         string errMsg = "IoTSlave: Unable to read!";
85                         cerr << errMsg << endl;
86                         writeToFile(errMsg);
87                         exit(1);
88                 }
89                 totalBytesReceived += bytesReceived;     // Keep tally of total bytes
90         }
91
92         return recvBuffer;
93 }
94
95
96 // Factoring out iteration
97 char* IoTSlave::recvFileIter(char* recvBuffer, int recvLen) {
98
99     int bytesReceived = 0;              // Bytes read on each recv()
100     int totalBytesReceived = 0;         // Total bytes read
101
102         while (totalBytesReceived < recvLen) {
103                 // Receive up to the buffer size bytes from the sender
104                 if ((bytesReceived = (socket->recv(recvBuffer, recvLen))) <= 0) {
105                         string errMsg = "IoTSlave: Unable to read!";
106                         cerr << errMsg << endl;
107                         writeToFile(errMsg);
108                         exit(1);
109                 }
110                 totalBytesReceived += bytesReceived;     // Keep tally of total bytes
111         }
112
113         return recvBuffer;
114 }
115
116
117 void IoTSlave::openFile(string fileName) {
118
119         log.open(LOGFILEPATH + fileName + FILEEXT);
120 }
121
122
123 void IoTSlave::writeToFile(string logMsg) {
124
125         log << "IoTSlave: " << logMsg << endl;
126 }
127
128
129 void IoTSlave::closeFile() {
130
131         log.close();
132 }
133
134
135 void IoTSlave::getObjectHandler(string objectClassName) {
136
137         // Object handling
138         string strObj = FILEPATH + objectClassName + SOEXT;
139         void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
140         if (!handle) {
141                 fputs (dlerror(), stderr);
142                 writeToFile("Error handling object!");
143                 exit(1);
144         }
145         writeToFile("Object handled!");
146         // Create handler
147         string createFunction = CREATEFUNCTION + objectClassName;
148         create_object = (create_t*) dlsym(handle, createFunction.c_str());
149         const char* dlsym_error = dlerror();
150     if (dlsym_error) {
151         cerr << "Cannot load symbol create: " << dlsym_error << '\n';
152                 writeToFile("Cannot load symbol create!");
153         exit(1);
154     }
155         writeToFile("Object factory created for " + objectClassName);
156         // Destroy handler
157         string destroyFunction = DESTROYFUNCTION + objectClassName;
158     destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
159     dlsym_error = dlerror();
160     if (dlsym_error) {
161         cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
162                 writeToFile("Cannot load symbol destroy!");
163         exit(1);
164     }
165         writeToFile("Object destroyer created for " + objectClassName);
166         // Create initializer
167         string initFunction = INITFUNCTION + objectClassName;
168     init_object = (init_t*) dlsym(handle, initFunction.c_str());
169     dlsym_error = dlerror();
170     if (dlsym_error) {
171         cerr << "Cannot load symbol init: " << dlsym_error << '\n';
172                 writeToFile("Cannot load symbol init!");
173         exit(1);
174     }
175         writeToFile("Object initializer created for " + objectClassName);
176 }
177
178
179 // Run init_object function
180 void IoTSlave::runInitObject(IoTSlave* iotslave) {
181
182         iotslave->init_object(iotslave->objMainCls);
183 }
184
185
186 // Instantiate main object!
187 // Use handler obtained by getObjectHandler() and instantiate object!
188 void IoTSlave::instantiateMainObject() {
189
190         // IoTSet + IoTRelation objects
191         int paramSize = vecIoTSet.size() + vecIoTRel.size();
192         void* params[paramSize];
193         int j = 0;
194         for(int i=0; i<vecIoTSet.size(); i++) {
195                 params[j] = vecIoTSet[i]; j++;
196         }
197         writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
198         for(int i=0; i<vecIoTRel.size(); i++) {
199                 params[j] = vecIoTRel[i]; j++;
200         }
201         writeToFile("Vector IoTRelation size: " + to_string(vecIoTRel.size()));
202         objMainCls = create_object(params);
203         writeToFile("Object created for " + mainObjectName);
204         init_object(objMainCls);
205     // TODO: Maybe we want to change this into multithreading at some point
206         //thread th1 (&IoTSlave::runInitObject, this, this);
207         //th1.detach();
208         //thread th1 (&IoTSlave::runInitObject, this, this);
209         //th1.join();
210         writeToFile("Initialized object " + mainObjectName);
211 }
212
213
214 // Instantiate driver object!
215 // Use handler obtained by getObjectHandler() and instantiate object!
216 void IoTSlave::instantiateDriverObject() {
217
218         // IoTDeviceAddress + other arguments
219         int paramSize = vecIoTSet.size() + args.size();
220         void* params[paramSize];
221         for(int i=0; i<vecIoTSet.size(); i++) {
222                 params[i] = vecIoTSet[i];       // Just the first object is taken in this case
223         }
224         writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
225         writeToFile("Arg size: " + to_string(args.size()));
226         int countArg = vecIoTSet.size();        // Start from after the address set
227         // Iterate over arguments
228         for(int i=0; i<args.size(); i++) {
229                 params[countArg] = getObjectConverted(params[countArg], args[i], argClasses[i]);
230                 countArg++; 
231         }
232         objMainCls = create_object(params);
233         // Delete unused object after conversion and instantiation
234         for(int i=1; i<paramSize; i++) {
235                 if (argClasses[i-1].compare(STRINGCLASS) == 0) {                
236                         delete (string*) params[i];
237                 } else if (argClasses[i-1].compare(INTCLASS) == 0)
238                         delete (int*) params[i];
239         }               
240         writeToFile("Object created for " + objectClassName);
241 }
242
243
244 // Use handler obtained by getObjectHandler() and instantiate skeleton object!
245 void IoTSlave::instantiateSkelObject() {
246
247         void* params[SKELPARAMSIZE];
248         params[0] = objMainCls;
249         params[1] = &objectStubPort;
250         params[2] = &objectRegPort;
251         writeToFile("Skeleton Object " + objectSkelClass + " created for " + objectClassName);
252         // After this, this slave needs to be killed using "pkill IoTSlave" because it's waiting in an infinite while-loop
253         objSkelCls = create_object(params);
254 }
255
256
257 // Use handler obtained by getObjectHandler() and instantiate stub object!
258 void IoTSlave::instantiateStubObject() {
259
260         void* params[STUBPARAMSIZE];
261         params[0] = &objectStubPort;
262         params[1] = &objectRegPort;
263         params[2] = &hostAddress;
264         int rev = 0;
265         params[3] = &rev;
266         bool result = false;
267         params[4] = &result;
268         writeToFile("Stub Object " + objectStubClass + " created for " + objectClassName);
269         writeToFile("Success 1!");
270         objStubCls = create_object(params);
271         writeToFile("Success 2!");
272 }
273
274
275 // Public methods
276 string IoTSlave::getServerAddress() {
277
278         return serverAddress;
279 }
280
281
282 int IoTSlave::getServerPort() {
283
284         return serverPort;
285 }
286
287
288 string IoTSlave::getObjectName() {
289
290         return objectName;
291 }
292
293
294 void IoTSlave::sendInteger(int intSend) {
295
296         char charInt[sizeof(int)];
297         // Convert int to byte array and fix endianness
298         intToByteArray(intSend, charInt);
299         // Send the length first
300         void* toSend = charInt;
301         socket->send(toSend, sizeof(int));
302 }
303
304
305 int IoTSlave::recvInteger() {
306
307         int toBeReceived = sizeof(int);
308         char recvInt[sizeof(int)];                      // Normally 4 bytes
309
310         // Receive and iterate until complete
311         recvIter(recvInt, toBeReceived);
312
313         int retVal = 0;
314         byteToInt(&retVal, recvInt);
315
316         return retVal;
317 }
318
319
320 void IoTSlave::sendString(string strSend) {
321
322         // Send the length first
323         int strLen = strSend.length();
324         sendInteger(strLen);
325
326         // Send the string
327         char* chStrSend = new char[strLen];
328         strcpy(chStrSend, strSend.c_str());
329         void* toSend = chStrSend;
330         socket->send(toSend, strLen);
331         // Avoid memory leak
332         delete[] chStrSend;
333 }
334
335
336 string IoTSlave::recvString() {
337
338         // Get the length of string first
339         int strLen = recvInteger();
340         char* recvStr = new char[strLen];
341
342         // Receive and iterate until complete
343         recvIter(recvStr, strLen);
344
345         string retVal(recvStr, strLen);
346         delete[] recvStr;
347
348         return retVal;
349 }
350
351
352 // Receive file from IoTMaster
353 void IoTSlave::transferFile() {
354
355         string fileName = recvFile(); sendAck();
356         //unzipFile(fileName);
357 }
358
359
360 void IoTSlave::unzipFile(string fileName) {
361
362         // Unzip file (what we are sending is a zipped file)
363         // TODO: perhaps we need to replace this with libzip or zlib later      
364         writeToFile("Unzipping file!");
365         string chmodCmd = FILEPATH + fileName + SHELL;
366         thread th1 (std::system, chmodCmd.c_str());
367         th1.detach();
368         writeToFile("Finished unzipping file!");
369 }
370
371
372 string IoTSlave::recvFile() {
373
374         // Get the length of string first
375         string fileName = recvString(); sendAck();
376         int fileLen = recvInteger(); sendAck();
377         writeToFile("Receiving file " + fileName + " with length " + to_string(fileLen) + " bytes...");
378         char* recvFil = new char[fileLen];
379         // Receive and iterate until complete
380         recvFileIter(recvFil, fileLen);
381         // Write into file
382         ofstream fileStream;
383         fileStream.open(FILEPATH + fileName);
384         if (!fileStream) {
385                 writeToFile("Error opening file: " + FILEPATH + fileName);
386                 exit(1);
387         }
388         fileStream.write(recvFil, fileLen);
389         delete[] recvFil;
390         fileStream.close();
391         return fileName;
392 }
393
394
395 // Create a driver object, e.g. LifxLightBulb
396 void IoTSlave::createObject() {
397
398         writeToFile("Creating a driver object now...");
399         // Receiving object info
400         objectName = recvString(); sendAck();
401         writeToFile("=> Driver object name: " + objectName);
402         objectClassName = recvString(); sendAck();
403         writeToFile("=> Driver object class name: " + objectClassName);
404         objectInterfaceName = recvString(); sendAck();
405         writeToFile("=> Driver object interface name: " + objectInterfaceName);
406         objectSkelClass = recvString(); sendAck();
407         writeToFile("=> Driver object skeleton class name: " + objectSkelClass);
408         objectRegPort = recvInteger(); sendAck();
409         writeToFile("=> Driver object registry port: " + to_string(objectRegPort));
410         objectStubPort = recvInteger(); sendAck();
411         writeToFile("=> Driver object stub port: " + to_string(objectStubPort));
412         int numOfArgs = recvInteger(); sendAck();
413         writeToFile("=> Number of args: " + to_string(numOfArgs));
414         for (int i = 0; i < numOfArgs; i++) {
415                 string arg = recvString(); sendAck();
416                 args.push_back(arg);
417                 writeToFile("==> Got argument: " + arg);
418         }
419         for (int i = 0; i < numOfArgs; i++) {
420                 string argClass = recvString(); sendAck();
421                 argClasses.push_back(argClass);
422                 writeToFile("==> Got argument class: " + argClass);
423         }
424         // We are just receiving object information here
425         // Instantiation will be done when IoTDeviceAddress has been sent
426 }
427
428
429 // Create a new IoTSet object to hold objects
430 void IoTSlave::createNewIoTSet() {
431
432         objectFieldName = recvString(); sendAck();
433         // Instantiating new IoTSet object
434         isetObject = new unordered_set<void*>();
435         writeToFile("Creating new IoTSet for field: " + objectFieldName);
436 }
437
438
439 // Get IoTDeviceAddress object reference and put it inside IoTSet object
440 void IoTSlave::getDeviceIoTSetObject() {
441
442         writeToFile("Getting IoTDeviceAddress... ");
443         // Get the IoTDeviceAddress info
444         hostAddress = recvString(); sendAck();
445         writeToFile("=> Host address: " + hostAddress);
446         int sourcePort = recvInteger(); sendAck();
447         writeToFile("=> Source port: " + to_string(sourcePort));
448         int destPort = recvInteger(); sendAck();
449         writeToFile("=> Destination port: " + to_string(destPort));
450         bool sourcePortWildCard = (bool) recvInteger(); sendAck();
451         writeToFile("=> Is source port wild card? " + to_string(sourcePortWildCard));
452         bool destPortWildCard = (bool) recvInteger(); sendAck();
453         writeToFile("=> Is destination port wild card? " + to_string(destPortWildCard));
454         // Create IoTDeviceAddress      
455         IoTDeviceAddress* objDeviceAddress = new IoTDeviceAddress(hostAddress, sourcePort, destPort, 
456                 sourcePortWildCard, destPortWildCard);
457         // Insert it into isetObject!
458         isetObject->insert(objDeviceAddress);
459         writeToFile("=> Inserting IoTDeviceAddress into set...");
460         writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
461 }
462
463
464 void IoTSlave::createStub() {
465         // Create Stub object
466         unordered_map<string,void*>::const_iterator itr = mapObjNameStub.find(objectName);
467         if (itr != mapObjNameStub.end()) {      // Stub has been created earlier
468                 writeToFile("=> Stub has been created! Getting back reference...");
469                 objStubCls = itr->second;
470         } else {        // Instantiate a new stub and map it
471                 writeToFile("=> Stub has not been created! Creating a new stub...");
472                 getObjectHandler(objectStubClass);
473                 instantiateStubObject();
474                 mapObjNameStub.insert(make_pair(objectName,objStubCls));
475                 writeToFile("=> Map has: " + to_string(mapObjNameStub.size()) + " members");
476         }
477 }
478
479
480 // Get IoTSet object content reference and put it inside IoTSet object
481 // This is basically the stub objects
482 void IoTSlave::getIoTSetObject() {
483
484         writeToFile("Getting IoTSet object... ");
485         getIoTSetRelationObject();
486         createStub();
487         // Insert it into isetObject!
488         isetObject->insert(objStubCls);
489         writeToFile("=> Inserting stub object into set...");
490         writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
491 }
492
493
494 // Reinitialize IoTSet field!
495 void IoTSlave::reinitializeIoTSetField() {
496
497         writeToFile("Reinitialize IoTSet field...");
498         iotsetObject = new IoTSet<void*>(isetObject);
499         // Collect IoTSet field first in a vector
500         vecIoTSet.push_back(iotsetObject);
501
502 }
503
504
505 // Instantiate driver object
506 void IoTSlave::createDriverObject() {
507
508         // Instantiate driver object
509         getObjectHandler(objectClassName);
510         instantiateDriverObject();
511         // Instantiate skeleton object
512         getObjectHandler(objectSkelClass);
513         instantiateSkelObject();
514 }
515
516
517 // Create a new IoTRelation object to hold objects
518 void IoTSlave::createNewIoTRelation() {
519
520         objectFieldName = recvString(); sendAck();
521         // Instantiating new IoTSet object
522         irelObject = new unordered_multimap<void*,void*>();
523         writeToFile("Creating new IoTRelation for field: " + objectFieldName);
524 }
525
526
527 // Get IoTRelation object
528 void IoTSlave::getIoTSetRelationObject() {
529
530         hostAddress = recvString(); sendAck();
531         writeToFile("=> Host address: " + hostAddress);
532         objectName = recvString(); sendAck();
533         writeToFile("=> Driver object name: " + objectName);
534         objectClassName = recvString(); sendAck();
535         writeToFile("=> Driver object class name: " + objectClassName);
536         objectInterfaceName = recvString(); sendAck();
537         writeToFile("=> Driver object interface name: " + objectInterfaceName);
538         objectStubClass = recvString(); sendAck();
539         writeToFile("=> Driver object stub class name: " + objectStubClass);
540         objectRegPort = recvInteger(); sendAck();
541         writeToFile("=> Driver object registry port: " + to_string(objectRegPort));
542         objectStubPort = recvInteger(); sendAck();
543         writeToFile("=> Driver object stub port: " + to_string(objectStubPort));
544 }
545
546
547 // Get the first object of IoTRelation
548 void IoTSlave::getIoTRelationFirstObject() {
549
550         writeToFile("Getting IoTRelation first object... ");
551         getIoTSetRelationObject();
552         createStub();
553         // Hold the first object of IoTRelation
554         irelFirstObject = objStubCls;
555         writeToFile("=> Holding first stub object...");
556 }
557
558
559 // Get the second object of IoTRelation
560 void IoTSlave::getIoTRelationSecondObject() {
561
562         writeToFile("Getting IoTRelation second object... ");
563         getIoTSetRelationObject();
564         createStub();
565         // Hold the first object of IoTRelation
566         irelSecondObject = objStubCls;
567         writeToFile("=> Holding second stub object...");
568         pair<void*,void*>* iotrelPair = new pair<void*,void*>(irelFirstObject, irelSecondObject);
569         writeToFile("=> Creating a pair of stub objects and inserting into IoTRelation object...");
570         irelObject->insert(*iotrelPair);
571 }
572
573
574 // Reinitialize IoTRelation
575 void IoTSlave::reinitializeIoTRelationField() {
576
577         writeToFile("Reinitialize IoTRelation field...");
578         iotrelObject = new IoTRelation<void*,void*>(irelObject);
579         // Collect IoTSet field first in a vector
580         vecIoTRel.push_back(iotrelObject);
581 }
582
583
584 // Invoke init() method in main controller
585 void IoTSlave::invokeInitMethod() {
586
587         writeToFile("Invoke init() method for: " + mainObjectName);
588         // Instantiate main controller object
589         getObjectHandler(mainObjectName);
590         instantiateMainObject();
591
592 }
593
594
595 // Create a main object, e.g. Lifxtest
596 void IoTSlave::createMainObject() {
597
598         mainObjectName = recvString(); sendAck();
599         writeToFile("Creating main object: " + mainObjectName);
600         // Just receive the name of the class object here
601         // We will instantiate the object after we get the set/relation objects
602 }
603
604
605 void IoTSlave::sendAck() {
606
607         int codeAck = (int) ACKNOWLEDGED;
608         sendInteger(codeAck);
609 }
610
611
612 bool IoTSlave::recvEndTransfer() {
613
614         int codeEndTransfer = (int) END_TRANSFER;
615         int recvCode = recvInteger();
616         if (recvCode == codeEndTransfer)
617                 return true;
618         return false;
619 }
620
621
622 void IoTSlave::commIoTMaster() {
623
624         writeToFile("Starting main loop...");
625         // Main iteration/loop
626         while(true) {
627                 IoTCommCode message = (IoTCommCode) recvInteger(); 
628                 writeToFile("Message: " + to_string(message));
629                 sendAck();
630                 
631                 switch(message) {
632
633                         case CREATE_OBJECT:
634                                 createObject();
635                                 break;
636
637                         case TRANSFER_FILE:
638                                 transferFile();
639                                 break;
640
641                         case CREATE_MAIN_OBJECT:
642                                 createMainObject();
643                                 break;
644
645                         case CREATE_NEW_IOTSET:
646                                 createNewIoTSet();
647                                 break;
648
649                         case CREATE_NEW_IOTRELATION:
650                                 createNewIoTRelation();
651                                 break;
652
653                         case GET_IOTSET_OBJECT:
654                                 getIoTSetObject();
655                                 break;
656
657                         case GET_IOTRELATION_FIRST_OBJECT:
658                                 getIoTRelationFirstObject();
659                                 break;
660
661                         case GET_IOTRELATION_SECOND_OBJECT:
662                                 getIoTRelationSecondObject();
663                                 break;
664
665                         case REINITIALIZE_IOTSET_FIELD:
666                                 reinitializeIoTSetField();
667                                 break;
668
669                         case REINITIALIZE_IOTRELATION_FIELD:
670                                 reinitializeIoTRelationField();
671                                 break;
672
673                         case GET_DEVICE_IOTSET_OBJECT:
674                                 getDeviceIoTSetObject();
675                                 break;
676
677                         case GET_ZB_DEV_IOTSET_OBJECT:
678                             // TODO: Support ZigBee in the future
679                                 //getZBDevIoTSetObject();
680                                 break;
681
682                         case GET_ADD_IOTSET_OBJECT:
683                                 //getAddIoTSetObject();
684                                 break;
685
686                         case INVOKE_INIT_METHOD:
687                                 invokeInitMethod();
688                                 break;
689
690                         case CREATE_DRIVER_OBJECT:
691                                 createDriverObject();
692                                 break;
693
694                         case END_SESSION:
695                                 // END of session
696                                 goto ENDLOOP;
697                                 break;
698
699                         default:
700                                 break;
701                 }
702         }
703         ENDLOOP:
704         writeToFile("End of loop!");
705 }
706
707
708 int main(int argc, char *argv[]) {
709
710         string serverAddress = argv[1];
711         char* servPort = argv[2];
712         int serverPort = atoi(servPort);
713         string strObjName = argv[3];
714         IoTSlave *iotSlave = new IoTSlave(serverAddress, serverPort, strObjName);
715         iotSlave->sendAck();
716         iotSlave->commIoTMaster();
717         
718         return 0;
719 }