Adding last version of iotruntime and iotinstaller; preparing to extend IoTMaster...
[iot2.git] / iotjava / iotrmi / C++ / IoTSocket.hpp
1 /** Class IoTSocket is a base class for IoTSocketServer.cpp
2  *  and IoTSocketClient.cpp that provide interfaces to connect 
3  *  to either Java or C++ socket endpoint
4  *  <p>
5  *  Adapted from Java/C++ socket implementation
6  *  by Keith Vertanen
7  *  @see        <a href="https://www.keithv.com/software/socket/</a>
8  *
9  * @author      Rahmadi Trimananda <rtrimana @ uci.edu>
10  * @version     1.0
11  * @since       2016-10-17
12  */
13 #ifndef _IOTSOCKET_HPP__
14 #define _IOTSOCKET_HPP__
15
16 // Adds in the send/recv acks after each message.
17 #define DEBUG_ACK
18
19 static const int SOCKET_BUFF_SIZE = 64000;
20 // Before, it was too short as we were just using 1 byte to receive the length
21 // Now, we allocate 4 bytes (a size of integer) to receive the message length
22 static const int MSG_LEN_SIZE = 4;
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <sys/types.h>
29
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #include <sys/socket.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35
36 #include "IoTRMIUtil.hpp"
37
38 // Duplicated from winsock2.h
39 #define SD_RECEIVE      0x00
40 #define SD_SEND         0x01
41 #define SD_BOTH         0x02
42
43
44 class IoTSocket {
45         public:
46                 IoTSocket(int iPort, bool* pResult);
47                 ~IoTSocket();
48
49                 bool                            close();                                                                // Close the socket
50                 bool                            sendBytes(char* pVals, int _iLen);              // Send a set of bytes
51                 char*                           receiveBytes(char* pVals, int* len);    // Receive a set of bytes
52
53         protected:              
54                 int                                     m_iPort;                                                        // Port I'm listening on
55                 int                                     m_iSock;                                                        // Socket connection
56                 struct sockaddr_in      m_addrRemote;                                           // Connector's address information
57                 double*                         m_pBuffer;                                                      // Reuse the same memory for buffer
58
59         private:
60                 bool                            receiveAck();
61                 bool                            sendAck();
62 };
63
64
65 // Constructor
66 IoTSocket::IoTSocket(int iPort, bool* pResult) {
67
68         m_iPort         = iPort;
69         m_iSock         = -1;
70         m_pBuffer       = NULL;
71
72         // Allocate our temporary buffers that are used to convert data types
73         m_pBuffer = (double *) malloc(sizeof(double) * SOCKET_BUFF_SIZE);
74         if (!m_pBuffer) {
75                 perror("IoTSocket: Failed to malloc buffer!");
76                 return;
77         }
78
79 }
80
81
82 // Destructor
83 IoTSocket::~IoTSocket() {
84
85         if (m_pBuffer) {
86                 free(m_pBuffer);
87                 m_pBuffer = NULL;
88         }
89 }
90
91
92 // Send bytes over the wire
93 bool IoTSocket::sendBytes(char* pVals, int iLen) {
94
95         int i = 0;
96         char size[MSG_LEN_SIZE];
97         // Convert int to byte array and fix endianness
98         IoTRMIUtil::intToByteArray(iLen, size);
99
100         if (send(m_iSock, size, MSG_LEN_SIZE, 0) == -1) {
101                 perror("IoTSocket: Send size error!");
102                 return false;
103         }
104
105         if (send(m_iSock, (char *) pVals, iLen, 0) == -1) {
106                 perror("IoTSocket: Send bytes error!");
107                 return false;
108         }
109 #ifdef DEBUG_ACK
110         if (!receiveAck())
111                 return false;
112         if (!sendAck())
113                 return false;
114 #endif
115
116         return true;
117 }
118
119
120 // Receive bytes, returns number of bytes received
121 // Generate an array of char on the heap and return it
122 char* IoTSocket::receiveBytes(char* pVals, int* len)
123 {
124         int                     i                               = 0;
125         int                     j                               = 0;
126         char*           pTemp                   = NULL;
127         int                     iTotalBytes             = 0;
128         int                     iNumBytes               = 0;
129         bool            bEnd                    = false;
130
131         int iTotal = 0;
132         int iResult = 0;
133         char size[MSG_LEN_SIZE];
134         
135         while ((iTotal < 1) && (iResult != -1)) {
136                 iResult = recv(m_iSock, size, MSG_LEN_SIZE, 0);         
137                 iTotal += iResult;
138         }
139         if (iResult == -1) {
140                 perror("IoTSocket: Receive size error!");
141                 return NULL;
142         }
143         // Convert byte to int array based on correct endianness
144         int iLen = 0;
145         IoTRMIUtil::byteArrayToInt(&iLen, size);
146
147         // To be returned from this method...
148         *len = iLen;
149         pVals = new char[iLen];
150         pTemp = (char *) m_pBuffer;
151         // We receiving the incoming ints one byte at a time.
152         while (!bEnd) {
153                 if ((iNumBytes = recv(m_iSock, pTemp, SOCKET_BUFF_SIZE, 0)) == -1) {
154                         perror("IoTSocket: Receive error!");
155                         return NULL;
156                 }
157                 for (i = 0; i < iNumBytes; i++) {
158                         pVals[j] = pTemp[i];
159                         j++;
160                 }
161                 iTotalBytes += iNumBytes;
162                 if (iTotalBytes == iLen)
163                         bEnd = true;
164         }
165 #ifdef DEBUG_ACK
166         if (!sendAck())
167                 return NULL;
168         if (!receiveAck())
169                 return NULL;
170 #endif
171         return pVals;
172 }
173
174
175 // Shut down the socket
176 bool IoTSocket::close()
177 {
178         if (shutdown(m_iSock, SD_BOTH) == -1) {
179                 perror("IoTSocket: Close error!");
180                 return false;
181         }
182
183         return true;
184 }
185
186
187 // Receive a short ack from the client 
188 bool IoTSocket::receiveAck()
189 {
190         char temp[1];
191         int iTotal = 0;
192         int iResult = 0;
193         while ((iTotal < 1) && (iResult != -1)) {
194
195                 iResult = recv(m_iSock, temp, 1, 0);    
196                 iTotal += iResult;
197         }
198         if (iResult == -1) {
199
200                 perror("IoTSocket: ReceiveAck error!");
201                 return false;
202         }
203
204         return true;
205 }       
206
207
208 // Send a short ack to the client 
209 bool IoTSocket::sendAck()
210 {
211         char temp[1];
212         temp[0] = 42;
213
214         if (send(m_iSock, temp, 1, 0) == -1)
215                 return false;
216         return true;
217 }
218
219 #endif