Moving Java drivers; Creating iotruntime socket connections for C++; First version...
[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/socket.h>      // For socket(), connect(), send(), and recv()
31   #include <netdb.h>           // For gethostbyname()
32   #include <arpa/inet.h>       // For inet_addr()
33   #include <unistd.h>          // For close()
34   #include <netinet/in.h>      // For sockaddr_in
35   typedef void raw_type;       // Type used for raw data on this platform
36 #endif
37
38 #include <errno.h>             // For errno
39 #include <string.h>            // For memset
40
41 using namespace std;
42
43 #ifdef WIN32
44 static bool initialized = false;
45 #endif
46
47 // SocketException Code
48
49 SocketException::SocketException(const string &message, bool inclSysMsg)
50   throw() : userMessage(message) {
51   if (inclSysMsg) {
52     userMessage.append(": ");
53     userMessage.append(strerror(errno));
54   }
55 }
56
57 SocketException::~SocketException() throw() {
58 }
59
60 const char *SocketException::what() const throw() {
61   return userMessage.c_str();
62 }
63
64 // Function to fill in address structure given an address and port
65 static void fillAddr(const string &address, unsigned short port, 
66                      sockaddr_in &addr) {
67   memset(&addr, 0, sizeof(addr));  // Zero out address structure
68   addr.sin_family = AF_INET;       // Internet address
69
70   hostent *host;  // Resolve name
71   if ((host = gethostbyname(address.c_str())) == NULL) {
72     // strerror() will not work for gethostbyname() and hstrerror() 
73     // is supposedly obsolete
74     throw SocketException("Failed to resolve name (gethostbyname())");
75   }
76   addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
77
78   addr.sin_port = htons(port);     // Assign port in network byte order
79 }
80
81 // Socket Code
82
83 Socket::Socket(int type, int protocol) throw(SocketException) {
84   #ifdef WIN32
85     if (!initialized) {
86       WORD wVersionRequested;
87       WSADATA wsaData;
88
89       wVersionRequested = MAKEWORD(2, 0);              // Request WinSock v2.0
90       if (WSAStartup(wVersionRequested, &wsaData) != 0) {  // Load WinSock DLL
91         throw SocketException("Unable to load WinSock DLL");
92       }
93       initialized = true;
94     }
95   #endif
96
97   // Make a new socket
98   if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
99     throw SocketException("Socket creation failed (socket())", true);
100   }
101 }
102
103 Socket::Socket(int sockDesc) {
104   this->sockDesc = sockDesc;
105 }
106
107 Socket::~Socket() {
108   #ifdef WIN32
109     ::closesocket(sockDesc);
110   #else
111     ::close(sockDesc);
112   #endif
113   sockDesc = -1;
114 }
115
116 string Socket::getLocalAddress() throw(SocketException) {
117   sockaddr_in addr;
118   unsigned int addr_len = sizeof(addr);
119
120   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
121     throw SocketException("Fetch of local address failed (getsockname())", true);
122   }
123   return inet_ntoa(addr.sin_addr);
124 }
125
126 unsigned short Socket::getLocalPort() throw(SocketException) {
127   sockaddr_in addr;
128   unsigned int addr_len = sizeof(addr);
129
130   if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
131     throw SocketException("Fetch of local port failed (getsockname())", true);
132   }
133   return ntohs(addr.sin_port);
134 }
135
136 void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
137   // Bind the socket to its port
138   sockaddr_in localAddr;
139   memset(&localAddr, 0, sizeof(localAddr));
140   localAddr.sin_family = AF_INET;
141   localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
142   localAddr.sin_port = htons(localPort);
143
144   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
145     throw SocketException("Set of local port failed (bind())", true);
146   }
147 }
148
149 void Socket::setLocalAddressAndPort(const string &localAddress,
150     unsigned short localPort) throw(SocketException) {
151   // Get the address of the requested host
152   sockaddr_in localAddr;
153   fillAddr(localAddress, localPort, localAddr);
154
155   if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
156     throw SocketException("Set of local address and port failed (bind())", true);
157   }
158 }
159
160 void Socket::cleanUp() throw(SocketException) {
161   #ifdef WIN32
162     if (WSACleanup() != 0) {
163       throw SocketException("WSACleanup() failed");
164     }
165   #endif
166 }
167
168 unsigned short Socket::resolveService(const string &service,
169                                       const string &protocol) {
170   struct servent *serv;        /* Structure containing service information */
171
172   if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
173     return atoi(service.c_str());  /* Service is port number */
174   else 
175     return ntohs(serv->s_port);    /* Found port (network byte order) by name */
176 }
177
178 // CommunicatingSocket Code
179
180 CommunicatingSocket::CommunicatingSocket(int type, int protocol)  
181     throw(SocketException) : Socket(type, protocol) {
182 }
183
184 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
185 }
186
187 void CommunicatingSocket::connect(const string &foreignAddress,
188     unsigned short foreignPort) throw(SocketException) {
189   // Get the address of the requested host
190   sockaddr_in destAddr;
191   fillAddr(foreignAddress, foreignPort, destAddr);
192
193   // Try to connect to the given port
194   if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
195     throw SocketException("Connect failed (connect())", true);
196   }
197 }
198
199 void CommunicatingSocket::send(const void *buffer, int bufferLen) 
200     throw(SocketException) {
201   if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
202     throw SocketException("Send failed (send())", true);
203   }
204 }
205
206 int CommunicatingSocket::recv(void *buffer, int bufferLen) 
207     throw(SocketException) {
208   int rtn;
209   if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
210     throw SocketException("Received failed (recv())", true);
211   }
212
213   return rtn;
214 }
215
216 string CommunicatingSocket::getForeignAddress() 
217     throw(SocketException) {
218   sockaddr_in addr;
219   unsigned int addr_len = sizeof(addr);
220
221   if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
222     throw SocketException("Fetch of foreign address failed (getpeername())", true);
223   }
224   return inet_ntoa(addr.sin_addr);
225 }
226
227 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
228   sockaddr_in addr;
229   unsigned int addr_len = sizeof(addr);
230
231   if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
232     throw SocketException("Fetch of foreign port failed (getpeername())", true);
233   }
234   return ntohs(addr.sin_port);
235 }
236
237 // TCPSocket Code
238
239 TCPSocket::TCPSocket() 
240     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, 
241     IPPROTO_TCP) {
242 }
243
244 TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort)
245     throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
246   connect(foreignAddress, foreignPort);
247 }
248
249 TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
250 }
251
252 // TCPServerSocket Code
253
254 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen) 
255     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
256   setLocalPort(localPort);
257   setListen(queueLen);
258 }
259
260 TCPServerSocket::TCPServerSocket(const string &localAddress, 
261     unsigned short localPort, int queueLen) 
262     throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
263   setLocalAddressAndPort(localAddress, localPort);
264   setListen(queueLen);
265 }
266
267 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
268   int newConnSD;
269   if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
270     throw SocketException("Accept failed (accept())", true);
271   }
272
273   return new TCPSocket(newConnSD);
274 }
275
276 void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
277   if (listen(sockDesc, queueLen) < 0) {
278     throw SocketException("Set listening socket failed (listen())", true);
279   }
280 }
281
282 // UDPSocket Code
283
284 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
285     IPPROTO_UDP) {
286   setBroadcast();
287 }
288
289 UDPSocket::UDPSocket(unsigned short localPort)  throw(SocketException) : 
290     CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
291   setLocalPort(localPort);
292   setBroadcast();
293 }
294
295 UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort) 
296      throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
297   setLocalAddressAndPort(localAddress, localPort);
298   setBroadcast();
299 }
300
301 void UDPSocket::setBroadcast() {
302   // If this fails, we'll hear about it when we try to send.  This will allow 
303   // system that cannot broadcast to continue if they don't plan to broadcast
304   int broadcastPermission = 1;
305   setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST, 
306              (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
307 }
308
309 void UDPSocket::disconnect() throw(SocketException) {
310   sockaddr_in nullAddr;
311   memset(&nullAddr, 0, sizeof(nullAddr));
312   nullAddr.sin_family = AF_UNSPEC;
313
314   // Try to disconnect
315   if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
316    #ifdef WIN32
317     if (errno != WSAEAFNOSUPPORT) {
318    #else
319     if (errno != EAFNOSUPPORT) {
320    #endif
321       throw SocketException("Disconnect failed (connect())", true);
322     }
323   }
324 }
325
326 void UDPSocket::sendTo(const void *buffer, int bufferLen, 
327     const string &foreignAddress, unsigned short foreignPort) 
328     throw(SocketException) {
329   sockaddr_in destAddr;
330   fillAddr(foreignAddress, foreignPort, destAddr);
331
332   // Write out the whole buffer as a single message.
333   if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
334              (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
335     throw SocketException("Send failed (sendto())", true);
336   }
337 }
338
339 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
340     unsigned short &sourcePort) throw(SocketException) {
341   sockaddr_in clntAddr;
342   socklen_t addrLen = sizeof(clntAddr);
343   int rtn;
344   if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0, 
345                       (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
346     throw SocketException("Receive failed (recvfrom())", true);
347   }
348   sourceAddress = inet_ntoa(clntAddr.sin_addr);
349   sourcePort = ntohs(clntAddr.sin_port);
350
351   return rtn;
352 }
353
354 void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
355   if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL, 
356                  (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
357     throw SocketException("Multicast TTL set failed (setsockopt())", true);
358   }
359 }
360
361 void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
362   struct ip_mreq multicastRequest;
363
364   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
365   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
366   if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP, 
367                  (raw_type *) &multicastRequest, 
368                  sizeof(multicastRequest)) < 0) {
369     throw SocketException("Multicast group join failed (setsockopt())", true);
370   }
371 }
372
373 void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
374   struct ip_mreq multicastRequest;
375
376   multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
377   multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
378   if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP, 
379                  (raw_type *) &multicastRequest, 
380                  sizeof(multicastRequest)) < 0) {
381     throw SocketException("Multicast group leave failed (setsockopt())", true);
382   }
383 }