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