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