1 /** Class IoTRMIComm combines the functionalities
2 * of IoTRMICall and IoTRMIObject to create a single
3 * communication class with two sockets serving one
4 * directional traffic for each.
6 * @author Rahmadi Trimananda <rtrimana @ uci.edu>
10 #ifndef _IOTRMICOMM_HPP__
11 #define _IOTRMICOMM_HPP__
20 #include "IoTSocketServer.hpp"
21 #include "IoTSocketClient.hpp"
22 #include "ConcurrentLinkedListQueue.cpp"
26 std::atomic<bool> didGetMethodBytes(false);
27 std::atomic<bool> didGetReturnBytes(false);
32 mutex remoteCallMutex;
33 mutex sendReturnObjMutex;
40 virtual void sendReturnObj(void* retObj, string type, char* methodBytes) = 0;
41 virtual void sendReturnObj(void* retObj[], string type[], int numRet, char* methodBytes) = 0;
42 int returnLength(void* retObj[], string retCls[], int numRet);
43 char* returnToBytes(void* retObj[], string retCls[], char* retBytes, int numRet);
44 char* getMethodBytes();
45 int getMethodLength();
46 int getObjectIdFromMethod();
47 static int getObjectId(char* packetBytes);
48 static int getMethodId(char* packetBytes);
49 static int getPacketType(char* packetBytes);
50 void** getMethodParams(string paramCls[], int numParam, void* paramObj[], char* methodBytes);
51 void registerSkeleton(int objectId, bool* methodReceived);
52 void registerStub(int objectId, int methodId, bool* retValueReceived);
53 int getObjectIdCounter();
54 void setObjectIdCounter(int objIdCounter);
55 void decrementObjectIdCounter();
57 int methodLength(string paramCls[], void* paramObj[], int numParam);
58 char* methodToBytes(int objectId, int methId, string paramCls[], void* paramObj[],
59 char* method, int numParam);
60 virtual void remoteCall(int objectId, int methodId, string paramCls[],
61 void* paramObj[], int numParam) = 0;
62 void* getReturnValue(string retType, void* retObj);
64 void** getStructObjects(string retType[], int numRet, void* retObj[]);
65 void** getReturnObjects(char* retBytes, string retCls[], int numRet, void* retObj[]);
73 ConcurrentLinkedListQueue methodQueue;
74 ConcurrentLinkedListQueue returnQueue;
75 map<int,bool*> mapSkeletonId;
76 map<string,bool*> mapStubId;
77 int objectIdCounter = std::numeric_limits<int>::max();
81 void wakeUpThreadOnMethodCall(IoTRMIComm* rmiComm);
82 void wakeUpThreadOnReturnValue(IoTRMIComm* rmiComm);
87 IoTRMIComm::IoTRMIComm() {
89 rmiUtil = new IoTRMIUtil();
94 thread th1 (&IoTRMIComm::wakeUpThreadOnMethodCall, this, this);
96 thread th2 (&IoTRMIComm::wakeUpThreadOnReturnValue, this, this);
103 IoTRMIComm::~IoTRMIComm() {
106 if (rmiUtil != NULL) {
113 void IoTRMIComm::wakeUpThreadOnMethodCall(IoTRMIComm* rmiComm) {
117 // Convert back to char*
118 char* queueHead = rmiComm->methodQueue.deQAndGetLength(&methLen);
119 if (queueHead != NULL) {
120 rmiComm->methodBytes = queueHead;
121 rmiComm->methodLen = methLen;
122 //IoTRMIUtil::printBytes(rmiComm->methodBytes, rmiComm->methodLen, false);
123 int currObjId = rmiComm->getObjectId(rmiComm->methodBytes);
124 auto search = rmiComm->mapSkeletonId.find(currObjId);
125 bool* methRecv = search->second;
126 didGetMethodBytes.exchange(false);
128 while(!didGetMethodBytes);
134 void IoTRMIComm::wakeUpThreadOnReturnValue(IoTRMIComm* rmiComm) {
138 // Convert back to char*
139 char* queueHead = rmiComm->returnQueue.deQAndGetLength(&retLen);
140 if (queueHead != NULL) {
141 rmiComm->retValueBytes = queueHead;
142 rmiComm->retValueLen = retLen;
143 //IoTRMIUtil::printBytes(rmiComm->retValueBytes, rmiComm->retValueLen, false);
144 int objectId = rmiComm->getObjectId(rmiComm->retValueBytes);
145 int methodId = rmiComm->getMethodId(rmiComm->retValueBytes);
146 string strKey = to_string(objectId) + "-" + to_string(methodId);
147 auto search = rmiComm->mapStubId.find(strKey);
148 bool* retRecv = search->second;
149 didGetReturnBytes.exchange(false);
151 while(!didGetReturnBytes);
157 // registerSkeleton() registers the skeleton to be woken up
158 void IoTRMIComm::registerSkeleton(int objectId, bool* methodReceived) {
160 lock_guard<mutex> guard(regSkelMutex);
161 mapSkeletonId.insert(make_pair(objectId, methodReceived));
165 // registerStub() registers the skeleton to be woken up
166 void IoTRMIComm::registerStub(int objectId, int methodId, bool* retValueReceived) {
168 lock_guard<mutex> guard(regStubMutex);
169 string strKey = to_string(objectId) + "-" + to_string(methodId);
170 mapStubId.insert(make_pair(strKey, retValueReceived));
174 // getObjectIdCounter() gets object Id counter
175 int IoTRMIComm::getObjectIdCounter() {
177 return objectIdCounter;
181 // setObjectIdCounter() sets object Id counter
182 void IoTRMIComm::setObjectIdCounter(int objIdCounter) {
184 objectIdCounter = objIdCounter;
188 // decrementObjectIdCounter() gets object Id counter
189 void IoTRMIComm::decrementObjectIdCounter() {
195 // Get method bytes from the socket
196 char* IoTRMIComm::getMethodBytes() {
203 // Get method length from the socket
204 int IoTRMIComm::getMethodLength() {
211 // Get object Id from bytes
212 int IoTRMIComm::getObjectIdFromMethod() {
214 char objectIdBytes[IoTRMIUtil::OBJECT_ID_LEN];
215 memcpy(objectIdBytes, methodBytes, IoTRMIUtil::OBJECT_ID_LEN);
216 // Get method signature
218 IoTRMIUtil::byteArrayToInt(&objectId, objectIdBytes);
224 // Get object Id from bytes (static version)
225 int IoTRMIComm::getObjectId(char* packetBytes) {
227 char objectIdBytes[IoTRMIUtil::OBJECT_ID_LEN];
228 memcpy(objectIdBytes, packetBytes, IoTRMIUtil::OBJECT_ID_LEN);
229 // Get method signature
231 IoTRMIUtil::byteArrayToInt(&objectId, objectIdBytes);
237 // Get methodId from bytes (static version)
238 int IoTRMIComm::getMethodId(char* packetBytes) {
241 char methodIdBytes[IoTRMIUtil::METHOD_ID_LEN];
242 int offset = IoTRMIUtil::OBJECT_ID_LEN;
243 memcpy(methodIdBytes, packetBytes + offset, IoTRMIUtil::METHOD_ID_LEN);
244 // Get method signature
246 IoTRMIUtil::byteArrayToInt(&methodId, methodIdBytes);
252 // Get methodId from bytes (static version)
253 int IoTRMIComm::getPacketType(char* packetBytes) {
256 char packetTypeBytes[IoTRMIUtil::METHOD_ID_LEN];
257 int offset = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN;
258 memcpy(packetTypeBytes, packetBytes + offset, IoTRMIUtil::PACKET_TYPE_LEN);
259 // Get method signature
261 IoTRMIUtil::byteArrayToInt(&packetType, packetTypeBytes);
267 // Get method parameters and return an array of parameter objects
269 // For primitive objects:
270 // | 32-bit method ID | m-bit actual data (fixed length) |
272 // For string, arrays, and non-primitive objects:
273 // | 32-bit method ID | 32-bit length | n-bit actual data | ...
274 void** IoTRMIComm::getMethodParams(string paramCls[], int numParam, void* paramObj[], char* methodBytes) {
276 // Byte scanning position
277 int pos = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN + IoTRMIUtil::PACKET_TYPE_LEN;
278 for (int i = 0; i < numParam; i++) {
279 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
280 // Get the 32-bit field in the byte array to get the actual
281 // length (this is a param with indefinite length)
282 if (paramLen == -1) {
283 char bytPrmLen[IoTRMIUtil::PARAM_LEN];
284 memcpy(bytPrmLen, methodBytes + pos, IoTRMIUtil::PARAM_LEN);
285 pos = pos + IoTRMIUtil::PARAM_LEN;
286 int* prmLenPtr = IoTRMIUtil::byteArrayToInt(¶mLen, bytPrmLen);
287 paramLen = *prmLenPtr;
289 char paramBytes[paramLen];
290 memcpy(paramBytes, methodBytes + pos, paramLen);
291 pos = pos + paramLen;
292 paramObj[i] = IoTRMIUtil::getParamObject(paramObj[i], paramCls[i].c_str(), paramBytes, paramLen);
299 // Find the bytes length of a return object (struct that has more than 1 member)
300 int IoTRMIComm::returnLength(void* retObj[], string retCls[], int numRet) {
302 // Get byte arrays and calculate return bytes length
303 int returnLen = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN + IoTRMIUtil::PACKET_TYPE_LEN;
304 for (int i = 0; i < numRet; i++) {
305 // Find the return length
306 int retObjLen = rmiUtil->getTypeSize(retCls[i]);
307 if (retObjLen == -1) { // Store the length of the field - indefinite length
308 retObjLen = rmiUtil->getVarTypeSize(retCls[i], retObj[i]);
309 // Some space for return length, i.e. 32 bits for integer
310 returnLen = returnLen + IoTRMIUtil::RETURN_LEN;
312 // Calculate returnLen
313 returnLen = returnLen + retObjLen;
320 // Convert return object (struct members) into bytes
321 char* IoTRMIComm::returnToBytes(void* retObj[], string retCls[], char* retBytes, int numRet) {
324 // Get byte arrays and calculate return bytes length
325 for (int i = 0; i < numRet; i++) {
326 // Find the return length
327 int retObjLen = rmiUtil->getTypeSize(retCls[i]);
328 if (retObjLen == -1) { // Store the length of the field - indefinite length
329 retObjLen = rmiUtil->getVarTypeSize(retCls[i], retObj[i]);
330 // Write the return length
331 char retLenBytes[IoTRMIUtil::RETURN_LEN];
332 IoTRMIUtil::intToByteArray(retObjLen, retLenBytes);
333 memcpy(retBytes + pos, retLenBytes, IoTRMIUtil::RETURN_LEN);
334 pos = pos + IoTRMIUtil::RETURN_LEN;
336 // Get array of bytes and put it in the array of array of bytes
337 char objBytes[retObjLen];
338 IoTRMIUtil::getObjectBytes(objBytes, retObj[i], retCls[i].c_str());
339 memcpy(retBytes + pos, objBytes, retObjLen);
340 pos = pos + retObjLen;
347 // Get return value for single values (non-structs)
348 void* IoTRMIComm::getReturnValue(string retType, void* retObj) {
350 // Receive return value and return it to caller
351 lock_guard<mutex> guard(retValMutex);
352 // Copy just the actual return value bytes
353 int headerLen = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN + IoTRMIUtil::PACKET_TYPE_LEN;
354 int retActualLen = retValueLen - headerLen;
355 //char *retActualBytes = new char[retActualLen];
356 char retActualBytes[retActualLen];
357 memcpy(retActualBytes, retValueBytes + headerLen, retActualLen);
358 //IoTRMIUtil::printBytes(retActualBytes, retActualLen, false);
359 retObj = IoTRMIUtil::getParamObject(retObj, retType.c_str(), retActualBytes, retActualLen);
360 // Delete received bytes object
361 delete[] retValueBytes;
362 //delete[] retActualBytes;
368 // Get a set of return objects (struct)
369 void** IoTRMIComm::getStructObjects(string retType[], int numRet, void* retObj[]) {
371 // Critical section that is used by different objects
372 lock_guard<mutex> guard(retValMutex);
373 // Copy just the actual return value bytes
374 int headerLen = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN + IoTRMIUtil::PACKET_TYPE_LEN;
375 int retActualLen = retValueLen - headerLen;
376 char retActualBytes[retActualLen];
377 memcpy(retActualBytes, retValueBytes + headerLen, retActualLen);
378 // Return size of array of struct
379 retObj = getReturnObjects(retActualBytes, retType, numRet, retObj);
380 // Delete received bytes object
381 delete[] retValueBytes;
387 // Find the bytes length of a method
388 int IoTRMIComm::methodLength(string paramCls[], void* paramObj[], int numParam) {
390 // Get byte arrays and calculate method bytes length
391 // Start from the object Id + method Id...
392 int methodLen = IoTRMIUtil::OBJECT_ID_LEN + IoTRMIUtil::METHOD_ID_LEN + IoTRMIUtil::PACKET_TYPE_LEN;
393 for (int i = 0; i < numParam; i++) {
394 // Find the parameter length
395 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
396 if (paramLen == -1) { // Store the length of the field - indefinite length
397 paramLen = rmiUtil->getVarTypeSize(paramCls[i], paramObj[i]);
398 // Some space for param length, i.e. 32 bits for integer
399 methodLen = methodLen + IoTRMIUtil::PARAM_LEN;
401 // Calculate methodLen
402 methodLen = methodLen + paramLen;
408 // Convert method and its parameters into bytes
409 char* IoTRMIComm::methodToBytes(int objectId, int methId, string paramCls[],
410 void* paramObj[], char* method, int numParam) {
412 // Get object Id in bytes
413 char objId[IoTRMIUtil::OBJECT_ID_LEN];
414 IoTRMIUtil::intToByteArray(objectId, objId);
415 memcpy(method, objId, IoTRMIUtil::OBJECT_ID_LEN);
416 int pos = IoTRMIUtil::OBJECT_ID_LEN;
417 // Get method Id in bytes
418 char methodId[IoTRMIUtil::METHOD_ID_LEN];
419 IoTRMIUtil::intToByteArray(methId, methodId);
420 memcpy(method + pos, methodId, IoTRMIUtil::METHOD_ID_LEN);
421 pos = pos + IoTRMIUtil::METHOD_ID_LEN;
422 char packetType[IoTRMIUtil::PACKET_TYPE_LEN];
423 IoTRMIUtil::intToByteArray(IoTRMIUtil::METHOD_TYPE, methodId);
424 memcpy(method + pos, methodId, IoTRMIUtil::PACKET_TYPE_LEN);
425 pos = pos + IoTRMIUtil::PACKET_TYPE_LEN;
426 // Get byte arrays and calculate method bytes length
427 for (int i = 0; i < numParam; i++) {
428 // Find the parameter length
429 int paramLen = rmiUtil->getTypeSize(paramCls[i]);
430 if (paramLen == -1) { // Store the length of the field - indefinite length
431 paramLen = rmiUtil->getVarTypeSize(paramCls[i], paramObj[i]);
432 // Write the parameter length
433 char prmLenBytes[IoTRMIUtil::PARAM_LEN];
434 IoTRMIUtil::intToByteArray(paramLen, prmLenBytes);
435 memcpy(method + pos, prmLenBytes, IoTRMIUtil::PARAM_LEN);
436 pos = pos + IoTRMIUtil::PARAM_LEN;
438 // Get array of bytes and put it in the array of array of bytes
439 char objBytes[paramLen];
440 IoTRMIUtil::getObjectBytes(objBytes, paramObj[i], paramCls[i].c_str());
441 memcpy(method + pos, objBytes, paramLen);
442 pos = pos + paramLen;
449 // Get return objects for structs
450 void** IoTRMIComm::getReturnObjects(char* retBytes, string retCls[], int numRet, void* retObj[]) {
452 // Byte scanning position
454 for (int i = 0; i < numRet; i++) {
455 int retLen = rmiUtil->getTypeSize(retCls[i]);
456 // Get the 32-bit field in the byte array to get the actual
457 // length (this is a param with indefinite length)
459 char bytRetLen[IoTRMIUtil::RETURN_LEN];
460 memcpy(bytRetLen, retBytes + pos, IoTRMIUtil::RETURN_LEN);
461 pos = pos + IoTRMIUtil::RETURN_LEN;
462 int* retLenPtr = IoTRMIUtil::byteArrayToInt(&retLen, bytRetLen);
465 char retObjBytes[retLen];
466 memcpy(retObjBytes, retBytes + pos, retLen);
468 retObj[i] = IoTRMIUtil::getParamObject(retObj[i], retCls[i].c_str(), retObjBytes, retLen);