4 #include "IoTSlave.hpp"
6 IoTSlave::IoTSlave(string _serverAddress, int _serverPort, string _objectName) {
8 serverAddress = _serverAddress;
9 serverPort = _serverPort;
10 objectName = _objectName;
11 socket = new TCPSocket(serverAddress, serverPort);
13 writeToFile("IoTSlave object created! Connection established!");
17 IoTSlave::~IoTSlave() {
23 /*if (objMainCls != NULL) {
27 if (objSkelCls != NULL) {
31 for (IoTSet<void*>* iotset : vecIoTSet) {
39 // Private helper functions
40 int* IoTSlave::byteToInt(int* result, char* bytes) {
43 memcpy(&i, bytes, sizeof(int));
50 char* IoTSlave::intToByteArray(int i, char* bytes) {
52 int iInvert = htobe32(i);
53 memcpy(bytes, &iInvert, sizeof(int));
59 void* IoTSlave::getObjectConverted(void* retObj, string object, string objectClass) {
61 // Returning new objects in heap - so we need to delete them afterwards
62 if (objectClass.compare(STRINGCLASS) == 0) {
63 string* retStr = new string(object);
65 } else if (objectClass.compare(INTCLASS) == 0) {
66 int* retInt = new int(atoi(object.c_str()));
68 } else // return NULL if class is not identifiable
75 // Factoring out iteration
76 char* IoTSlave::recvIter(char* recvBuffer, int recvLen) {
78 int bytesReceived = 0; // Bytes read on each recv()
79 int totalBytesReceived = 0; // Total bytes read
81 while (totalBytesReceived < recvLen) {
82 // Receive up to the buffer size bytes from the sender
83 if ((bytesReceived = (socket->recv(recvBuffer, RCVBUFSIZE))) <= 0) {
84 string errMsg = "IoTSlave: Unable to read!";
85 cerr << errMsg << endl;
89 totalBytesReceived += bytesReceived; // Keep tally of total bytes
96 // Factoring out iteration
97 char* IoTSlave::recvFileIter(char* recvBuffer, int recvLen) {
99 int bytesReceived = 0; // Bytes read on each recv()
100 int totalBytesReceived = 0; // Total bytes read
102 while (totalBytesReceived < recvLen) {
103 // Receive up to the buffer size bytes from the sender
104 if ((bytesReceived = (socket->recv(recvBuffer, recvLen))) <= 0) {
105 string errMsg = "IoTSlave: Unable to read!";
106 cerr << errMsg << endl;
110 totalBytesReceived += bytesReceived; // Keep tally of total bytes
117 void IoTSlave::openFile(string fileName) {
119 log.open(LOGFILEPATH + fileName + FILEEXT);
123 void IoTSlave::writeToFile(string logMsg) {
125 log << "IoTSlave: " << logMsg << endl;
129 void IoTSlave::closeFile() {
135 void IoTSlave::getObjectHandler(string objectClassName) {
138 string strObj = FILEPATH + objectClassName + SOEXT;
139 void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
141 fputs (dlerror(), stderr);
142 writeToFile("Error handling object!");
145 writeToFile("Object handled!");
147 string createFunction = CREATEFUNCTION + objectClassName;
148 create_object = (create_t*) dlsym(handle, createFunction.c_str());
149 const char* dlsym_error = dlerror();
151 cerr << "Cannot load symbol create: " << dlsym_error << '\n';
152 writeToFile("Cannot load symbol create!");
155 writeToFile("Object factory created for " + objectClassName);
157 string destroyFunction = DESTROYFUNCTION + objectClassName;
158 destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
159 dlsym_error = dlerror();
161 cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
162 writeToFile("Cannot load symbol destroy!");
165 writeToFile("Object destroyer created for " + objectClassName);
166 // Create initializer
167 string initFunction = INITFUNCTION + objectClassName;
168 init_object = (init_t*) dlsym(handle, initFunction.c_str());
169 dlsym_error = dlerror();
171 cerr << "Cannot load symbol init: " << dlsym_error << '\n';
172 writeToFile("Cannot load symbol init!");
175 writeToFile("Object initializer created for " + objectClassName);
179 // Run init_object function
180 void IoTSlave::runInitObject(IoTSlave* iotslave) {
182 iotslave->init_object(iotslave->objMainCls);
186 // Instantiate main object!
187 // Use handler obtained by getObjectHandler() and instantiate object!
188 void IoTSlave::instantiateMainObject() {
190 // IoTSet + IoTRelation objects
191 int paramSize = vecIoTSet.size() + vecIoTRel.size();
192 void* params[paramSize];
194 for(int i=0; i<vecIoTSet.size(); i++) {
195 params[j] = vecIoTSet[i]; j++;
197 writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
198 for(int i=0; i<vecIoTRel.size(); i++) {
199 params[j] = vecIoTRel[i]; j++;
201 writeToFile("Vector IoTRelation size: " + to_string(vecIoTRel.size()));
202 objMainCls = create_object(params);
203 writeToFile("Object created for " + mainObjectName);
204 init_object(objMainCls);
205 // TODO: Maybe we want to change this into multithreading at some point
206 //thread th1 (&IoTSlave::runInitObject, this, this);
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 recvIter(recvInt, toBeReceived);
314 byteToInt(&retVal, recvInt);
320 void IoTSlave::sendString(string strSend) {
322 // Send the length first
323 int strLen = strSend.length();
327 char* chStrSend = new char[strLen];
328 strcpy(chStrSend, strSend.c_str());
329 void* toSend = chStrSend;
330 socket->send(toSend, strLen);
336 string IoTSlave::recvString() {
338 // Get the length of string first
339 int strLen = recvInteger();
340 char* recvStr = new char[strLen];
342 // Receive and iterate until complete
343 recvIter(recvStr, strLen);
345 string retVal(recvStr, strLen);
352 // Receive file from IoTMaster
353 void IoTSlave::transferFile() {
355 string fileName = recvFile(); sendAck();
356 //unzipFile(fileName);
360 void IoTSlave::unzipFile(string fileName) {
362 // Unzip file (what we are sending is a zipped file)
363 // TODO: perhaps we need to replace this with libzip or zlib later
364 writeToFile("Unzipping file!");
365 string chmodCmd = FILEPATH + fileName + SHELL;
366 thread th1 (std::system, chmodCmd.c_str());
368 writeToFile("Finished unzipping file!");
372 string IoTSlave::recvFile() {
374 // Get the length of string first
375 string fileName = recvString(); sendAck();
376 int fileLen = recvInteger(); sendAck();
377 writeToFile("Receiving file " + fileName + " with length " + to_string(fileLen) + " bytes...");
378 char* recvFil = new char[fileLen];
379 // Receive and iterate until complete
380 recvFileIter(recvFil, fileLen);
383 fileStream.open(FILEPATH + fileName);
385 writeToFile("Error opening file: " + FILEPATH + fileName);
388 fileStream.write(recvFil, fileLen);
395 // Create a driver object, e.g. LifxLightBulb
396 void IoTSlave::createObject() {
398 writeToFile("Creating a driver object now...");
399 // Receiving object info
400 objectName = recvString(); sendAck();
401 writeToFile("=> Driver object name: " + objectName);
402 objectClassName = recvString(); sendAck();
403 writeToFile("=> Driver object class name: " + objectClassName);
404 objectInterfaceName = recvString(); sendAck();
405 writeToFile("=> Driver object interface name: " + objectInterfaceName);
406 objectSkelClass = recvString(); sendAck();
407 writeToFile("=> Driver object skeleton class name: " + objectSkelClass);
408 objectRegPort = recvInteger(); sendAck();
409 writeToFile("=> Driver object registry port: " + to_string(objectRegPort));
410 objectStubPort = recvInteger(); sendAck();
411 writeToFile("=> Driver object stub port: " + to_string(objectStubPort));
412 int numOfArgs = recvInteger(); sendAck();
413 writeToFile("=> Number of args: " + to_string(numOfArgs));
414 for (int i = 0; i < numOfArgs; i++) {
415 string arg = recvString(); sendAck();
417 writeToFile("==> Got argument: " + arg);
419 for (int i = 0; i < numOfArgs; i++) {
420 string argClass = recvString(); sendAck();
421 argClasses.push_back(argClass);
422 writeToFile("==> Got argument class: " + argClass);
424 // We are just receiving object information here
425 // Instantiation will be done when IoTDeviceAddress has been sent
429 // Create a new IoTSet object to hold objects
430 void IoTSlave::createNewIoTSet() {
432 objectFieldName = recvString(); sendAck();
433 // Instantiating new IoTSet object
434 isetObject = new unordered_set<void*>();
435 writeToFile("Creating new IoTSet for field: " + objectFieldName);
439 // Get IoTDeviceAddress object reference and put it inside IoTSet object
440 void IoTSlave::getDeviceIoTSetObject() {
442 writeToFile("Getting IoTDeviceAddress... ");
443 // Get the IoTDeviceAddress info
444 hostAddress = recvString(); sendAck();
445 writeToFile("=> Host address: " + hostAddress);
446 int sourcePort = recvInteger(); sendAck();
447 writeToFile("=> Source port: " + to_string(sourcePort));
448 int destPort = recvInteger(); sendAck();
449 writeToFile("=> Destination port: " + to_string(destPort));
450 bool sourcePortWildCard = (bool) recvInteger(); sendAck();
451 writeToFile("=> Is source port wild card? " + to_string(sourcePortWildCard));
452 bool destPortWildCard = (bool) recvInteger(); sendAck();
453 writeToFile("=> Is destination port wild card? " + to_string(destPortWildCard));
454 // Create IoTDeviceAddress
455 IoTDeviceAddress* objDeviceAddress = new IoTDeviceAddress(hostAddress, sourcePort, destPort,
456 sourcePortWildCard, destPortWildCard);
457 // Insert it into isetObject!
458 isetObject->insert(objDeviceAddress);
459 writeToFile("=> Inserting IoTDeviceAddress into set...");
460 writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
464 void IoTSlave::createStub() {
465 // Create Stub object
466 unordered_map<string,void*>::const_iterator itr = mapObjNameStub.find(objectName);
467 if (itr != mapObjNameStub.end()) { // Stub has been created earlier
468 writeToFile("=> Stub has been created! Getting back reference...");
469 objStubCls = itr->second;
470 } else { // Instantiate a new stub and map it
471 writeToFile("=> Stub has not been created! Creating a new stub...");
472 getObjectHandler(objectStubClass);
473 instantiateStubObject();
474 mapObjNameStub.insert(make_pair(objectName,objStubCls));
475 writeToFile("=> Map has: " + to_string(mapObjNameStub.size()) + " members");
480 // Get IoTSet object content reference and put it inside IoTSet object
481 // This is basically the stub objects
482 void IoTSlave::getIoTSetObject() {
484 writeToFile("Getting IoTSet object... ");
485 getIoTSetRelationObject();
487 // Insert it into isetObject!
488 isetObject->insert(objStubCls);
489 writeToFile("=> Inserting stub object into set...");
490 writeToFile("==> Now we have " + to_string(isetObject->size()) + " object(s)!");
494 // Reinitialize IoTSet field!
495 void IoTSlave::reinitializeIoTSetField() {
497 writeToFile("Reinitialize IoTSet field...");
498 iotsetObject = new IoTSet<void*>(isetObject);
499 // Collect IoTSet field first in a vector
500 vecIoTSet.push_back(iotsetObject);
505 // Instantiate driver object
506 void IoTSlave::createDriverObject() {
508 // Instantiate driver object
509 getObjectHandler(objectClassName);
510 instantiateDriverObject();
511 // Instantiate skeleton object
512 getObjectHandler(objectSkelClass);
513 instantiateSkelObject();
517 // Create a new IoTRelation object to hold objects
518 void IoTSlave::createNewIoTRelation() {
520 objectFieldName = recvString(); sendAck();
521 // Instantiating new IoTSet object
522 irelObject = new unordered_multimap<void*,void*>();
523 writeToFile("Creating new IoTRelation for field: " + objectFieldName);
527 // Get IoTRelation object
528 void IoTSlave::getIoTSetRelationObject() {
530 hostAddress = recvString(); sendAck();
531 writeToFile("=> Host address: " + hostAddress);
532 objectName = recvString(); sendAck();
533 writeToFile("=> Driver object name: " + objectName);
534 objectClassName = recvString(); sendAck();
535 writeToFile("=> Driver object class name: " + objectClassName);
536 objectInterfaceName = recvString(); sendAck();
537 writeToFile("=> Driver object interface name: " + objectInterfaceName);
538 objectStubClass = recvString(); sendAck();
539 writeToFile("=> Driver object stub class name: " + objectStubClass);
540 objectRegPort = recvInteger(); sendAck();
541 writeToFile("=> Driver object registry port: " + to_string(objectRegPort));
542 objectStubPort = recvInteger(); sendAck();
543 writeToFile("=> Driver object stub port: " + to_string(objectStubPort));
547 // Get the first object of IoTRelation
548 void IoTSlave::getIoTRelationFirstObject() {
550 writeToFile("Getting IoTRelation first object... ");
551 getIoTSetRelationObject();
553 // Hold the first object of IoTRelation
554 irelFirstObject = objStubCls;
555 writeToFile("=> Holding first stub object...");
559 // Get the second object of IoTRelation
560 void IoTSlave::getIoTRelationSecondObject() {
562 writeToFile("Getting IoTRelation second object... ");
563 getIoTSetRelationObject();
565 // Hold the first object of IoTRelation
566 irelSecondObject = objStubCls;
567 writeToFile("=> Holding second stub object...");
568 pair<void*,void*>* iotrelPair = new pair<void*,void*>(irelFirstObject, irelSecondObject);
569 writeToFile("=> Creating a pair of stub objects and inserting into IoTRelation object...");
570 irelObject->insert(*iotrelPair);
574 // Reinitialize IoTRelation
575 void IoTSlave::reinitializeIoTRelationField() {
577 writeToFile("Reinitialize IoTRelation field...");
578 iotrelObject = new IoTRelation<void*,void*>(irelObject);
579 // Collect IoTSet field first in a vector
580 vecIoTRel.push_back(iotrelObject);
584 // Invoke init() method in main controller
585 void IoTSlave::invokeInitMethod() {
587 writeToFile("Invoke init() method for: " + mainObjectName);
588 // Instantiate main controller object
589 getObjectHandler(mainObjectName);
590 instantiateMainObject();
595 // Create a main object, e.g. Lifxtest
596 void IoTSlave::createMainObject() {
598 mainObjectName = recvString(); sendAck();
599 writeToFile("Creating main object: " + mainObjectName);
600 // Just receive the name of the class object here
601 // We will instantiate the object after we get the set/relation objects
605 void IoTSlave::sendAck() {
607 int codeAck = (int) ACKNOWLEDGED;
608 sendInteger(codeAck);
612 bool IoTSlave::recvEndTransfer() {
614 int codeEndTransfer = (int) END_TRANSFER;
615 int recvCode = recvInteger();
616 if (recvCode == codeEndTransfer)
622 void IoTSlave::commIoTMaster() {
624 writeToFile("Starting main loop...");
625 // Main iteration/loop
627 IoTCommCode message = (IoTCommCode) recvInteger();
628 writeToFile("Message: " + to_string(message));
641 case CREATE_MAIN_OBJECT:
645 case CREATE_NEW_IOTSET:
649 case CREATE_NEW_IOTRELATION:
650 createNewIoTRelation();
653 case GET_IOTSET_OBJECT:
657 case GET_IOTRELATION_FIRST_OBJECT:
658 getIoTRelationFirstObject();
661 case GET_IOTRELATION_SECOND_OBJECT:
662 getIoTRelationSecondObject();
665 case REINITIALIZE_IOTSET_FIELD:
666 reinitializeIoTSetField();
669 case REINITIALIZE_IOTRELATION_FIELD:
670 reinitializeIoTRelationField();
673 case GET_DEVICE_IOTSET_OBJECT:
674 getDeviceIoTSetObject();
677 case GET_ZB_DEV_IOTSET_OBJECT:
678 // TODO: Support ZigBee in the future
679 //getZBDevIoTSetObject();
682 case GET_ADD_IOTSET_OBJECT:
683 //getAddIoTSetObject();
686 case INVOKE_INIT_METHOD:
690 case CREATE_DRIVER_OBJECT:
691 createDriverObject();
704 writeToFile("End of loop!");
708 int main(int argc, char *argv[]) {
710 string serverAddress = argv[1];
711 char* servPort = argv[2];
712 int serverPort = atoi(servPort);
713 string strObjName = argv[3];
714 IoTSlave *iotSlave = new IoTSlave(serverAddress, serverPort, strObjName);
716 iotSlave->commIoTMaster();