52907ba0f6dc095b6d5a3dfeb947d1059d012b0a
[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 mutex sendBytesMutex;
44 mutex recvBytesMutex;
45 mutex sendAckMutex;
46 mutex recvAckMutex;
47
48 class IoTSocket {
49         public:
50                 IoTSocket(int iPort, bool* pResult);
51                 ~IoTSocket();
52
53                 bool                            close();                                                                // Close the socket
54                 bool                            sendBytes(char* pVals, int _iLen);              // Send a set of bytes
55                 char*                           receiveBytes(char* pVals, int* len);    // Receive a set of bytes
56
57         protected:              
58                 int                                     m_iPort;                                                        // Port I'm listening on
59                 int                                     m_iSock;                                                        // Socket connection
60                 struct sockaddr_in      m_addrRemote;                                           // Connector's address information
61                 double*                         m_pBuffer;                                                      // Reuse the same memory for buffer
62
63         private:
64                 bool                            receiveAck();
65                 bool                            sendAck();
66 };
67
68
69 // Constructor
70 IoTSocket::IoTSocket(int iPort, bool* pResult) {
71
72         m_iPort         = iPort;
73         m_iSock         = -1;
74         m_pBuffer       = NULL;
75
76         // Allocate our temporary buffers that are used to convert data types
77         m_pBuffer = (double *) malloc(sizeof(double) * SOCKET_BUFF_SIZE);
78         if (!m_pBuffer) {
79                 perror("IoTSocket: Failed to malloc buffer!");
80                 return;
81         }
82
83 }
84
85
86 // Destructor
87 IoTSocket::~IoTSocket() {
88
89         if (m_pBuffer) {
90                 free(m_pBuffer);
91                 m_pBuffer = NULL;
92         }
93 }
94
95
96 // Send bytes over the wire
97 bool IoTSocket::sendBytes(char* pVals, int iLen) {
98
99         // Critical section that is used by different objects
100         lock_guard<mutex> guard(sendBytesMutex);
101
102         int i = 0;
103         char size[MSG_LEN_SIZE];
104         // Convert int to byte array and fix endianness
105         IoTRMIUtil::intToByteArray(iLen, size);
106
107         if (send(m_iSock, size, MSG_LEN_SIZE, 0) == -1) {
108                 perror("IoTSocket: Send size error!");
109                 return false;
110         }
111
112         IoTRMIUtil::printBytes(size, 4, false);
113
114         if (send(m_iSock, (char *) pVals, iLen, 0) == -1) {
115                 perror("IoTSocket: Send bytes error!");
116                 return false;
117         }
118
119 #ifdef DEBUG_ACK
120         if (!receiveAck())
121                 return false;
122         if (!sendAck())
123                 return false;
124 #endif
125
126         return true;
127 }
128
129
130 // Receive bytes, returns number of bytes received
131 // Generate an array of char on the heap and return it
132 char* IoTSocket::receiveBytes(char* pVals, int* len)
133 {
134         // Critical section that is used by different objects
135         lock_guard<mutex> guard(recvBytesMutex);
136
137         int                     i                               = 0;
138         int                     j                               = 0;
139         char*           pTemp                   = NULL;
140         int                     iTotalBytes             = 0;
141         int                     iNumBytes               = 0;
142         bool            bEnd                    = false;
143
144         int iTotal = 0;
145         int iResult = 0;
146         char size[MSG_LEN_SIZE];
147         
148         while ((iTotal < 1) && (iResult != -1)) {
149                 iResult = recv(m_iSock, size, MSG_LEN_SIZE, 0);         
150                 iTotal += iResult;
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