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