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