4 #include "IoTSlave.hpp"
6 #include "Lifxtest.cpp"
8 IoTSlave::IoTSlave(string _serverAddress, int _serverPort, string _objectName) {
10 isDriverObject = false; // Default to false
11 serverAddress = _serverAddress;
12 serverPort = _serverPort;
13 objectName = _objectName;
14 socket = new TCPSocket(serverAddress, serverPort);
16 writeToFile("IoTSlave object created! Connection established!");
20 IoTSlave::~IoTSlave() {
26 /*if (objMainCls != NULL) {
30 if (objSkelCls != NULL) {
34 for (IoTSet<void*>* iotset : vecIoTSet) {
42 // Private helper functions
43 int* IoTSlave::byteToInt(int* result, char* bytes) {
46 memcpy(&i, bytes, sizeof(int));
53 char* IoTSlave::intToByteArray(int i, char* bytes) {
55 int iInvert = htobe32(i);
56 memcpy(bytes, &iInvert, sizeof(int));
62 void* IoTSlave::getObjectConverted(void* retObj, string object, string objectClass) {
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);
68 } else if (objectClass.compare(INTCLASS) == 0) {
69 int* retInt = new int(atoi(object.c_str()));
71 } else // return NULL if class is not identifiable
78 // Factoring out iteration
79 char* IoTSlave::recvIter(char* recvBuffer, int recvLen) {
81 int bytesReceived = 0; // Bytes read on each recv()
82 int totalBytesReceived = 0; // Total bytes read
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;
92 totalBytesReceived += bytesReceived; // Keep tally of total bytes
99 // Factoring out iteration
100 char* IoTSlave::recvFileIter(char* recvBuffer, int recvLen) {
102 int bytesReceived = 0; // Bytes read on each recv()
103 int totalBytesReceived = 0; // Total bytes read
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;
113 totalBytesReceived += bytesReceived; // Keep tally of total bytes
120 void IoTSlave::openFile(string fileName) {
122 log.open(FILEPATH + fileName + FILEEXT);
126 void IoTSlave::writeToFile(string logMsg) {
128 log << "IoTSlave: " << logMsg << endl;
132 void IoTSlave::closeFile() {
138 void IoTSlave::getObjectHandler(string objectClassName) {
141 string strObj = FILEPATH + objectClassName + SOEXT;
142 void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
144 fputs (dlerror(), stderr);
145 writeToFile("Error handling object!");
148 writeToFile("Object handled!");
150 string createFunction = CREATEFUNCTION + objectClassName;
151 create_object = (create_t*) dlsym(handle, createFunction.c_str());
152 const char* dlsym_error = dlerror();
154 cerr << "Cannot load symbol create: " << dlsym_error << '\n';
155 writeToFile("Cannot load symbol create!");
158 writeToFile("Object factory created for " + objectClassName);
160 string destroyFunction = DESTROYFUNCTION + objectClassName;
161 destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
162 dlsym_error = dlerror();
164 cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
165 writeToFile("Cannot load symbol destroy!");
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();
174 cerr << "Cannot load symbol init: " << dlsym_error << '\n';
175 writeToFile("Cannot load symbol init!");
178 writeToFile("Object initializer created for " + objectClassName);
182 // Run init_object function
183 void IoTSlave::runInitObject(IoTSlave* iotslave) {
185 iotslave->init_object(iotslave->objMainCls);
189 // Instantiate main object!
190 // Use handler obtained by getObjectHandler() and instantiate object!
191 void IoTSlave::instantiateMainObject() {
193 // IoTSet + IoTRelation objects
194 int paramSize = vecIoTSet.size() + vecIoTRel.size();
195 void* params[paramSize];
197 for(int i=0; i<vecIoTSet.size(); i++) {
198 params[j] = vecIoTSet[i]; j++;
200 writeToFile("Vector IoTSet size: " + to_string(vecIoTSet.size()));
201 for(int i=0; i<vecIoTRel.size(); i++) {
202 params[j] = vecIoTRel[i]; j++;
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);
210 //thread th1 (&IoTSlave::runInitObject, this, this);
212 writeToFile("Initialized object " + mainObjectName);
216 // Instantiate driver object!
217 // Use handler obtained by getObjectHandler() and instantiate object!
218 void IoTSlave::instantiateDriverObject() {
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
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]);
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];
242 writeToFile("Object created for " + objectClassName);
246 // Use handler obtained by getObjectHandler() and instantiate skeleton object!
247 void IoTSlave::instantiateSkelObject() {
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);
260 // Use handler obtained by getObjectHandler() and instantiate stub object!
261 void IoTSlave::instantiateStubObject() {
263 void* params[STUBPARAMSIZE];
264 params[0] = &objectStubPort;
265 params[1] = &hostAddress;
266 string callbackAddress = LOCALHOST;
267 params[2] = &callbackAddress;
273 writeToFile("Stub Object " + objectStubClass + " created for " + objectClassName);
274 objStubCls = create_object(params);
279 string IoTSlave::getServerAddress() {
281 return serverAddress;
285 int IoTSlave::getServerPort() {
291 string IoTSlave::getObjectName() {
297 void IoTSlave::sendInteger(int intSend) {
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));
308 int IoTSlave::recvInteger() {
310 int toBeReceived = sizeof(int);
311 char recvInt[sizeof(int)]; // Normally 4 bytes
313 // Receive and iterate until complete
314 recvIter(recvInt, toBeReceived);
317 byteToInt(&retVal, recvInt);
323 void IoTSlave::sendString(string strSend) {
325 // Send the length first
326 int strLen = strSend.length();
330 char* chStrSend = new char[strLen];
331 strcpy(chStrSend, strSend.c_str());
332 void* toSend = chStrSend;
333 socket->send(toSend, strLen);
339 string IoTSlave::recvString() {
341 // Get the length of string first
342 int strLen = recvInteger();
343 char* recvStr = new char[strLen];
345 // Receive and iterate until complete
346 recvIter(recvStr, strLen);
348 string retVal(recvStr, strLen);
355 // Receive file from IoTMaster
356 void IoTSlave::transferFile() {
358 string fileName = recvFile(); sendAck();
359 //unzipFile(fileName);
363 void IoTSlave::unzipFile(string fileName) {
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());
372 writeToFile("Finished unzipping file!");
376 string IoTSlave::recvFile() {
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);
387 fileStream.open(FILEPATH + fileName);
389 writeToFile("Error opening file: " + FILEPATH + fileName);
392 fileStream.write(recvFil, fileLen);
395 // TODO: Experimental
396 //string chmodCmd = FILEPATH + fileName + SHELL;
397 //execv(chmodCmd.c_str(), 0);
402 // Create a driver object, e.g. LifxLightBulb
403 void IoTSlave::createObject() {
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();
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);
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();
523 // Create a new IoTRelation object to hold objects
524 void IoTSlave::createNewIoTRelation() {
526 objectFieldName = recvString(); sendAck();
527 // Instantiating new IoTSet object
528 irelObject = new unordered_multimap<void*,void*>();
529 writeToFile("Creating new IoTSet for field: " + objectFieldName);
533 // Get IoTRelation object
534 void IoTSlave::getIoTSetRelationObject() {
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));
559 // Get the first object of IoTRelation
560 void IoTSlave::getIoTRelationFirstObject() {
562 writeToFile("Getting IoTRelation first object... ");
563 getIoTSetRelationObject();
565 // Hold the first object of IoTRelation
566 irelFirstObject = objStubCls;
567 writeToFile("=> Holding first stub object...");
571 // Get the second object of IoTRelation
572 void IoTSlave::getIoTRelationSecondObject() {
574 writeToFile("Getting IoTRelation second object... ");
575 getIoTSetRelationObject();
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);
585 // Reinitialize IoTRelation
586 void IoTSlave::reinitializeIoTRelationField() {
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);
595 // Invoke init() method in main controller
596 void IoTSlave::invokeInitMethod() {
598 writeToFile("Invoke init() method for: " + mainObjectName);
599 // Instantiate main controller object
600 getObjectHandler(mainObjectName);
601 instantiateMainObject();
606 // Create a main object, e.g. Lifxtest
607 void IoTSlave::createMainObject() {
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
616 void IoTSlave::sendAck() {
618 int codeAck = (int) ACKNOWLEDGED;
619 sendInteger(codeAck);
623 bool IoTSlave::recvEndTransfer() {
625 int codeEndTransfer = (int) END_TRANSFER;
626 int recvCode = recvInteger();
627 if (recvCode == codeEndTransfer)
633 void IoTSlave::commIoTMaster() {
635 writeToFile("Starting main loop...");
636 // Main iteration/loop
638 IoTCommCode message = (IoTCommCode) recvInteger();
639 writeToFile("Message: " + to_string(message));
652 case CREATE_MAIN_OBJECT:
656 case CREATE_NEW_IOTSET:
660 case CREATE_NEW_IOTRELATION:
661 createNewIoTRelation();
664 case GET_IOTSET_OBJECT:
668 case GET_IOTRELATION_FIRST_OBJECT:
669 getIoTRelationFirstObject();
672 case GET_IOTRELATION_SECOND_OBJECT:
673 getIoTRelationSecondObject();
676 case REINITIALIZE_IOTSET_FIELD:
677 reinitializeIoTSetField();
680 case REINITIALIZE_IOTRELATION_FIELD:
681 reinitializeIoTRelationField();
684 case GET_DEVICE_IOTSET_OBJECT:
685 getDeviceIoTSetObject();
688 case GET_ZB_DEV_IOTSET_OBJECT:
689 //getZBDevIoTSetObject();
692 case GET_ADD_IOTSET_OBJECT:
693 //getAddIoTSetObject();
696 case INVOKE_INIT_METHOD:
710 writeToFile("End of loop!");
714 int main(int argc, char *argv[]) {
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);
722 iotSlave->commIoTMaster();