4 #include "IoTSlave.hpp"
6 IoTSlave::IoTSlave(string _serverAddress, int _serverPort, string _objectName) {
8 //isDriverObject = false; // Default to false
9 serverAddress = _serverAddress;
10 serverPort = _serverPort;
11 objectName = _objectName;
12 socket = new TCPSocket(serverAddress, serverPort);
14 writeToFile("IoTSlave object created! Connection established!");
18 IoTSlave::~IoTSlave() {
24 /*if (objMainCls != NULL) {
28 if (objSkelCls != NULL) {
32 for (IoTSet<void*>* iotset : vecIoTSet) {
40 // Private helper functions
41 int* IoTSlave::byteToInt(int* result, char* bytes) {
44 memcpy(&i, bytes, sizeof(int));
51 char* IoTSlave::intToByteArray(int i, char* bytes) {
53 int iInvert = htobe32(i);
54 memcpy(bytes, &iInvert, sizeof(int));
60 void* IoTSlave::getObjectConverted(void* retObj, string object, string objectClass) {
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);
66 } else if (objectClass.compare(INTCLASS) == 0) {
67 int* retInt = new int(atoi(object.c_str()));
69 } else // return NULL if class is not identifiable
76 // Factoring out iteration
77 char* IoTSlave::recvIter(char* recvBuffer, int recvLen) {
79 int bytesReceived = 0; // Bytes read on each recv()
80 int totalBytesReceived = 0; // Total bytes read
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;
90 totalBytesReceived += bytesReceived; // Keep tally of total bytes
97 // Factoring out iteration
98 char* IoTSlave::recvFileIter(char* recvBuffer, int recvLen) {
100 int bytesReceived = 0; // Bytes read on each recv()
101 int totalBytesReceived = 0; // Total bytes read
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;
111 totalBytesReceived += bytesReceived; // Keep tally of total bytes
118 void IoTSlave::openFile(string fileName) {
120 log.open(FILEPATH + fileName + FILEEXT);
124 void IoTSlave::writeToFile(string logMsg) {
126 log << "IoTSlave: " << logMsg << endl;
130 void IoTSlave::closeFile() {
136 void IoTSlave::getObjectHandler(string objectClassName) {
139 string strObj = FILEPATH + objectClassName + SOEXT;
140 void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
142 fputs (dlerror(), stderr);
143 writeToFile("Error handling object!");
146 writeToFile("Object handled!");
148 string createFunction = CREATEFUNCTION + objectClassName;
149 create_object = (create_t*) dlsym(handle, createFunction.c_str());
150 const char* dlsym_error = dlerror();
152 cerr << "Cannot load symbol create: " << dlsym_error << '\n';
153 writeToFile("Cannot load symbol create!");
156 writeToFile("Object factory created for " + objectClassName);
158 string destroyFunction = DESTROYFUNCTION + objectClassName;
159 destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
160 dlsym_error = dlerror();
162 cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
163 writeToFile("Cannot load symbol destroy!");
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();
172 cerr << "Cannot load symbol init: " << dlsym_error << '\n';
173 writeToFile("Cannot load symbol init!");
176 writeToFile("Object initializer created for " + objectClassName);
180 // Run init_object function
181 void IoTSlave::runInitObject(IoTSlave* iotslave) {
183 iotslave->init_object(iotslave->objMainCls);
187 // Instantiate main object!
188 // Use handler obtained by getObjectHandler() and instantiate object!
189 void IoTSlave::instantiateMainObject() {
191 // IoTSet + IoTRelation objects
192 int paramSize = vecIoTSet.size() + vecIoTRel.size();
193 void* params[paramSize];
195 for(int i=0; i<vecIoTSet.size(); i++) {
196 params[j] = vecIoTSet[i]; j++;
198 writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
199 for(int i=0; i<vecIoTRel.size(); i++) {
200 params[j] = vecIoTRel[i]; j++;
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);
208 //thread th1 (&IoTSlave::runInitObject, this, this);
210 writeToFile("Initialized object " + mainObjectName);
214 // Instantiate driver object!
215 // Use handler obtained by getObjectHandler() and instantiate object!
216 void IoTSlave::instantiateDriverObject() {
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
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]);
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];
240 writeToFile("Object created for " + objectClassName);
244 // Use handler obtained by getObjectHandler() and instantiate skeleton object!
245 void IoTSlave::instantiateSkelObject() {
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);
257 // Use handler obtained by getObjectHandler() and instantiate stub object!
258 void IoTSlave::instantiateStubObject() {
260 void* params[STUBPARAMSIZE];
261 params[0] = &objectStubPort;
262 params[1] = &objectRegPort;
263 params[2] = &hostAddress;
268 writeToFile("Stub Object " + objectStubClass + " created for " + objectClassName);
269 writeToFile("Success 1!");
270 objStubCls = create_object(params);
271 writeToFile("Success 2!");
276 string IoTSlave::getServerAddress() {
278 return serverAddress;
282 int IoTSlave::getServerPort() {
288 string IoTSlave::getObjectName() {
294 void IoTSlave::sendInteger(int intSend) {
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));
305 int IoTSlave::recvInteger() {
307 int toBeReceived = sizeof(int);
308 char recvInt[sizeof(int)]; // Normally 4 bytes
310 // Receive and iterate until complete
311 //writeToFile("Receiving Integer! Size: " + to_string(toBeReceived));
312 recvIter(recvInt, toBeReceived);
315 byteToInt(&retVal, recvInt);
321 void IoTSlave::sendString(string strSend) {
323 // Send the length first
324 int strLen = strSend.length();
328 char* chStrSend = new char[strLen];
329 strcpy(chStrSend, strSend.c_str());
330 void* toSend = chStrSend;
331 socket->send(toSend, strLen);
337 string IoTSlave::recvString() {
339 // Get the length of string first
340 int strLen = recvInteger();
341 char* recvStr = new char[strLen];
343 // Receive and iterate until complete
344 //writeToFile("Receiving String! Size: " + to_string(strLen));
345 recvIter(recvStr, strLen);
347 string retVal(recvStr, strLen);
354 // Receive file from IoTMaster
355 void IoTSlave::transferFile() {
357 string fileName = recvFile(); sendAck();
358 //unzipFile(fileName);
362 void IoTSlave::unzipFile(string fileName) {
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());
371 writeToFile("Finished unzipping file!");
375 string IoTSlave::recvFile() {
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);
386 fileStream.open(FILEPATH + fileName);
388 writeToFile("Error opening file: " + FILEPATH + fileName);
391 fileStream.write(recvFil, fileLen);
394 // TODO: Experimental
395 //string chmodCmd = FILEPATH + fileName + SHELL;
396 //execv(chmodCmd.c_str(), 0);
401 // Create a driver object, e.g. LifxLightBulb
402 void IoTSlave::createObject() {
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();
423 writeToFile("==> Got argument: " + arg);
425 for (int i = 0; i < numOfArgs; i++) {
426 string argClass = recvString(); sendAck();
427 argClasses.push_back(argClass);
428 writeToFile("==> Got argument class: " + argClass);
430 // We are just receiving object information here
431 // Instantiation will be done when IoTDeviceAddress has been sent
435 // Create a new IoTSet object to hold objects
436 void IoTSlave::createNewIoTSet() {
438 objectFieldName = recvString(); sendAck();
439 // Instantiating new IoTSet object
440 isetObject = new unordered_set<void*>();
441 writeToFile("Creating new IoTSet for field: " + objectFieldName);
445 // Get IoTDeviceAddress object reference and put it inside IoTSet object
446 void IoTSlave::getDeviceIoTSetObject() {
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)!");
468 //isDriverObject = true;
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");
488 // Get IoTSet object content reference and put it inside IoTSet object
489 // This is basically the stub objects
490 void IoTSlave::getIoTSetObject() {
492 writeToFile("Getting IoTSet object... ");
493 getIoTSetRelationObject();
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)!");
502 // Reinitialize IoTSet field!
503 void IoTSlave::reinitializeIoTSetField() {
505 writeToFile("Reinitialize IoTSet field...");
506 iotsetObject = new IoTSet<void*>(isetObject);
507 // Collect IoTSet field first in a vector
508 vecIoTSet.push_back(iotsetObject);
513 // Instantiate driver object
514 void IoTSlave::createDriverObject() {
516 // Instantiate driver object
517 getObjectHandler(objectClassName);
518 instantiateDriverObject();
519 // Instantiate skeleton object
520 getObjectHandler(objectSkelClass);
521 instantiateSkelObject();
525 // Create a new IoTRelation object to hold objects
526 void IoTSlave::createNewIoTRelation() {
528 objectFieldName = recvString(); sendAck();
529 // Instantiating new IoTSet object
530 irelObject = new unordered_multimap<void*,void*>();
531 writeToFile("Creating new IoTRelation for field: " + objectFieldName);
535 // Get IoTRelation object
536 void IoTSlave::getIoTSetRelationObject() {
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));
555 // Get the first object of IoTRelation
556 void IoTSlave::getIoTRelationFirstObject() {
558 writeToFile("Getting IoTRelation first object... ");
559 getIoTSetRelationObject();
561 // Hold the first object of IoTRelation
562 irelFirstObject = objStubCls;
563 writeToFile("=> Holding first stub object...");
567 // Get the second object of IoTRelation
568 void IoTSlave::getIoTRelationSecondObject() {
570 writeToFile("Getting IoTRelation second object... ");
571 getIoTSetRelationObject();
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);
582 // Reinitialize IoTRelation
583 void IoTSlave::reinitializeIoTRelationField() {
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);
592 // Invoke init() method in main controller
593 void IoTSlave::invokeInitMethod() {
595 writeToFile("Invoke init() method for: " + mainObjectName);
596 // Instantiate main controller object
597 getObjectHandler(mainObjectName);
598 instantiateMainObject();
603 // Create a main object, e.g. Lifxtest
604 void IoTSlave::createMainObject() {
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
613 void IoTSlave::sendAck() {
615 int codeAck = (int) ACKNOWLEDGED;
616 sendInteger(codeAck);
620 bool IoTSlave::recvEndTransfer() {
622 int codeEndTransfer = (int) END_TRANSFER;
623 int recvCode = recvInteger();
624 if (recvCode == codeEndTransfer)
630 void IoTSlave::commIoTMaster() {
632 writeToFile("Starting main loop...");
633 // Main iteration/loop
635 IoTCommCode message = (IoTCommCode) recvInteger();
636 writeToFile("Message: " + to_string(message));
649 case CREATE_MAIN_OBJECT:
653 case CREATE_NEW_IOTSET:
657 case CREATE_NEW_IOTRELATION:
658 createNewIoTRelation();
661 case GET_IOTSET_OBJECT:
665 case GET_IOTRELATION_FIRST_OBJECT:
666 getIoTRelationFirstObject();
669 case GET_IOTRELATION_SECOND_OBJECT:
670 getIoTRelationSecondObject();
673 case REINITIALIZE_IOTSET_FIELD:
674 reinitializeIoTSetField();
677 case REINITIALIZE_IOTRELATION_FIELD:
678 reinitializeIoTRelationField();
681 case GET_DEVICE_IOTSET_OBJECT:
682 getDeviceIoTSetObject();
685 case GET_ZB_DEV_IOTSET_OBJECT:
686 //getZBDevIoTSetObject();
689 case GET_ADD_IOTSET_OBJECT:
690 //getAddIoTSetObject();
693 case INVOKE_INIT_METHOD:
697 case CREATE_DRIVER_OBJECT:
698 createDriverObject();
711 writeToFile("End of loop!");
715 int main(int argc, char *argv[]) {
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);
723 iotSlave->commIoTMaster();