Fixing 2 issues in LifxLightBulb driver: 1) Detached thread handling (need to pass...
[iot2.git] / iotjava / iotruntime / cpp / socket / Socket.cpp
1 /*
2  *   C++ sockets on Unix and Windows
3  *   Copyright (C) 2002
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 // http://cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical/
21
22 #include "Socket.hpp"
23
24 #ifdef WIN32
25   #include <winsock.h>         // For socket(), connect(), send(), and recv()
26   typedef int socklen_t;
27   typedef char raw_type;       // Type used for raw data on this platform
28 #else
29   #include <sys/types.h>       // For data types
30   #include <sys/select.h>      // For select() - non-blocking socket
31   #include <sys/socket.h>      // For socket(), connect(), send(), and recv()
32   #include <netdb.h>           // For gethostbyname()
33   #include <arpa/inet.h>       // For inet_addr()
34   #include <unistd.h>          // For close()
35   #include <netinet/in.h>      // For sockaddr_in
36   typedef void raw_type;       // Type used for raw data on this platform
37 #endif
38
39 #include <errno.h>             // For errno
40 #include <string.h>            // For memset
41 #include <fcntl.h>             // For fcntl
42
43 using namespace std;
44
45 #ifdef WIN32
46 static bool initialized = false;
47 #endif
48
49 // SocketException Code
50
51 SocketException::SocketException(const string &message, bool inclSysMsg)
52   throw() : userMessage(message) {
53   if (inclSysMsg) {
54     userMessage.append(": ");
55     userMessage.append(strerror(errno));
56   }
57 }
58
59 SocketException::~SocketException() throw() {
60 }
61
62 const char *SocketException::what() const throw() {
63   return userMessage.c_str();
64 }
65
66 // Function to fill in address structure given an address and port
67 static void fillAddr(const string &address, unsigned short port, 
68                      sockaddr_in &addr) {
69   memset(&addr, 0, sizeof(addr));  // Zero out address structure
70   addr.sin_family = AF_INET;       // Internet address
71
72   hostent *host;  // Resolve name
73   if ((host = gethostbyname(address.c_str())) == NULL) {
74     // strerror() will not work for gethostbyname() and hstrerror() 
75     // is supposedly obsolete
76     throw SocketException("Failed to resolve name (gethostbyname())");
77   }
78   addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
79
80   addr.sin_port = htons(port);     // Assign port in network byte order
81 }
82
83 // Socket Code
84
85 Socket::Socket(int type, int protocol) throw(SocketException) {
86   #ifdef WIN32
87     if (!initialized) {
88       WORD wVersionRequested;
89       WSADATA wsaData;
90
91       wVersionRequested = MAKEWORD(2, 0);              // Request WinSock v2.0
92       if (WSAStartup(wVersionRequested, &wsaData) != 0) {  // Load WinSock DLL
93         throw SocketException("Unable to load WinSock DLL");
94       }
95       initialized = true;
96     }
97   #endif
98
99   // Make a new socket
100   if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
101     throw SocketException("Socket creation failed (socket())", true);
102   }
103 }
104
105 Socket::Socket(int sockDesc) {
106   this->sockDesc = sockDesc;
107 }
108
109 Socket::~Socket() {
110   #ifdef WIN32
111     ::closesocket(sockDesc);
112   #else
113     ::close(sockDesc);
114   #endif
115   sockDesc = -1;
116 }
117
118 string Socket::getLocalAddress() throw(SocketException) {
119   sockaddr_in addr;
120   unsigned int addr_len = sizeof(addr);
121
122   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
123     throw SocketException("Fetch of local address failed (getsockname())", true);
124   }
125   return inet_ntoa(addr.sin_addr);
126 }
127
128 unsigned short Socket::getLocalPort() throw(SocketException) {
129   sockaddr_in addr;
130   unsigned int addr_len = sizeof(addr);
131
132   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
133     throw SocketException("Fetch of local port failed (getsockname())", true);
134   }
135   return ntohs(addr.sin_port);
136 }
137
138 void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
139   // Bind the socket to its port
140   sockaddr_in localAddr;
141   memset(&localAddr, 0, sizeof(localAddr));
142   localAddr.sin_family = AF_INET;
143   localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
144   localAddr.sin_port = htons(localPort);
145
146   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
147     throw SocketException("Set of local port failed (bind())", true);
148   }
149 }
150
151 void Socket::setLocalAddressAndPort(const string &localAddress,
152     unsigned short localPort) throw(SocketException) {
153   // Get the address of the requested host
154   sockaddr_in localAddr;
155   fillAddr(localAddress, localPort, localAddr);
156
157   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
158     throw SocketException("Set of local address and port failed (bind())", true);
159   }
160 }
161
162 void Socket::cleanUp() throw(SocketException) {
163   #ifdef WIN32
164     if (WSACleanup() != 0) {
165       throw SocketException("WSACleanup() failed");
166     }
167   #endif
168 }
169
170 unsigned short Socket::resolveService(const string &service,
171                                       const string &protocol) {
172   struct servent *serv;        /* Structure containing service information */
173
174   if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
175     return atoi(service.c_str());  /* Service is port number */
176   else 
177     return ntohs(serv->s_port);    /* Found port (network byte order) by name */
178 }
179
180 // CommunicatingSocket Code
181
182 CommunicatingSocket::CommunicatingSocket(int type, int protocol)  
183     throw(SocketException) : Socket(type, protocol) {
184 }
185
186 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
187 }
188
189 void CommunicatingSocket::connect(const string &foreignAddress,
190     unsigned short foreignPort) throw(SocketException) {
191   // Get the address of the requested host
192   sockaddr_in destAddr;
193   fillAddr(foreignAddress, foreignPort, destAddr);
194
195   // Try to connect to the given port
196   if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
197     throw SocketException("Connect failed (connect())", true);
198   }
199 }
200
201 void CommunicatingSocket::send(const void *buffer, int bufferLen) 
202     throw(SocketException) {
203   if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
204     throw SocketException("Send failed (send())", true);
205   }
206 }
207
208 int CommunicatingSocket::recv(void *buffer, int bufferLen) 
209     throw(SocketException) {
210   int rtn;
211   if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
212     throw SocketException("Received failed (recv())", true);
213   }
214
215   return rtn;
216 }
217
218 string CommunicatingSocket::getForeignAddress() 
219     throw(SocketException) {
220   sockaddr_in addr;
221   unsigned int addr_len = sizeof(addr);
222
223   if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
224     throw SocketException("Fetch of foreign address failed (getpeername())", true);
225   }
226   return inet_ntoa(addr.sin_addr);
227 }
228
229 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
230   sockaddr_in addr;
231   unsigned int addr_len = sizeof(addr);
232
233   if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
234     throw SocketException("Fetch of foreign port failed (getpeername())", true);
235   }
236   return ntohs(addr.sin_port);
237 }
238
239 // TCPSocket Code
240
241 TCPSocket::TCPSocket() 
242     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, 
243     IPPROTO_TCP) {
244 }
245
246 TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort)
247     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
248   connect(foreignAddress, foreignPort);
249 }
250
251 TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
252 }
253
254 // TCPServerSocket Code
255
256 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen) 
257     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
258   setLocalPort(localPort);
259   setListen(queueLen);
260 }
261
262 TCPServerSocket::TCPServerSocket(const string &localAddress, 
263     unsigned short localPort, int queueLen) 
264     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
265   setLocalAddressAndPort(localAddress, localPort);
266   setListen(queueLen);
267 }
268
269 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
270   int newConnSD;
271   if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
272     throw SocketException("Accept failed (accept())", true);
273   }
274
275   return new TCPSocket(newConnSD);
276 }
277
278 void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
279   if (listen(sockDesc, queueLen) < 0) {
280     throw SocketException("Set listening socket failed (listen())", true);
281   }
282 }
283
284 // UDPSocket Code
285
286 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
287     IPPROTO_UDP) {
288   setBroadcast();
289 }
290
291 UDPSocket::UDPSocket(unsigned short localPort)  throw(SocketException) : 
292     CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
293   setLocalPort(localPort);
294   setBroadcast();
295 }
296
297 UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort) 
298      throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
299   setLocalAddressAndPort(localAddress, localPort);
300   setBroadcast();
301 }
302
303 void UDPSocket::setBroadcast() {
304   // If this fails, we'll hear about it when we try to send.  This will allow 
305   // system that cannot broadcast to continue if they don't plan to broadcast
306   int broadcastPermission = 1;
307   setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST, 
308              (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
309 }
310
311 void UDPSocket::disconnect() throw(SocketException) {
312   sockaddr_in nullAddr;
313   memset(&nullAddr, 0, sizeof(nullAddr));
314   nullAddr.sin_family = AF_UNSPEC;
315
316   // Try to disconnect
317   if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
318    #ifdef WIN32
319     if (errno != WSAEAFNOSUPPORT) {
320    #else
321     if (errno != EAFNOSUPPORT) {
322    #endif
323       throw SocketException("Disconnect failed (connect())", true);
324     }
325   }
326 }
327
328 void UDPSocket::sendTo(const void *buffer, int bufferLen, 
329     const string &foreignAddress, unsigned short foreignPort) 
330     throw(SocketException) {
331   sockaddr_in destAddr;
332   fillAddr(foreignAddress, foreignPort, destAddr);
333
334   // Write out the whole buffer as a single message.
335   if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
336              (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
337     throw SocketException("Send failed (sendto())", true);
338   }
339 }
340
341 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
342     unsigned short &sourcePort) throw(SocketException) {
343   sockaddr_in clntAddr;
344   socklen_t addrLen = sizeof(clntAddr);
345   int rtn;
346   if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0, 
347                       (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
348     throw SocketException("Receive failed (recvfrom())", true);
349   }
350   sourceAddress = inet_ntoa(clntAddr.sin_addr);
351   sourcePort = ntohs(clntAddr.sin_port);
352
353   return rtn;
354 }
355
356 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
357     unsigned short &sourcePort, int timeOut) throw(SocketException) {
358
359   if(!(fcntl(sockDesc, F_GETFL) & O_NONBLOCK)) {
360   // If not non-blocking then put it into non-blocking
361      if(fcntl(sockDesc, F_SETFL, fcntl(sockDesc, F_GETFL) | O_NONBLOCK) < 0) {
362         throw SocketException("Set non-blocking failed (recvfrom())", true);
363      }
364   }
365   fd_set readFds;  // FD
366   FD_ZERO(&readFds);
367   FD_SET(sockDesc, &readFds);
368   struct timeval to;    // timeout
369   to.tv_sec = 0;
370   to.tv_usec = timeOut;
371   sockaddr_in clntAddr;
372   socklen_t addrLen = sizeof(clntAddr);
373   
374   int rv = select(sockDesc+1 ,&readFds, NULL, NULL, &to);
375   int rtn = -1; // Assuming receive failure
376   if (rv == 1) {
377          if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0, 
378                           (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
379         throw SocketException("Receive failed (recvfrom())", true);
380          }
381          sourceAddress = inet_ntoa(clntAddr.sin_addr);
382          sourcePort = ntohs(clntAddr.sin_port);
383   }
384
385   return rtn;
386 }
387
388 void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
389   if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL, 
390                  (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
391     throw SocketException("Multicast TTL set failed (setsockopt())", true);
392   }
393 }
394
395 void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
396   struct ip_mreq multicastRequest;
397
398   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
399   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
400   if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
401                  (raw_type *) &multicastRequest, 
402                  sizeof(multicastRequest)) < 0) {
403     throw SocketException("Multicast group join failed (setsockopt())", true);
404   }
405 }
406
407 void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
408   struct ip_mreq multicastRequest;
409
410   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
411   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
412   if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
413                  (raw_type *) &multicastRequest, 
414                  sizeof(multicastRequest)) < 0) {
415     throw SocketException("Multicast group leave failed (setsockopt())", true);
416   }
417 }
418
419 void UDPSocket::setTimeOut(int interval) throw(SocketException) {
420
421   struct timeval timeout;
422   timeout.tv_sec = 0;
423   timeout.tv_usec = interval;
424   if (setsockopt(sockDesc, SOL_SOCKET, SO_RCVTIMEO, &timeout, 
425                  sizeof(timeout)) < 0) {
426     throw SocketException("Multicast group join failed (setsockopt())", true);
427   }
428 }