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-2008 Othmar Gsenger, Erwin Nindl,
15 * Christian Pointner <satp@wirdorange.org>
17 * This file is part of Anytun.
19 * Anytun is free software: you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License version 3 as
21 * published by the Free Software Foundation.
23 * Anytun is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
28 * You should have received a copy of the GNU General Public License
29 * along with anytun. If not, see <http://www.gnu.org/licenses/>.
32 #include "datatypes.h"
34 // this is from: http://cs.ecs.baylor.edu/~donahoo/practical/CSockets/practical/
35 // and this is their header:
37 * C++ sockets on Unix and Windows
40 * This program is free software; you can redistribute it and/or modify
41 * it under the terms of the GNU General Public License as published by
42 * the Free Software Foundation; either version 2 of the License, or
43 * (at your option) any later version.
45 * This program is distributed in the hope that it will be useful,
46 * but WITHOUT ANY WARRANTY; without even the implied warranty of
47 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48 * GNU General Public License for more details.
50 * You should have received a copy of the GNU General Public License
51 * along with this program; if not, write to the Free Software
52 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
55 #include "PracticalSocket.h"
58 #include <winsock.h> // For socket(), connect(), send(), and recv()
59 typedef int socklen_t
;
60 typedef char raw_type
; // Type used for raw data on this platform
62 #include <sys/types.h> // For data types
63 #include <sys/socket.h> // For socket(), connect(), send(), and recv()
64 #include <netdb.h> // For gethostbyname()
65 #include <arpa/inet.h> // For inet_addr()
66 #include <unistd.h> // For close()
67 #include <netinet/in.h> // For sockaddr_in
69 typedef void raw_type
; // Type used for raw data on this platform
72 #include <errno.h> // For errno
77 static bool initialized
= false;
80 // SocketException Code
82 SocketException::SocketException(const string
&message
, bool inclSysMsg
)
83 throw() : userMessage(message
) {
85 userMessage
.append(": ");
86 char buf
[STERROR_TEXT_MAX
];
88 strerror_r(errno
, buf
, STERROR_TEXT_MAX
);
89 userMessage
.append(buf
);
93 SocketException::~SocketException() throw() {
96 const char *SocketException::what() const throw() {
97 return userMessage
.c_str();
100 // Function to fill in address structure given an address and port
101 static void fillAddr(const string
&address
, unsigned short port
,
103 memset(&addr
, 0, sizeof(addr
)); // Zero out address structure
104 addr
.sin_family
= AF_INET
; // Internet address
106 hostent
*host
; // Resolve name
107 if ((host
= gethostbyname(address
.c_str())) == NULL
) {
108 // strerror() will not work for gethostbyname() and hstrerror()
109 // is supposedly obsolete
110 throw SocketException("Failed to resolve name (gethostbyname())");
112 addr
.sin_addr
.s_addr
= *((unsigned long *) host
->h_addr_list
[0]);
114 addr
.sin_port
= htons(port
); // Assign port in network byte order
119 Socket::Socket(int type
, int protocol
) throw(SocketException
) {
122 WORD wVersionRequested
;
125 wVersionRequested
= MAKEWORD(2, 0); // Request WinSock v2.0
126 if (WSAStartup(wVersionRequested
, &wsaData
) != 0) { // Load WinSock DLL
127 throw SocketException("Unable to load WinSock DLL");
134 if ((sockDesc
= socket(PF_INET
, type
, protocol
)) < 0) {
135 throw SocketException("Socket creation failed (socket())", true);
139 Socket::Socket(int sockDesc
) {
140 this->sockDesc
= sockDesc
;
145 ::closesocket(sockDesc
);
152 string
Socket::getLocalAddress() throw(SocketException
) {
154 unsigned int addr_len
= sizeof(addr
);
156 if (getsockname(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
157 throw SocketException("Fetch of local address failed (getsockname())", true);
159 return inet_ntoa(addr
.sin_addr
);
162 unsigned short Socket::getLocalPort() throw(SocketException
) {
164 unsigned int addr_len
= sizeof(addr
);
166 if (getsockname(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
167 throw SocketException("Fetch of local port failed (getsockname())", true);
169 return ntohs(addr
.sin_port
);
172 void Socket::setLocalPort(unsigned short localPort
) throw(SocketException
) {
173 // Bind the socket to its port
174 sockaddr_in localAddr
;
175 memset(&localAddr
, 0, sizeof(localAddr
));
176 localAddr
.sin_family
= AF_INET
;
177 localAddr
.sin_addr
.s_addr
= htonl(INADDR_ANY
);
178 localAddr
.sin_port
= htons(localPort
);
180 if (bind(sockDesc
, (sockaddr
*) &localAddr
, sizeof(sockaddr_in
)) < 0) {
181 throw SocketException("Set of local port failed (bind())", true);
185 void Socket::setLocalAddressAndPort(const string
&localAddress
,
186 unsigned short localPort
) throw(SocketException
) {
187 // Get the address of the requested host
188 sockaddr_in localAddr
;
189 fillAddr(localAddress
, localPort
, localAddr
);
191 if (bind(sockDesc
, (sockaddr
*) &localAddr
, sizeof(sockaddr_in
)) < 0) {
192 throw SocketException("Set of local address and port failed (bind())", true);
196 void Socket::setSocketOpt(int optionName
, const void* optionValue
, socklen_t optionLen
)
197 throw(SocketException
)
199 if (::setsockopt(sockDesc
, SOL_SOCKET
, optionName
, optionValue
, optionLen
) < 0) {
200 throw SocketException("setSockopt failed", true);
204 void Socket::cleanUp() throw(SocketException
) {
206 if (WSACleanup() != 0) {
207 throw SocketException("WSACleanup() failed");
212 unsigned short Socket::resolveService(const string
&service
,
213 const string
&protocol
) {
214 struct servent
*serv
; /* Structure containing service information */
216 if ((serv
= getservbyname(service
.c_str(), protocol
.c_str())) == NULL
)
217 return atoi(service
.c_str()); /* Service is port number */
219 return ntohs(serv
->s_port
); /* Found port (network byte order) by name */
222 // CommunicatingSocket Code
224 CommunicatingSocket::CommunicatingSocket(int type
, int protocol
)
225 throw(SocketException
) : Socket(type
, protocol
) {
228 CommunicatingSocket::CommunicatingSocket(int newConnSD
) : Socket(newConnSD
) {
231 void CommunicatingSocket::connect(const string
&foreignAddress
,
232 unsigned short foreignPort
) throw(SocketException
) {
233 // Get the address of the requested host
234 sockaddr_in destAddr
;
235 fillAddr(foreignAddress
, foreignPort
, destAddr
);
237 // Try to connect to the given port
238 if (::connect(sockDesc
, (sockaddr
*) &destAddr
, sizeof(destAddr
)) < 0) {
239 throw SocketException("Connect failed (connect())", true);
243 void CommunicatingSocket::send(const void *buffer
, int bufferLen
)
244 throw(SocketException
) {
245 if (::send(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0) < 0) {
246 throw SocketException("Send failed (send())", true);
250 int CommunicatingSocket::recv(void *buffer
, int bufferLen
)
251 throw(SocketException
) {
253 if ((rtn
= ::recv(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0)) < 0) {
254 throw SocketException("Received failed (recv())", true);
260 int CommunicatingSocket::recvNonBlocking(void *buffer
, int bufferLen
, int timeOut
)
261 throw(SocketException
)
263 struct pollfd pfd
[1];
264 pfd
[0].fd
= sockDesc
;
265 pfd
[0].events
= POLLIN
;
266 int rtn
= poll(pfd
,1,timeOut
);
268 if ((rtn
= ::recv(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0)) < 0) {
269 throw SocketException("non blocking receive failed", true);
272 throw SocketException("connection closed by peer", false);
278 string
CommunicatingSocket::getForeignAddress()
279 throw(SocketException
) {
281 unsigned int addr_len
= sizeof(addr
);
283 if (getpeername(sockDesc
, (sockaddr
*) &addr
,(socklen_t
*) &addr_len
) < 0) {
284 throw SocketException("Fetch of foreign address failed (getpeername())", true);
286 return inet_ntoa(addr
.sin_addr
);
289 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException
) {
291 unsigned int addr_len
= sizeof(addr
);
293 if (getpeername(sockDesc
, (sockaddr
*) &addr
, (socklen_t
*) &addr_len
) < 0) {
294 throw SocketException("Fetch of foreign port failed (getpeername())", true);
296 return ntohs(addr
.sin_port
);
301 TCPSocket::TCPSocket()
302 throw(SocketException
) : CommunicatingSocket(SOCK_STREAM
,
306 TCPSocket::TCPSocket(const string
&foreignAddress
, unsigned short foreignPort
)
307 throw(SocketException
) : CommunicatingSocket(SOCK_STREAM
, IPPROTO_TCP
) {
308 connect(foreignAddress
, foreignPort
);
311 TCPSocket::TCPSocket(int newConnSD
) : CommunicatingSocket(newConnSD
) {
314 // TCPServerSocket Code
316 TCPServerSocket::TCPServerSocket(unsigned short localPort
, int queueLen
)
317 throw(SocketException
) : Socket(SOCK_STREAM
, IPPROTO_TCP
) {
319 setSocketOpt(SO_REUSEADDR
, &opt
, sizeof(opt
));
320 setLocalPort(localPort
);
324 TCPServerSocket::TCPServerSocket(const string
&localAddress
,
325 unsigned short localPort
, int queueLen
)
326 throw(SocketException
) : Socket(SOCK_STREAM
, IPPROTO_TCP
) {
328 setSocketOpt(SO_REUSEADDR
, &opt
, sizeof(opt
));
329 setLocalAddressAndPort(localAddress
, localPort
);
333 TCPSocket
*TCPServerSocket::accept() throw(SocketException
) {
335 if ((newConnSD
= ::accept(sockDesc
, NULL
, 0)) < 0) {
336 throw SocketException("Accept failed (accept())", true);
339 return new TCPSocket(newConnSD
);
342 void TCPServerSocket::setListen(int queueLen
) throw(SocketException
) {
343 if (listen(sockDesc
, queueLen
) < 0) {
344 throw SocketException("Set listening socket failed (listen())", true);
350 UDPSocket::UDPSocket() throw(SocketException
) : CommunicatingSocket(SOCK_DGRAM
,
354 setSocketOpt(SO_REUSEADDR
, &opt
, sizeof(opt
));
358 UDPSocket::UDPSocket(unsigned short localPort
) throw(SocketException
) :
359 CommunicatingSocket(SOCK_DGRAM
, IPPROTO_UDP
) {
361 setSocketOpt(SO_REUSEADDR
, &opt
, sizeof(opt
));
362 setLocalPort(localPort
);
366 UDPSocket::UDPSocket(const string
&localAddress
, unsigned short localPort
)
367 throw(SocketException
) : CommunicatingSocket(SOCK_DGRAM
, IPPROTO_UDP
) {
369 setSocketOpt(SO_REUSEADDR
, &opt
, sizeof(opt
));
370 setLocalAddressAndPort(localAddress
, localPort
);
374 void UDPSocket::setBroadcast() {
375 // If this fails, we'll hear about it when we try to send. This will allow
376 // system that cannot broadcast to continue if they don't plan to broadcast
377 int broadcastPermission
= 1;
378 setsockopt(sockDesc
, SOL_SOCKET
, SO_BROADCAST
,
379 (raw_type
*) &broadcastPermission
, sizeof(broadcastPermission
));
382 void UDPSocket::disconnect() throw(SocketException
) {
383 sockaddr_in nullAddr
;
384 memset(&nullAddr
, 0, sizeof(nullAddr
));
385 nullAddr
.sin_family
= AF_UNSPEC
;
388 if (::connect(sockDesc
, (sockaddr
*) &nullAddr
, sizeof(nullAddr
)) < 0) {
390 if (errno
!= WSAEAFNOSUPPORT
) {
392 if (errno
!= EAFNOSUPPORT
) {
394 throw SocketException("Disconnect failed (connect())", true);
399 void UDPSocket::sendTo(const void *buffer
, int bufferLen
,
400 const string
&foreignAddress
, unsigned short foreignPort
)
401 throw(SocketException
) {
402 sockaddr_in destAddr
;
403 fillAddr(foreignAddress
, foreignPort
, destAddr
);
405 // Write out the whole buffer as a single message.
406 if (sendto(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0,
407 (sockaddr
*) &destAddr
, sizeof(destAddr
)) != bufferLen
) {
408 throw SocketException("Send failed (sendto())", true);
412 int UDPSocket::recvFrom(void *buffer
, int bufferLen
, string
&sourceAddress
,
413 unsigned short &sourcePort
) throw(SocketException
) {
414 sockaddr_in clntAddr
;
415 socklen_t addrLen
= sizeof(clntAddr
);
417 if ((rtn
= recvfrom(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0,
418 (sockaddr
*) &clntAddr
, (socklen_t
*) &addrLen
)) < 0) {
419 throw SocketException("Receive failed (recvfrom())", true);
421 sourceAddress
= inet_ntoa(clntAddr
.sin_addr
);
422 sourcePort
= ntohs(clntAddr
.sin_port
);
427 int UDPSocket::recvFromNonBlocking(void *buffer
, int bufferLen
, string
&sourceAddress
,
428 unsigned short &sourcePort
, int timeOut
) throw(SocketException
) {
429 sockaddr_in clntAddr
;
430 socklen_t addrLen
= sizeof(clntAddr
);
431 struct pollfd pfd
[1];
432 pfd
[0].fd
= sockDesc
;
433 pfd
[0].events
= POLLIN
;
434 int rtn
= poll(pfd
,1,timeOut
);
436 if ((rtn
= recvfrom(sockDesc
, (raw_type
*) buffer
, bufferLen
, 0,
437 (sockaddr
*) &clntAddr
, (socklen_t
*) &addrLen
)) < 0) {
438 throw SocketException("Receive failed (recvfrom())", true);
441 throw SocketException("connection closed by peer", false);
444 sourceAddress
= inet_ntoa(clntAddr
.sin_addr
);
445 sourcePort
= ntohs(clntAddr
.sin_port
);
450 void UDPSocket::setMulticastTTL(unsigned char multicastTTL
) throw(SocketException
) {
451 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_MULTICAST_TTL
,
452 (raw_type
*) &multicastTTL
, sizeof(multicastTTL
)) < 0) {
453 throw SocketException("Multicast TTL set failed (setsockopt())", true);
457 void UDPSocket::joinGroup(const string
&multicastGroup
) throw(SocketException
) {
458 struct ip_mreq multicastRequest
;
460 multicastRequest
.imr_multiaddr
.s_addr
= inet_addr(multicastGroup
.c_str());
461 multicastRequest
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
462 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
,
463 (raw_type
*) &multicastRequest
,
464 sizeof(multicastRequest
)) < 0) {
465 throw SocketException("Multicast group join failed (setsockopt())", true);
469 void UDPSocket::leaveGroup(const string
&multicastGroup
) throw(SocketException
) {
470 struct ip_mreq multicastRequest
;
472 multicastRequest
.imr_multiaddr
.s_addr
= inet_addr(multicastGroup
.c_str());
473 multicastRequest
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
474 if (setsockopt(sockDesc
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
,
475 (raw_type
*) &multicastRequest
,
476 sizeof(multicastRequest
)) < 0) {
477 throw SocketException("Multicast group leave failed (setsockopt())", true);