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