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 void IoTSlave::openFile(string fileName) {
101 log.open(FILEPATH + fileName + FILEEXT);
105 void IoTSlave::writeToFile(string logMsg) {
107 log << "IoTSlave: " << logMsg << endl;
111 void IoTSlave::closeFile() {
117 void IoTSlave::getObjectHandler(string objectClassName) {
120 string strObj = FILEPATH + objectClassName + SOEXT;
121 void* handle = dlopen (strObj.c_str(), RTLD_LAZY);
123 fputs (dlerror(), stderr);
124 writeToFile("Error handling object!");
127 writeToFile("Object handled!");
129 string createFunction = CREATEFUNCTION + objectClassName;
130 create_object = (create_t*) dlsym(handle, createFunction.c_str());
131 const char* dlsym_error = dlerror();
133 cerr << "Cannot load symbol create: " << dlsym_error << '\n';
134 writeToFile("Cannot load symbol create!");
137 writeToFile("Object factory created for " + objectClassName);
139 string destroyFunction = DESTROYFUNCTION + objectClassName;
140 destroy_object = (destroy_t*) dlsym(handle, destroyFunction.c_str());
141 dlsym_error = dlerror();
143 cerr << "Cannot load symbol destroy: " << dlsym_error << '\n';
144 writeToFile("Cannot load symbol destroy!");
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();
153 cerr << "Cannot load symbol init: " << dlsym_error << '\n';
154 writeToFile("Cannot load symbol init!");
157 writeToFile("Object initializer created for " + objectClassName);
161 // Run init_object function
162 void IoTSlave::runInitObject(IoTSlave* iotslave) {
164 iotslave->init_object(iotslave->objMainCls);
168 // Instantiate main object!
169 // Use handler obtained by getObjectHandler() and instantiate object!
170 void IoTSlave::instantiateMainObject() {
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
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);
184 //thread th1 (&IoTSlave::runInitObject, this, this);
186 writeToFile("Initialized object " + mainObjectName);
190 // Instantiate driver object!
191 // Use handler obtained by getObjectHandler() and instantiate object!
192 void IoTSlave::instantiateDriverObject() {
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
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]);
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];
216 writeToFile("Object created for " + objectClassName);
220 // Use handler obtained by getObjectHandler() and instantiate skeleton object!
221 void IoTSlave::instantiateSkelObject() {
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);
234 // Use handler obtained by getObjectHandler() and instantiate stub object!
235 void IoTSlave::instantiateStubObject() {
237 void* params[STUBPARAMSIZE];
238 params[0] = &objectStubPort;
239 params[1] = &hostAddress;
240 string callbackAddress = LOCALHOST;
241 params[2] = &callbackAddress;
247 writeToFile("Stub Object " + objectStubClass + " created for " + objectClassName);
248 objStubCls = create_object(params);
253 string IoTSlave::getServerAddress() {
255 return serverAddress;
259 int IoTSlave::getServerPort() {
265 string IoTSlave::getObjectName() {
271 void IoTSlave::sendInteger(int intSend) {
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));
282 int IoTSlave::recvInteger() {
284 int toBeReceived = sizeof(int);
285 char recvInt[sizeof(int)]; // Normally 4 bytes
287 // Receive and iterate until complete
288 recvIter(recvInt, toBeReceived);
291 byteToInt(&retVal, recvInt);
297 void IoTSlave::sendString(string strSend) {
299 // Send the length first
300 int strLen = strSend.length();
304 char* chStrSend = new char[strLen];
305 strcpy(chStrSend, strSend.c_str());
306 void* toSend = chStrSend;
307 socket->send(toSend, strLen);
313 string IoTSlave::recvString() {
315 // Get the length of string first
316 int strLen = recvInteger();
317 char* recvStr = new char[strLen]; // Normally 4 bytes
319 // Receive and iterate until complete
320 recvIter(recvStr, strLen);
322 string retVal(recvStr, strLen);
329 // Create a driver object, e.g. LifxLightBulb
330 void IoTSlave::createObject() {
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();
350 writeToFile("==> Got argument: " + arg);
352 for (int i = 0; i < numOfArgs; i++) {
353 string argClass = recvString(); sendAck();
354 argClasses.push_back(argClass);
355 writeToFile("==> Got argument class: " + argClass);
357 // We are just receiving object information here
358 // Instantiation will be done when IoTDeviceAddress has been sent
362 // Create a new IoTSet object to hold objects
363 void IoTSlave::createNewIoTSet() {
365 objectFieldName = recvString(); sendAck();
366 // Instantiating new IoTSet object
367 isetObject = new unordered_set<void*>();
368 writeToFile("Creating new IoTSet for field: " + objectFieldName);
372 // Get IoTDeviceAddress object reference and put it inside IoTSet object
373 void IoTSlave::getDeviceIoTSetObject() {
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)!");
395 isDriverObject = true;
399 // Get IoTSet object content reference and put it inside IoTSet object
400 // This is basically the stub objects
401 void IoTSlave::getIoTSetObject() {
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));
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");
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)!");
444 // Reinitialize IoTSet field!
445 void IoTSlave::reinitializeIoTSetField() {
447 writeToFile("Reinitialize IoTSet field...");
448 iotsetObject = new IoTSet<void*>(isetObject);
449 // Collect IoTSet field first in a vector
450 vecIoTSet.push_back(iotsetObject);
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();
464 // Invoke init() method in main controller
465 void IoTSlave::invokeInitMethod() {
467 writeToFile("Invoke init() method for: " + mainObjectName);
468 // Instantiate main controller object
469 getObjectHandler(mainObjectName);
470 instantiateMainObject();
475 // Create a main object, e.g. Lifxtest
476 void IoTSlave::createMainObject() {
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
485 void IoTSlave::sendAck() {
487 int codeAck = (int) ACKNOWLEDGED;
488 sendInteger(codeAck);
492 bool IoTSlave::recvEndTransfer() {
494 int codeEndTransfer = (int) END_TRANSFER;
495 int recvCode = recvInteger();
496 if (recvCode == codeEndTransfer)
502 void IoTSlave::commIoTMaster() {
504 writeToFile("Starting main loop...");
505 // Main iteration/loop
507 IoTCommCode message = (IoTCommCode) recvInteger(); sendAck();
508 //writeToFile("Message: " + (int) message);
520 case CREATE_MAIN_OBJECT:
524 case CREATE_NEW_IOTSET:
528 case CREATE_NEW_IOTRELATION:
529 //createNewIoTRelation();
532 case GET_IOTSET_OBJECT:
536 case GET_IOTRELATION_FIRST_OBJECT:
537 //getIoTRelationFirstObject();
540 case GET_IOTRELATION_SECOND_OBJECT:
541 //getIoTRelationSecondObject();
544 case REINITIALIZE_IOTSET_FIELD:
545 reinitializeIoTSetField();
548 case REINITIALIZE_IOTRELATION_FIELD:
549 //reinitializeIoTRelationField();
552 case GET_DEVICE_IOTSET_OBJECT:
553 getDeviceIoTSetObject();
556 case GET_ZB_DEV_IOTSET_OBJECT:
557 //getZBDevIoTSetObject();
560 case GET_ADD_IOTSET_OBJECT:
561 //getAddIoTSetObject();
564 case INVOKE_INIT_METHOD:
578 writeToFile("End of loop!");
582 int main(int argc, char *argv[]) {
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;*/
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);
603 iotSlave->commIoTMaster();