4 * The secure anycast tunneling protocol (satp) defines a protocol used
5 * for communication between any combination of unicast and anycast
6 * tunnel endpoints. It has less protocol overhead than IPSec in Tunnel
7 * mode and allows tunneling of every ETHER TYPE protocol (e.g.
8 * ethernet, ip, arp ...). satp directly includes cryptography and
9 * message authentication based on the methodes used by SRTP. It is
10 * intended to deliver a generic, scaleable and secure solution for
11 * tunneling and relaying of packets of any protocol.
14 * Copyright (C) 2007 anytun.org <satp@wirdorange.org>
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2
18 * as published by the Free Software Foundation.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program (see the file COPYING included with this
27 * distribution); if not, write to the Free Software Foundation, Inc.,
28 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 // this is from: http://cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical/
32 // and this is their header:
34 * C++ sockets on Unix and Windows
37 * This program is free software; you can redistribute it and/or modify
38 * it under the terms of the GNU General Public License as published by
39 * the Free Software Foundation; either version 2 of the License, or
40 * (at your option) any later version.
42 * This program is distributed in the hope that it will be useful,
43 * but WITHOUT ANY WARRANTY; without even the implied warranty of
44 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 * GNU General Public License for more details.
47 * You should have received a copy of the GNU General Public License
48 * along with this program; if not, write to the Free Software
49 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
52 #include "PracticalSocket.h"
55 #include <winsock.h> // For socket(), connect(), send(), and recv()
56 typedef int socklen_t
;
57 typedef char raw_type
; // Type used for raw data on this platform
59 #include <sys/types.h> // For data types
60 #include <sys/socket.h> // For socket(), connect(), send(), and recv()
61 #include <netdb.h> // For gethostbyname()
62 #include <arpa/inet.h> // For inet_addr()
63 #include <unistd.h> // For close()
64 #include <netinet/in.h> // For sockaddr_in
65 typedef void raw_type
; // Type used for raw data on this platform
68 #include <errno.h> // For errno
73 static bool initialized
= false;
76 // SocketException Code
78 SocketException::SocketException(const string
&message
, bool inclSysMsg
)
79 throw() : userMessage(message
) {
81 userMessage
.append(": ");
82 userMessage
.append(strerror(errno
));
86 SocketException::~SocketException() throw() {
89 const char *SocketException::what() const throw() {
90 return userMessage
.c_str();
93 // Function to fill in address structure given an address and port
94 static void fillAddr(const string
&address
, unsigned short port
,
96 memset(&addr
, 0, sizeof(addr
)); // Zero out address structure
97 addr
.sin_family
= AF_INET
; // Internet address
99 hostent
*host
; // Resolve name
100 if ((host
= gethostbyname(address
.c_str())) == NULL
) {
101 // strerror() will not work for gethostbyname() and hstrerror()
102 // is supposedly obsolete
103 throw SocketException("Failed to resolve name (gethostbyname())");
105 addr
.sin_addr
.s_addr
= *((unsigned long *) host
->h_addr_list
[0]);
107 addr
.sin_port
= htons(port
); // Assign port in network byte order
112 Socket::Socket(int type
, int protocol
) throw(SocketException
) {
115 WORD wVersionRequested
;
118 wVersionRequested
= MAKEWORD(2, 0); // Request WinSock v2.0
119 if (WSAStartup(wVersionRequested
, &wsaData
) != 0) { // Load WinSock DLL
120 throw SocketException("Unable to load WinSock DLL");
127 if ((sockDesc
= socket(PF_INET
, type
, protocol
)) < 0) {
128 throw SocketException("Socket creation failed (socket())", true);
132 Socket::Socket(int sockDesc
) {
133 this->sockDesc
= sockDesc
;
138 ::closesocket(sockDesc
);
145 string
Socket::getLocalAddress() throw(SocketException
) {
147 unsigned int addr_len
= sizeof(addr
);
149 if (getsockname(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
150 throw SocketException("Fetch of local address failed (getsockname())", true);
152 return inet_ntoa(addr
.sin_addr
);
155 unsigned short Socket::getLocalPort() throw(SocketException
) {
157 unsigned int addr_len
= sizeof(addr
);
159 if (getsockname(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
160 throw SocketException("Fetch of local port failed (getsockname())", true);
162 return ntohs(addr
.sin_port
);
165 void Socket::setLocalPort(unsigned short localPort
) throw(SocketException
) {
166 // Bind the socket to its port
167 sockaddr_in localAddr
;
168 memset(&localAddr
, 0, sizeof(localAddr
));
169 localAddr
.sin_family
= AF_INET
;
170 localAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
171 localAddr
.sin_port
= htons(localPort
);
173 if (bind(sockDesc
, (sockaddr
*) &localAddr
, sizeof(sockaddr_in
)) < 0) {
174 throw SocketException("Set of local port failed (bind())", true);
178 void Socket::setLocalAddressAndPort(const string
&localAddress
,
179 unsigned short localPort
) throw(SocketException
) {
180 // Get the address of the requested host
181 sockaddr_in localAddr
;
182 fillAddr(localAddress
, localPort
, localAddr
);
184 if (bind(sockDesc
, (sockaddr
*) &localAddr
, sizeof(sockaddr_in
)) < 0) {
185 throw SocketException("Set of local address and port failed (bind())", true);
189 void Socket::cleanUp() throw(SocketException
) {
191 if (WSACleanup() != 0) {
192 throw SocketException("WSACleanup() failed");
197 unsigned short Socket::resolveService(const string
&service
,
198 const string
&protocol
) {
199 struct servent
*serv
; /* Structure containing service information */
201 if ((serv
= getservbyname(service
.c_str(), protocol
.c_str())) == NULL
)
202 return atoi(service
.c_str()); /* Service is port number */
204 return ntohs(serv
->s_port
); /* Found port (network byte order) by name */
207 // CommunicatingSocket Code
209 CommunicatingSocket::CommunicatingSocket(int type
, int protocol
)
210 throw(SocketException
) : Socket(type
, protocol
) {
213 CommunicatingSocket::CommunicatingSocket(int newConnSD
) : Socket(newConnSD
) {
216 void CommunicatingSocket::connect(const string
&foreignAddress
,
217 unsigned short foreignPort
) throw(SocketException
) {
218 // Get the address of the requested host
219 sockaddr_in destAddr
;
220 fillAddr(foreignAddress
, foreignPort
, destAddr
);
222 // Try to connect to the given port
223 if (::connect(sockDesc
, (sockaddr
*) &destAddr
, sizeof(destAddr
)) < 0) {
224 throw SocketException("Connect failed (connect())", true);
228 void CommunicatingSocket::send(const void *buffer
, int bufferLen
)
229 throw(SocketException
) {
230 if (::send(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0) < 0) {
231 throw SocketException("Send failed (send())", true);
235 int CommunicatingSocket::recv(void *buffer
, int bufferLen
)
236 throw(SocketException
) {
238 if ((rtn
= ::recv(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0)) < 0) {
239 throw SocketException("Received failed (recv())", true);
245 string
CommunicatingSocket::getForeignAddress()
246 throw(SocketException
) {
248 unsigned int addr_len
= sizeof(addr
);
250 if (getpeername(sockDesc
, (sockaddr
*) &addr
,(socklen_t
*) &addr_len
) < 0) {
251 throw SocketException("Fetch of foreign address failed (getpeername())", true);
253 return inet_ntoa(addr
.sin_addr
);
256 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException
) {
258 unsigned int addr_len
= sizeof(addr
);
260 if (getpeername(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
261 throw SocketException("Fetch of foreign port failed (getpeername())", true);
263 return ntohs(addr
.sin_port
);
268 TCPSocket::TCPSocket()
269 throw(SocketException
) : CommunicatingSocket(SOCK_STREAM
,
273 TCPSocket::TCPSocket(const string
&foreignAddress
, unsigned short foreignPort
)
274 throw(SocketException
) : CommunicatingSocket(SOCK_STREAM
, IPPROTO_TCP
) {
275 connect(foreignAddress
, foreignPort
);
278 TCPSocket::TCPSocket(int newConnSD
) : CommunicatingSocket(newConnSD
) {
281 // TCPServerSocket Code
283 TCPServerSocket::TCPServerSocket(unsigned short localPort
, int queueLen
)
284 throw(SocketException
) : Socket(SOCK_STREAM
, IPPROTO_TCP
) {
285 setLocalPort(localPort
);
289 TCPServerSocket::TCPServerSocket(const string
&localAddress
,
290 unsigned short localPort
, int queueLen
)
291 throw(SocketException
) : Socket(SOCK_STREAM
, IPPROTO_TCP
) {
292 setLocalAddressAndPort(localAddress
, localPort
);
296 TCPSocket
*TCPServerSocket::accept() throw(SocketException
) {
298 if ((newConnSD
= ::accept(sockDesc
, NULL
, 0)) < 0) {
299 throw SocketException("Accept failed (accept())", true);
302 return new TCPSocket(newConnSD
);
305 void TCPServerSocket::setListen(int queueLen
) throw(SocketException
) {
306 if (listen(sockDesc
, queueLen
) < 0) {
307 throw SocketException("Set listening socket failed (listen())", true);
313 UDPSocket::UDPSocket() throw(SocketException
) : CommunicatingSocket(SOCK_DGRAM
,
318 UDPSocket::UDPSocket(unsigned short localPort
) throw(SocketException
) :
319 CommunicatingSocket(SOCK_DGRAM
, IPPROTO_UDP
) {
320 setLocalPort(localPort
);
324 UDPSocket::UDPSocket(const string
&localAddress
, unsigned short localPort
)
325 throw(SocketException
) : CommunicatingSocket(SOCK_DGRAM
, IPPROTO_UDP
) {
326 setLocalAddressAndPort(localAddress
, localPort
);
330 void UDPSocket::setBroadcast() {
331 // If this fails, we'll hear about it when we try to send. This will allow
332 // system that cannot broadcast to continue if they don't plan to broadcast
333 int broadcastPermission
= 1;
334 setsockopt(sockDesc
, SOL_SOCKET
, SO_BROADCAST
,
335 (raw_type
*) &broadcastPermission
, sizeof(broadcastPermission
));
338 void UDPSocket::disconnect() throw(SocketException
) {
339 sockaddr_in nullAddr
;
340 memset(&nullAddr
, 0, sizeof(nullAddr
));
341 nullAddr
.sin_family
= AF_UNSPEC
;
344 if (::connect(sockDesc
, (sockaddr
*) &nullAddr
, sizeof(nullAddr
)) < 0) {
346 if (errno
!= WSAEAFNOSUPPORT
) {
348 if (errno
!= EAFNOSUPPORT
) {
350 throw SocketException("Disconnect failed (connect())", true);
355 void UDPSocket::sendTo(const void *buffer
, int bufferLen
,
356 const string
&foreignAddress
, unsigned short foreignPort
)
357 throw(SocketException
) {
358 sockaddr_in destAddr
;
359 fillAddr(foreignAddress
, foreignPort
, destAddr
);
361 // Write out the whole buffer as a single message.
362 if (sendto(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0,
363 (sockaddr
*) &destAddr
, sizeof(destAddr
)) != bufferLen
) {
364 throw SocketException("Send failed (sendto())", true);
368 int UDPSocket::recvFrom(void *buffer
, int bufferLen
, string
&sourceAddress
,
369 unsigned short &sourcePort
) throw(SocketException
) {
370 sockaddr_in clntAddr
;
371 socklen_t addrLen
= sizeof(clntAddr
);
373 if ((rtn
= recvfrom(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0,
374 (sockaddr
*) &clntAddr
, (socklen_t
*) &addrLen
)) < 0) {
375 throw SocketException("Receive failed (recvfrom())", true);
377 sourceAddress
= inet_ntoa(clntAddr
.sin_addr
);
378 sourcePort
= ntohs(clntAddr
.sin_port
);
383 void UDPSocket::setMulticastTTL(unsigned char multicastTTL
) throw(SocketException
) {
384 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_MULTICAST_TTL
,
385 (raw_type
*) &multicastTTL
, sizeof(multicastTTL
)) < 0) {
386 throw SocketException("Multicast TTL set failed (setsockopt())", true);
390 void UDPSocket::joinGroup(const string
&multicastGroup
) throw(SocketException
) {
391 struct ip_mreq multicastRequest
;
393 multicastRequest
.imr_multiaddr
.s_addr
= inet_addr(multicastGroup
.c_str());
394 multicastRequest
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
395 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
396 (raw_type
*) &multicastRequest
,
397 sizeof(multicastRequest
)) < 0) {
398 throw SocketException("Multicast group join failed (setsockopt())", true);
402 void UDPSocket::leaveGroup(const string
&multicastGroup
) throw(SocketException
) {
403 struct ip_mreq multicastRequest
;
405 multicastRequest
.imr_multiaddr
.s_addr
= inet_addr(multicastGroup
.c_str());
406 multicastRequest
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
407 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
408 (raw_type
*) &multicastRequest
,
409 sizeof(multicastRequest
)) < 0) {
410 throw SocketException("Multicast group leave failed (setsockopt())", true);