CSL 5.2

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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
56 SocketException::~SocketException() throw() {
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
106 Socket::~Socket() {
107 #ifdef WIN32
108 ::closesocket(sockDesc);
109 #else
110 ::close(sockDesc);
111 #endif
112 sockDesc = -1;
113 }
114
115 string Socket::getLocalAddress() throw(SocketException) {
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
159 void Socket::cleanUp() throw(SocketException) {
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
179 CommunicatingSocket::CommunicatingSocket(int type, int protocol)
180 throw(SocketException) : Socket(type, protocol) {
181 }
182
183 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
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
215 string CommunicatingSocket::getForeignAddress()
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
226 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
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
238 TCPSocket::TCPSocket()
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
266 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
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
283 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
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
300 void UDPSocket::setBroadcast() {
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
308 void UDPSocket::disconnect() throw(SocketException) {
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 }