Perfecting IoTSlave for C++; Found one issue with SSH/Java process execution in which...
[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 void IoTSlave::openFile(string fileName) {
100
101         log.open(FILEPATH + fileName + FILEEXT);
102 }
103
104
105 void IoTSlave::writeToFile(string logMsg) {
106
107         log << "IoTSlave: " << logMsg << endl;
108 }
109
110
111 void IoTSlave::closeFile() {
112
113         log.close();
114 }
115
116
117 void IoTSlave::getObjectHandler(string objectClassName) {
118
119         // Object handling
120         string strObj = FILEPATH + objectClassName + SOEXT;
121         void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
122         if (!handle) {
123                 fputs (dlerror(), stderr);
124                 writeToFile("Error handling object!");
125                 exit(1);
126         }
127         writeToFile("Object handled!");
128         // Create handler
129         string createFunction = CREATEFUNCTION + objectClassName;
130         create_object = (create_t*) dlsym(handle, createFunction.c_str());
131         const char* dlsym_error = dlerror();
132     if (dlsym_error) {
133         cerr << "Cannot load symbol create: " << dlsym_error << '\n';
134                 writeToFile("Cannot load symbol create!");
135         exit(1);
136     }
137         writeToFile("Object factory created for " + objectClassName);
138         // Destroy handler
139         string destroyFunction = DESTROYFUNCTION + objectClassName;
140     destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
141     dlsym_error = dlerror();
142     if (dlsym_error) {
143         cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
144                 writeToFile("Cannot load symbol destroy!");
145         exit(1);
146     }
147         writeToFile("Object destroyer created for " + objectClassName);
148         // Create initializer
149         string initFunction = INITFUNCTION + objectClassName;
150     init_object = (init_t*) dlsym(handle, initFunction.c_str());
151     dlsym_error = dlerror();
152     if (dlsym_error) {
153         cerr << "Cannot load symbol init: " << dlsym_error << '\n';
154                 writeToFile("Cannot load symbol init!");
155         exit(1);
156     }
157         writeToFile("Object initializer created for " + objectClassName);
158 }
159
160
161 // Run init_object function
162 void IoTSlave::runInitObject(IoTSlave* iotslave) {
163
164         iotslave->init_object(iotslave->objMainCls);
165 }
166
167
168 // Instantiate main object!
169 // Use handler obtained by getObjectHandler() and instantiate object!
170 void IoTSlave::instantiateMainObject() {
171
172         // IoTDeviceAddress + other arguments
173         int paramSize = vecIoTSet.size();
174         void* params[paramSize];
175         for(int i=0; i<vecIoTSet.size(); i++) {
176                 params[i] = vecIoTSet[i];       // Just the first object is taken in this case
177         }
178         writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
179         objMainCls = create_object(params);
180         writeToFile("Object created for " + mainObjectName);
181         init_object(objMainCls);
182         //thread th1 (&IoTSlave::runInitObject, this, this);
183         //th1.detach();
184         //thread th1 (&IoTSlave::runInitObject, this, this);
185         //th1.join();
186         writeToFile("Initialized object " + mainObjectName);
187 }
188
189
190 // Instantiate driver object!
191 // Use handler obtained by getObjectHandler() and instantiate object!
192 void IoTSlave::instantiateDriverObject() {
193
194         // IoTDeviceAddress + other arguments
195         int paramSize = vecIoTSet.size() + args.size();
196         void* params[paramSize];
197         for(int i=0; i<vecIoTSet.size(); i++) {
198                 params[i] = vecIoTSet[i];       // Just the first object is taken in this case
199         }
200         writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
201         writeToFile("Arg size: " + to_string(args.size()));
202         int countArg = vecIoTSet.size();        // Start from after the address set
203         // Iterate over arguments
204         for(int i=0; i<args.size(); i++) {
205                 params[countArg] = getObjectConverted(params[countArg], args[i], argClasses[i]);
206                 countArg++; 
207         }
208         objMainCls = create_object(params);
209         // Delete unused object after conversion and instantiation
210         for(int i=1; i<paramSize; i++) {
211                 if (argClasses[i-1].compare(STRINGCLASS) == 0) {                
212                         delete (string*) params[i];
213                 } else if (argClasses[i-1].compare(INTCLASS) == 0)
214                         delete (int*) params[i];
215         }               
216         writeToFile("Object created for " + objectClassName);
217 }
218
219
220 // Use handler obtained by getObjectHandler() and instantiate skeleton object!
221 void IoTSlave::instantiateSkelObject() {
222
223         void* params[SKELPARAMSIZE];
224         params[0] = objMainCls;
225         string callbackAddress = LOCALHOST;
226         params[1] = &callbackAddress;
227         params[2] = &objectStubPort;
228         writeToFile("Skeleton Object " + objectSkelClass + " created for " + objectClassName);
229         // After this, this slave needs to be killed using "pkill IoTSlave" because it's waiting in an infinite while-loop
230         objSkelCls = create_object(params);
231 }
232
233
234 // Use handler obtained by getObjectHandler() and instantiate stub object!
235 void IoTSlave::instantiateStubObject() {
236
237         void* params[STUBPARAMSIZE];
238         params[0] = &objectStubPort;
239         params[1] = &hostAddress;
240         string callbackAddress = LOCALHOST;
241         params[2] = &callbackAddress;
242         int rev = 0;
243         params[3] = &rev;
244         bool result = false;
245         params[4] = &result;
246         params[5] = &ports;
247         writeToFile("Stub Object " + objectStubClass + " created for " + objectClassName);
248         objStubCls = create_object(params);
249 }
250
251
252 // Public methods
253 string IoTSlave::getServerAddress() {
254
255         return serverAddress;
256 }
257
258
259 int IoTSlave::getServerPort() {
260
261         return serverPort;
262 }
263
264
265 string IoTSlave::getObjectName() {
266
267         return objectName;
268 }
269
270
271 void IoTSlave::sendInteger(int intSend) {
272
273         char charInt[sizeof(int)];
274         // Convert int to byte array and fix endianness
275         intToByteArray(intSend, charInt);
276         // Send the length first
277         void* toSend = charInt;
278         socket->send(toSend, sizeof(int));
279 }
280
281
282 int IoTSlave::recvInteger() {
283
284         int toBeReceived = sizeof(int);
285         char recvInt[sizeof(int)];                      // Normally 4 bytes
286
287         // Receive and iterate until complete
288         recvIter(recvInt, toBeReceived);
289
290         int retVal = 0;
291         byteToInt(&retVal, recvInt);
292
293         return retVal;
294 }
295
296
297 void IoTSlave::sendString(string strSend) {
298
299         // Send the length first
300         int strLen = strSend.length();
301         sendInteger(strLen);
302
303         // Send the string
304         char* chStrSend = new char[strLen];
305         strcpy(chStrSend, strSend.c_str());
306         void* toSend = chStrSend;
307         socket->send(toSend, strLen);
308         // Avoid memory leak
309         delete[] chStrSend;
310 }
311
312
313 string IoTSlave::recvString() {
314
315         // Get the length of string first
316         int strLen = recvInteger();
317         char* recvStr = new char[strLen];               // Normally 4 bytes
318
319         // Receive and iterate until complete
320         recvIter(recvStr, strLen);
321
322         string retVal(recvStr, strLen);
323         delete[] recvStr;
324
325         return retVal;
326 }
327
328
329 // Create a driver object, e.g. LifxLightBulb
330 void IoTSlave::createObject() {
331
332         writeToFile("Creating a driver object now...");
333         // Receiving object info
334         objectName = recvString(); sendAck();
335         writeToFile("=> Driver object name: " + objectName);
336         objectClassName = recvString(); sendAck();
337         writeToFile("=> Driver object class name: " + objectClassName);
338         objectInterfaceName = recvString(); sendAck();
339         writeToFile("=> Driver object interface name: " + objectInterfaceName);
340         objectSkelClass = recvString(); sendAck();
341         writeToFile("=> Driver object skeleton class name: " + objectSkelClass);
342         objectRegPort = recvInteger(); sendAck();
343         writeToFile("=> Driver object registry port: " + to_string(objectRegPort));
344         objectStubPort = recvInteger(); sendAck();
345         writeToFile("=> Driver object stub port: " + to_string(objectStubPort));
346         int numOfArgs = recvInteger(); sendAck();
347         for (int i = 0; i < numOfArgs; i++) {
348                 string arg = recvString(); sendAck();
349                 args.push_back(arg);
350                 writeToFile("==> Got argument: " + arg);
351         }
352         for (int i = 0; i < numOfArgs; i++) {
353                 string argClass = recvString(); sendAck();
354                 argClasses.push_back(argClass);
355                 writeToFile("==> Got argument class: " + argClass);
356         }
357         // We are just receiving object information here
358         // Instantiation will be done when IoTDeviceAddress has been sent
359 }
360
361
362 // Create a new IoTSet object to hold objects
363 void IoTSlave::createNewIoTSet() {
364
365         objectFieldName = recvString(); sendAck();
366         // Instantiating new IoTSet object
367         isetObject = new unordered_set<void*>();
368         writeToFile("Creating new IoTSet for field: " + objectFieldName);
369 }
370
371
372 // Get IoTDeviceAddress object reference and put it inside IoTSet object
373 void IoTSlave::getDeviceIoTSetObject() {
374
375         writeToFile("Getting IoTDeviceAddress... ");
376         // Get the IoTDeviceAddress info
377         hostAddress = recvString(); sendAck();
378         writeToFile("=> Host address: " + hostAddress);
379         int sourcePort = recvInteger(); sendAck();
380         writeToFile("=> Source port: " + to_string(sourcePort));
381         int destPort = recvInteger(); sendAck();
382         writeToFile("=> Destination port: " + to_string(destPort));
383         bool sourcePortWildCard = (bool) recvInteger(); sendAck();
384         writeToFile("=> Is source port wild card? " + to_string(sourcePortWildCard));
385         bool destPortWildCard = (bool) recvInteger(); sendAck();
386         writeToFile("=> Is destination port wild card? " + to_string(destPortWildCard));
387         // Create IoTDeviceAddress      
388         IoTDeviceAddress* objDeviceAddress = new IoTDeviceAddress(hostAddress, sourcePort, destPort, 
389                 sourcePortWildCard, destPortWildCard);
390         // Insert it into isetObject!
391         isetObject->insert(objDeviceAddress);
392         writeToFile("=> Inserting IoTDeviceAddress into set...");
393         writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
394         // Set flag to true;
395         isDriverObject = true;
396 }
397
398
399 // Get IoTSet object content reference and put it inside IoTSet object
400 // This is basically the stub objects
401 void IoTSlave::getIoTSetObject() {
402
403         writeToFile("Getting IoTSet object... ");
404         // Get the IoTDeviceAddress info
405         hostAddress = recvString(); sendAck();
406         writeToFile("=> Host address: " + hostAddress);
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         objectStubClass = recvString(); sendAck();
414         writeToFile("=> Driver object stub class name: " + objectStubClass);
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 numOfPorts = recvInteger(); sendAck();
420         for (int i = 0; i < numOfPorts; i++) {
421                 int port = recvInteger(); sendAck();
422                 ports.push_back(port);
423                 writeToFile("==> Got a new port: " + to_string(port));
424         }
425         // Create Stub object
426         unordered_map<string,void*>::const_iterator itr = mapObjNameStub.find(objectName);
427         if (itr != mapObjNameStub.end()) {      // Stub has been created earlier
428                 writeToFile("=> Stub has been created! Getting back reference...");
429                 objStubCls = itr->second;
430         } else {        // Instantiate a new stub and map it
431                 writeToFile("=> Stub has not been created! Creating a new stub...");
432                 getObjectHandler(objectStubClass);
433                 instantiateStubObject();
434                 mapObjNameStub.insert(make_pair(objectName,objStubCls));
435                 writeToFile("=> Map has: " + to_string(mapObjNameStub.size()) + " members");
436         }
437         // Insert it into isetObject!
438         isetObject->insert(objStubCls);
439         writeToFile("=> Inserting stub object into set...");
440         writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
441 }
442
443
444 // Reinitialize IoTSet field!
445 void IoTSlave::reinitializeIoTSetField() {
446
447         writeToFile("Reinitialize IoTSet field...");
448         iotsetObject = new IoTSet<void*>(isetObject);
449         // Collect IoTSet field first in a vector
450         vecIoTSet.push_back(iotsetObject);
451
452         // Create object if this is for driver object
453         if (isDriverObject) {
454                 // Instantiate driver object
455                 getObjectHandler(objectClassName);
456                 instantiateDriverObject();
457                 // Instantiate skeleton object
458                 getObjectHandler(objectSkelClass);
459                 instantiateSkelObject();
460         }
461 }
462
463
464 // Invoke init() method in main controller
465 void IoTSlave::invokeInitMethod() {
466
467         writeToFile("Invoke init() method for: " + mainObjectName);
468         // Instantiate main controller object
469         getObjectHandler(mainObjectName);
470         instantiateMainObject();
471
472 }
473
474
475 // Create a main object, e.g. Lifxtest
476 void IoTSlave::createMainObject() {
477
478         mainObjectName = recvString(); sendAck();
479         writeToFile("Creating main object: " + mainObjectName);
480         // Just receive the name of the class object here
481         // We will instantiate the object after we get the set/relation objects
482 }
483
484
485 void IoTSlave::sendAck() {
486
487         int codeAck = (int) ACKNOWLEDGED;
488         sendInteger(codeAck);
489 }
490
491
492 bool IoTSlave::recvEndTransfer() {
493
494         int codeEndTransfer = (int) END_TRANSFER;
495         int recvCode = recvInteger();
496         if (recvCode == codeEndTransfer)
497                 return true;
498         return false;
499 }
500
501
502 void IoTSlave::commIoTMaster() {
503
504         writeToFile("Starting main loop...");
505         // Main iteration/loop
506         while(true) {
507                 IoTCommCode message = (IoTCommCode) recvInteger(); sendAck();
508                 //writeToFile("Message: " + (int) message);
509                 
510                 switch(message) {
511
512                         case CREATE_OBJECT:
513                                 createObject();
514                                 break;
515
516                         case TRANSFER_FILE:
517                                 //transferFile();
518                                 break;
519
520                         case CREATE_MAIN_OBJECT:
521                                 createMainObject();
522                                 break;
523
524                         case CREATE_NEW_IOTSET:
525                                 createNewIoTSet();
526                                 break;
527
528                         case CREATE_NEW_IOTRELATION:
529                                 //createNewIoTRelation();
530                                 break;
531
532                         case GET_IOTSET_OBJECT:
533                                 getIoTSetObject();
534                                 break;
535
536                         case GET_IOTRELATION_FIRST_OBJECT:
537                                 //getIoTRelationFirstObject();
538                                 break;
539
540                         case GET_IOTRELATION_SECOND_OBJECT:
541                                 //getIoTRelationSecondObject();
542                                 break;
543
544                         case REINITIALIZE_IOTSET_FIELD:
545                                 reinitializeIoTSetField();
546                                 break;
547
548                         case REINITIALIZE_IOTRELATION_FIELD:
549                                 //reinitializeIoTRelationField();
550                                 break;
551
552                         case GET_DEVICE_IOTSET_OBJECT:
553                                 getDeviceIoTSetObject();
554                                 break;
555
556                         case GET_ZB_DEV_IOTSET_OBJECT:
557                                 //getZBDevIoTSetObject();
558                                 break;
559
560                         case GET_ADD_IOTSET_OBJECT:
561                                 //getAddIoTSetObject();
562                                 break;
563
564                         case INVOKE_INIT_METHOD:
565                                 invokeInitMethod();
566                                 break;
567
568                         case END_SESSION:
569                                 // END of session
570                                 goto ENDLOOP;
571                                 break;
572
573                         default:
574                                 break;
575                 }
576         }
577         ENDLOOP:
578         writeToFile("End of loop!");
579 }
580
581
582 int main(int argc, char *argv[]) {
583
584         /*string serverAddress = "localhost";
585         int serverPort = 12345;
586         IoTSlave *iotSlave = new IoTSlave(serverAddress, serverPort);
587         cout << "Connection established with server!" << endl;
588         int intReceived = iotSlave->recvInteger();
589         cout << "Integer received: " << intReceived << endl;
590         cout << "Integer sent back + 1: " << intReceived++ << endl;
591         iotSlave->sendInteger(intReceived);
592         string strSend = "test sending string";
593         cout << "Sending string: " << strSend << endl;  
594         iotSlave->sendString(strSend);
595         cout << "Received string: " << iotSlave->recvString() << endl;*/
596         
597         string serverAddress = argv[1];
598         char* servPort = argv[2];
599         int serverPort = atoi(servPort);
600         string strObjName = argv[3];
601         IoTSlave *iotSlave = new IoTSlave(serverAddress, serverPort, strObjName);
602         iotSlave->sendAck();
603         iotSlave->commIoTMaster();
604         
605         return 0;
606 }