Adding premature C++ side; supporting only primitive types (including string) for now
[iot2.git] / iotjava / iotrmi / C++ / IoTSocket.hpp
diff --git a/iotjava/iotrmi/C++/IoTSocket.hpp b/iotjava/iotrmi/C++/IoTSocket.hpp
new file mode 100644 (file)
index 0000000..46685f7
--- /dev/null
@@ -0,0 +1,211 @@
+/** Class IoTSocket is a base class for IoTSocketServer.cpp
+ *  and IoTSocketClient.cpp that provide interfaces to connect 
+ *  to either Java or C++ socket endpoint
+ *  <p>
+ *  Adapted from Java/C++ socket implementation
+ *  by Keith Vertanen
+ *  @see        <a href="https://www.keithv.com/software/socket/</a>
+ *
+ * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
+ * @version     1.0
+ * @since       2016-10-17
+ */
+#ifndef _IOTSOCKET_HPP__
+#define _IOTSOCKET_HPP__
+
+// Adds in the send/recv acks after each message.
+#define DEBUG_ACK
+
+static const int SOCKET_BUFF_SIZE = 64000;
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+// Duplicated from winsock2.h
+#define SD_RECEIVE      0x00
+#define SD_SEND         0x01
+#define SD_BOTH         0x02
+
+
+class IoTSocket {
+       public:
+               IoTSocket(int iPort, bool* pResult);
+               ~IoTSocket();
+
+               bool                            close();                                                                // Close the socket
+               bool                            sendBytes(char* pVals, int _iLen);              // Send a set of bytes
+               char*                           receiveBytes(char* pVals, int* len);    // Receive a set of bytes
+
+       protected:              
+               int                                     m_iPort;                                                        // Port I'm listening on
+               int                                     m_iSock;                                                        // Socket connection
+               struct sockaddr_in      m_addrRemote;                                           // Connector's address information
+               double*                         m_pBuffer;                                                      // Reuse the same memory for buffer
+
+       private:
+               bool                            receiveAck();
+               bool                            sendAck();
+};
+
+
+// Constructor
+IoTSocket::IoTSocket(int iPort, bool* pResult) {
+
+       m_iPort         = iPort;
+       m_iSock         = -1;
+       m_pBuffer       = NULL;
+
+       // Allocate our temporary buffers that are used to convert data types
+       m_pBuffer = (double *) malloc(sizeof(double) * SOCKET_BUFF_SIZE);
+       if (!m_pBuffer) {
+               perror("IoTSocket: Failed to malloc buffer!");
+               return;
+       }
+
+}
+
+
+// Destructor
+IoTSocket::~IoTSocket() {
+
+       if (m_pBuffer) {
+               free(m_pBuffer);
+               m_pBuffer = NULL;
+       }
+}
+
+
+// Send bytes over the wire
+bool IoTSocket::sendBytes(char* pVals, int _iLen) {
+
+       int i = 0;
+       int size[1];
+       int iLen = _iLen;
+       size[0] = iLen;
+
+       if (send(m_iSock, size, 1, 0) == -1) {
+               perror("IoTSocket: Send size error!");
+               return false;
+       }
+
+       if (send(m_iSock, (char *) pVals, iLen, 0) == -1) {
+               perror("IoTSocket: Send bytes error!");
+               return false;
+       }
+#ifdef DEBUG_ACK
+       if (!receiveAck())
+               return false;
+       if (!sendAck())
+               return false;
+#endif
+
+       return true;
+}
+
+
+// Receive bytes, returns number of bytes received
+// Generate an array of char on the heap and return it
+char* IoTSocket::receiveBytes(char* pVals, int* len)
+{
+       int                     i                               = 0;
+       int                     j                               = 0;
+       char*           pTemp                   = NULL;
+       int                     iTotalBytes             = 0;
+       int                     iNumBytes               = 0;
+       bool            bEnd                    = false;
+
+       int iTotal = 0;
+       int iResult = 0;
+       char size[1];
+       while ((iTotal < 1) && (iResult != -1)) {
+               iResult = recv(m_iSock, size, 1, 0);    
+               iTotal += iResult;
+       }
+       if (iResult == -1) {
+               perror("IoTSocket: Receive size error!");
+               return NULL;
+       }
+       int iLen = (int) size[0];
+       // To be returned from this method...
+       *len = iLen;
+       pVals = new char[iLen];
+       pTemp = (char *) m_pBuffer;
+       // We receiving the incoming ints one byte at a time.
+       while (!bEnd) {
+               if ((iNumBytes = recv(m_iSock, pTemp, SOCKET_BUFF_SIZE, 0)) == -1) {
+                       perror("IoTSocket: Receive error!");
+                       return NULL;
+               }
+               for (i = 0; i < iNumBytes; i++) {
+                       pVals[j] = pTemp[i];
+                       j++;
+               }
+               iTotalBytes += iNumBytes;
+               if (iTotalBytes == iLen)
+                       bEnd = true;
+       }
+#ifdef DEBUG_ACK
+       if (!sendAck())
+               return NULL;
+       if (!receiveAck())
+               return NULL;
+#endif
+
+       return pVals;
+}
+
+
+// Shut down the socket
+bool IoTSocket::close()
+{
+       if (shutdown(m_iSock, SD_BOTH) == -1) {
+               perror("IoTSocket: Close error!");
+               return false;
+       }
+
+       return true;
+}
+
+
+// Receive a short ack from the client 
+bool IoTSocket::receiveAck()
+{
+       char temp[1];
+       int iTotal = 0;
+       int iResult = 0;
+       while ((iTotal < 1) && (iResult != -1)) {
+
+               iResult = recv(m_iSock, temp, 1, 0);    
+               iTotal += iResult;
+       }
+       if (iResult == -1) {
+
+               perror("IoTSocket: ReceiveAck error!");
+               return false;
+       }
+
+       return true;
+}      
+
+
+// Send a short ack to the client 
+bool IoTSocket::sendAck()
+{
+       char temp[1];
+       temp[0] = 42;
+
+       if (send(m_iSock, temp, 1, 0) == -1)
+               return false;
+       return true;
+}
+
+#endif