added OnConnect Callback
[anytun.git] / src / PracticalSocket.cpp
blob6f53da63a2313d78c6091ed0bf91de8aeff821c8
1 /*
2 * anytun
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
38 * Copyright (C) 2002
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"
57 #ifdef WIN32
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
61 #else
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
68 #include <poll.h>
69 typedef void raw_type; // Type used for raw data on this platform
70 #endif
72 #include <cstring> // for strerror_r
73 #include <errno.h> // For errno
75 using namespace std;
77 #ifdef WIN32
78 static bool initialized = false;
79 #endif
81 // SocketException Code
83 SocketException::SocketException(const string &message, bool inclSysMsg)
84 throw() : userMessage(message) {
85 if (inclSysMsg) {
86 userMessage.append(": ");
87 char buf[STERROR_TEXT_MAX];
88 buf[0] = 0;
89 strerror_r(errno, buf, STERROR_TEXT_MAX);
90 userMessage.append(buf);
94 SocketException::~SocketException() throw() {
97 const char *SocketException::what() const throw() {
98 return userMessage.c_str();
101 // Function to fill in address structure given an address and port
102 static void fillAddr(const string &address, unsigned short port,
103 sockaddr_in &addr) {
104 memset(&addr, 0, sizeof(addr)); // Zero out address structure
105 addr.sin_family = AF_INET; // Internet address
107 hostent *host; // Resolve name
108 if ((host = gethostbyname(address.c_str())) == NULL) {
109 // strerror() will not work for gethostbyname() and hstrerror()
110 // is supposedly obsolete
111 throw SocketException("Failed to resolve name (gethostbyname())");
113 addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
115 addr.sin_port = htons(port); // Assign port in network byte order
118 // Socket Code
120 Socket::Socket(int type, int protocol) throw(SocketException) {
121 #ifdef WIN32
122 if (!initialized) {
123 WORD wVersionRequested;
124 WSADATA wsaData;
126 wVersionRequested = MAKEWORD(2, 0); // Request WinSock v2.0
127 if (WSAStartup(wVersionRequested, &wsaData) != 0) { // Load WinSock DLL
128 throw SocketException("Unable to load WinSock DLL");
130 initialized = true;
132 #endif
134 // Make a new socket
135 if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
136 throw SocketException("Socket creation failed (socket())", true);
140 Socket::Socket(int sockDesc) {
141 this->sockDesc = sockDesc;
144 Socket::~Socket() {
145 #ifdef WIN32
146 ::closesocket(sockDesc);
147 #else
148 ::close(sockDesc);
149 #endif
150 sockDesc = -1;
153 string Socket::getLocalAddress() throw(SocketException) {
154 sockaddr_in addr;
155 unsigned int addr_len = sizeof(addr);
157 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
158 throw SocketException("Fetch of local address failed (getsockname())", true);
160 return inet_ntoa(addr.sin_addr);
163 unsigned short Socket::getLocalPort() throw(SocketException) {
164 sockaddr_in addr;
165 unsigned int addr_len = sizeof(addr);
167 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
168 throw SocketException("Fetch of local port failed (getsockname())", true);
170 return ntohs(addr.sin_port);
173 void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
174 // Bind the socket to its port
175 sockaddr_in localAddr;
176 memset(&localAddr, 0, sizeof(localAddr));
177 localAddr.sin_family = AF_INET;
178 localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
179 localAddr.sin_port = htons(localPort);
181 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
182 throw SocketException("Set of local port failed (bind())", true);
186 void Socket::setLocalAddressAndPort(const string &localAddress,
187 unsigned short localPort) throw(SocketException) {
188 // Get the address of the requested host
189 sockaddr_in localAddr;
190 fillAddr(localAddress, localPort, localAddr);
192 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
193 throw SocketException("Set of local address and port failed (bind())", true);
197 void Socket::setSocketOpt(int optionName, const void* optionValue, socklen_t optionLen)
198 throw(SocketException)
200 if (::setsockopt(sockDesc, SOL_SOCKET, optionName, optionValue, optionLen) < 0) {
201 throw SocketException("setSockopt failed", true);
205 void Socket::cleanUp() throw(SocketException) {
206 #ifdef WIN32
207 if (WSACleanup() != 0) {
208 throw SocketException("WSACleanup() failed");
210 #endif
213 unsigned short Socket::resolveService(const string &service,
214 const string &protocol) {
215 struct servent *serv; /* Structure containing service information */
217 if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
218 return atoi(service.c_str()); /* Service is port number */
219 else
220 return ntohs(serv->s_port); /* Found port (network byte order) by name */
223 // CommunicatingSocket Code
225 CommunicatingSocket::CommunicatingSocket(int type, int protocol)
226 throw(SocketException) : Socket(type, protocol) {
229 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
232 void CommunicatingSocket::connect(const string &foreignAddress,
233 unsigned short foreignPort) throw(SocketException) {
234 // Get the address of the requested host
235 sockaddr_in destAddr;
236 fillAddr(foreignAddress, foreignPort, destAddr);
238 // Try to connect to the given port
239 if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
240 throw SocketException("Connect failed (connect())", true);
244 void CommunicatingSocket::send(const void *buffer, int bufferLen)
245 throw(SocketException) {
246 if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
247 throw SocketException("Send failed (send())", true);
251 int CommunicatingSocket::recv(void *buffer, int bufferLen)
252 throw(SocketException) {
253 int rtn;
254 if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
255 throw SocketException("Received failed (recv())", true);
258 return rtn;
261 int CommunicatingSocket::recvNonBlocking(void *buffer, int bufferLen, int timeOut)
262 throw(SocketException)
264 struct pollfd pfd[1];
265 pfd[0].fd = sockDesc;
266 pfd[0].events = POLLIN;
267 int rtn = poll(pfd,1,timeOut);
268 if(rtn > 0) {
269 if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
270 throw SocketException("non blocking receive failed", true);
272 if(!rtn) {
273 throw SocketException("connection closed by peer", false);
276 return rtn;
279 string CommunicatingSocket::getForeignAddress()
280 throw(SocketException) {
281 sockaddr_in addr;
282 unsigned int addr_len = sizeof(addr);
284 if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
285 throw SocketException("Fetch of foreign address failed (getpeername())", true);
287 return inet_ntoa(addr.sin_addr);
290 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
291 sockaddr_in addr;
292 unsigned int addr_len = sizeof(addr);
294 if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
295 throw SocketException("Fetch of foreign port failed (getpeername())", true);
297 return ntohs(addr.sin_port);
300 // TCPSocket Code
302 TCPSocket::TCPSocket()
303 throw(SocketException) : CommunicatingSocket(SOCK_STREAM,
304 IPPROTO_TCP) {
307 TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort)
308 throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
309 connect(foreignAddress, foreignPort);
312 TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
315 // TCPServerSocket Code
317 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen)
318 throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
319 const int opt = 1;
320 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
321 setLocalPort(localPort);
322 setListen(queueLen);
325 TCPServerSocket::TCPServerSocket(const string &localAddress,
326 unsigned short localPort, int queueLen)
327 throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
328 const int opt = 1;
329 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
330 setLocalAddressAndPort(localAddress, localPort);
331 setListen(queueLen);
334 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
335 int newConnSD;
336 if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
337 throw SocketException("Accept failed (accept())", true);
340 return new TCPSocket(newConnSD);
343 void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
344 if (listen(sockDesc, queueLen) < 0) {
345 throw SocketException("Set listening socket failed (listen())", true);
349 // UDPSocket Code
351 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
352 IPPROTO_UDP) {
354 const int opt = 1;
355 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
356 setBroadcast();
359 UDPSocket::UDPSocket(unsigned short localPort) throw(SocketException) :
360 CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
361 const int opt = 1;
362 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
363 setLocalPort(localPort);
364 setBroadcast();
367 UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort)
368 throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
369 const int opt = 1;
370 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
371 setLocalAddressAndPort(localAddress, localPort);
372 setBroadcast();
375 void UDPSocket::setBroadcast() {
376 // If this fails, we'll hear about it when we try to send. This will allow
377 // system that cannot broadcast to continue if they don't plan to broadcast
378 int broadcastPermission = 1;
379 setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST,
380 (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
383 void UDPSocket::disconnect() throw(SocketException) {
384 sockaddr_in nullAddr;
385 memset(&nullAddr, 0, sizeof(nullAddr));
386 nullAddr.sin_family = AF_UNSPEC;
388 // Try to disconnect
389 if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
390 #ifdef WIN32
391 if (errno != WSAEAFNOSUPPORT) {
392 #else
393 if (errno != EAFNOSUPPORT) {
394 #endif
395 throw SocketException("Disconnect failed (connect())", true);
400 void UDPSocket::sendTo(const void *buffer, int bufferLen,
401 const string &foreignAddress, unsigned short foreignPort)
402 throw(SocketException) {
403 sockaddr_in destAddr;
404 fillAddr(foreignAddress, foreignPort, destAddr);
406 // Write out the whole buffer as a single message.
407 if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
408 (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
409 throw SocketException("Send failed (sendto())", true);
413 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
414 unsigned short &sourcePort) throw(SocketException) {
415 sockaddr_in clntAddr;
416 socklen_t addrLen = sizeof(clntAddr);
417 int rtn;
418 if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0,
419 (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
420 throw SocketException("Receive failed (recvfrom())", true);
422 sourceAddress = inet_ntoa(clntAddr.sin_addr);
423 sourcePort = ntohs(clntAddr.sin_port);
425 return rtn;
428 int UDPSocket::recvFromNonBlocking(void *buffer, int bufferLen, string &sourceAddress,
429 unsigned short &sourcePort, int timeOut) throw(SocketException) {
430 sockaddr_in clntAddr;
431 socklen_t addrLen = sizeof(clntAddr);
432 struct pollfd pfd[1];
433 pfd[0].fd = sockDesc;
434 pfd[0].events = POLLIN;
435 int rtn = poll(pfd,1,timeOut);
436 if(rtn > 0) {
437 if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0,
438 (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
439 throw SocketException("Receive failed (recvfrom())", true);
441 if(!rtn) {
442 throw SocketException("connection closed by peer", false);
445 sourceAddress = inet_ntoa(clntAddr.sin_addr);
446 sourcePort = ntohs(clntAddr.sin_port);
448 return rtn;
451 void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
452 if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL,
453 (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
454 throw SocketException("Multicast TTL set failed (setsockopt())", true);
458 void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
459 struct ip_mreq multicastRequest;
461 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
462 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
463 if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
464 (raw_type *) &multicastRequest,
465 sizeof(multicastRequest)) < 0) {
466 throw SocketException("Multicast group join failed (setsockopt())", true);
470 void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
471 struct ip_mreq multicastRequest;
473 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
474 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
475 if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,
476 (raw_type *) &multicastRequest,
477 sizeof(multicastRequest)) < 0) {
478 throw SocketException("Multicast group leave failed (setsockopt())", true);