Adding config file for sharing.
[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 #include <mutex>
36
37 #include "IoTRMIUtil.hpp"
38
39 // Duplicated from winsock2.h
40 #define SD_RECEIVE      0x00
41 #define SD_SEND         0x01
42 #define SD_BOTH         0x02
43
44 mutex sendBytesMutex;
45 mutex recvBytesMutex;
46 mutex sendAckMutex;
47 mutex recvAckMutex;
48
49 class IoTSocket {
50         public:
51                 IoTSocket(int iPort, bool* pResult);
52                 ~IoTSocket();
53
54                 bool                    close();                                // Close the socket
55                 bool                    sendBytes(char* pVals, int _iLen);      // Send a set of bytes
56                 char*                   receiveBytes(char* pVals, int* len);    // Receive a set of bytes
57
58         protected:              
59                 int                     m_iPort;                                // Port I'm listening on
60                 int                     m_iSock;                                // Socket connection
61                 struct sockaddr_in      m_addrRemote;                           // Connector's address information
62                 double*                 m_pBuffer;                              // Reuse the same memory for buffer
63
64         private:
65                 bool                    receiveAck();
66                 bool                    sendAck();
67 };
68
69
70 // Constructor
71 IoTSocket::IoTSocket(int iPort, bool* pResult) {
72
73         m_iPort         = iPort;
74         m_iSock         = -1;
75         m_pBuffer       = NULL;
76
77         // Allocate our temporary buffers that are used to convert data types
78         m_pBuffer = (double *) malloc(sizeof(double) * SOCKET_BUFF_SIZE);
79         if (!m_pBuffer) {
80                 perror("IoTSocket: Failed to malloc buffer!");
81                 return;
82         }
83
84 }
85
86
87 // Destructor
88 IoTSocket::~IoTSocket() {
89
90         if (m_pBuffer) {
91                 free(m_pBuffer);
92                 m_pBuffer = NULL;
93         }
94 }
95
96
97 // Send bytes over the wire
98 bool IoTSocket::sendBytes(char* pVals, int iLen) {
99
100         // Critical section that is used by different objects
101         lock_guard<mutex> guard(sendBytesMutex);
102
103         int i = 0;
104         char size[MSG_LEN_SIZE];
105         // Convert int to byte array and fix endianness
106         IoTRMIUtil::intToByteArray(iLen, size);
107
108         if (send(m_iSock, size, MSG_LEN_SIZE, 0) == -1) {
109                 perror("IoTSocket: Send size error!");
110                 return false;
111         }
112
113         if (send(m_iSock, (char *) pVals, iLen, 0) == -1) {
114                 perror("IoTSocket: Send bytes error!");
115                 return false;
116         }
117
118 #ifdef DEBUG_ACK
119         if (!receiveAck())
120                 return false;
121         if (!sendAck())
122                 return false;
123 #endif
124
125         return true;
126 }
127
128
129 // Receive bytes, returns number of bytes received
130 // Generate an array of char on the heap and return it
131 char* IoTSocket::receiveBytes(char* pVals, int* len)
132 {
133         // Critical section that is used by different objects
134         lock_guard<mutex> guard(recvBytesMutex);
135
136         int                     i                       = 0;
137         int                     j                       = 0;
138         char*                   pTemp                   = NULL;
139         int                     iTotalBytes             = 0;
140         int                     iNumBytes               = 0;
141         bool                    bEnd                    = false;
142
143         int iTotal = 0;
144         int iResult = 0;
145         char size[MSG_LEN_SIZE];
146         
147         while ((iTotal < 1) && (iResult != -1)) {
148                 iResult = recv(m_iSock, size, MSG_LEN_SIZE, 0);         
149                 iTotal += iResult;
150         }
151
152         if (iResult == -1) {
153                 perror("IoTSocket: Receive size error!");
154                 return NULL;
155         }
156         // Convert byte to int array based on correct endianness
157         int iLen = 0;
158         IoTRMIUtil::byteArrayToInt(&iLen, size);
159
160         // To be returned from this method...
161         *len = iLen;
162         pVals = new char[iLen];
163         pTemp = (char *) m_pBuffer;
164         // We receiving the incoming ints one byte at a time.
165         while (!bEnd) {
166                 if ((iNumBytes = recv(m_iSock, pTemp, SOCKET_BUFF_SIZE, 0)) == -1) {
167                         perror("IoTSocket: Receive error!");
168                         return NULL;
169                 }
170                 for (i = 0; i < iNumBytes; i++) {
171                         pVals[j] = pTemp[i];
172                         j++;
173                 }
174                 iTotalBytes += iNumBytes;
175                 if (iTotalBytes == iLen)
176                         bEnd = true;
177         }
178
179 #ifdef DEBUG_ACK
180         if (!sendAck())
181                 return NULL;
182         if (!receiveAck())
183                 return NULL;
184 #endif
185         return pVals;
186 }
187
188
189 // Shut down the socket
190 bool IoTSocket::close()
191 {
192         if (shutdown(m_iSock, SD_BOTH) == -1) {
193                 perror("IoTSocket: Close error!");
194                 return false;
195         }
196
197         return true;
198 }
199
200
201 // Receive a short ack from the client 
202 bool IoTSocket::receiveAck()
203 {
204         // Critical section that is used by different objects
205         lock_guard<mutex> guard(recvAckMutex);
206         char temp[1];
207         int iTotal = 0;
208         int iResult = 0;
209         while ((iTotal < 1) && (iResult != -1)) {
210
211                 iResult = recv(m_iSock, temp, 1, 0);    
212                 iTotal += iResult;
213         }
214         if (iResult == -1) {
215
216                 perror("IoTSocket: ReceiveAck error!");
217                 return false;
218         }
219
220         return true;
221 }       
222
223
224 // Send a short ack to the client 
225 bool IoTSocket::sendAck()
226 {
227         // Critical section that is used by different objects
228         lock_guard<mutex> guard(sendAckMutex);
229         char temp[1];
230         temp[0] = 42;
231
232         if (send(m_iSock, temp, 1, 0) == -1)
233                 return false;
234         return true;
235 }
236
237 #endif