working version with crypto
[anytun.git] / PracticalSocket.cpp
blob6f7b51c0422f003c6889b19f4ef4b235b7415d1c
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 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
35 * Copyright (C) 2002
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"
54 #ifdef WIN32
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
58 #else
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 #include <poll.h>
66 typedef void raw_type; // Type used for raw data on this platform
67 #endif
69 #include <errno.h> // For errno
71 using namespace std;
73 #ifdef WIN32
74 static bool initialized = false;
75 #endif
77 // SocketException Code
79 SocketException::SocketException(const string &message, bool inclSysMsg)
80 throw() : userMessage(message) {
81 if (inclSysMsg) {
82 userMessage.append(": ");
83 userMessage.append(strerror(errno));
87 SocketException::~SocketException() throw() {
90 const char *SocketException::what() const throw() {
91 return userMessage.c_str();
94 // Function to fill in address structure given an address and port
95 static void fillAddr(const string &address, unsigned short port,
96 sockaddr_in &addr) {
97 memset(&addr, 0, sizeof(addr)); // Zero out address structure
98 addr.sin_family = AF_INET; // Internet address
100 hostent *host; // Resolve name
101 if ((host = gethostbyname(address.c_str())) == NULL) {
102 // strerror() will not work for gethostbyname() and hstrerror()
103 // is supposedly obsolete
104 throw SocketException("Failed to resolve name (gethostbyname())");
106 addr.sin_addr.s_addr = *((unsigned long *) host->h_addr_list[0]);
108 addr.sin_port = htons(port); // Assign port in network byte order
111 // Socket Code
113 Socket::Socket(int type, int protocol) throw(SocketException) {
114 #ifdef WIN32
115 if (!initialized) {
116 WORD wVersionRequested;
117 WSADATA wsaData;
119 wVersionRequested = MAKEWORD(2, 0); // Request WinSock v2.0
120 if (WSAStartup(wVersionRequested, &wsaData) != 0) { // Load WinSock DLL
121 throw SocketException("Unable to load WinSock DLL");
123 initialized = true;
125 #endif
127 // Make a new socket
128 if ((sockDesc = socket(PF_INET, type, protocol)) < 0) {
129 throw SocketException("Socket creation failed (socket())", true);
133 Socket::Socket(int sockDesc) {
134 this->sockDesc = sockDesc;
137 Socket::~Socket() {
138 #ifdef WIN32
139 ::closesocket(sockDesc);
140 #else
141 ::close(sockDesc);
142 #endif
143 sockDesc = -1;
146 string Socket::getLocalAddress() throw(SocketException) {
147 sockaddr_in addr;
148 unsigned int addr_len = sizeof(addr);
150 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
151 throw SocketException("Fetch of local address failed (getsockname())", true);
153 return inet_ntoa(addr.sin_addr);
156 unsigned short Socket::getLocalPort() throw(SocketException) {
157 sockaddr_in addr;
158 unsigned int addr_len = sizeof(addr);
160 if (getsockname(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
161 throw SocketException("Fetch of local port failed (getsockname())", true);
163 return ntohs(addr.sin_port);
166 void Socket::setLocalPort(unsigned short localPort) throw(SocketException) {
167 // Bind the socket to its port
168 sockaddr_in localAddr;
169 memset(&localAddr, 0, sizeof(localAddr));
170 localAddr.sin_family = AF_INET;
171 localAddr.sin_addr.s_addr = htonl(INADDR_ANY);
172 localAddr.sin_port = htons(localPort);
174 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
175 throw SocketException("Set of local port failed (bind())", true);
179 void Socket::setLocalAddressAndPort(const string &localAddress,
180 unsigned short localPort) throw(SocketException) {
181 // Get the address of the requested host
182 sockaddr_in localAddr;
183 fillAddr(localAddress, localPort, localAddr);
185 if (bind(sockDesc, (sockaddr *) &localAddr, sizeof(sockaddr_in)) < 0) {
186 throw SocketException("Set of local address and port failed (bind())", true);
190 void Socket::setSocketOpt(int optionName, const void* optionValue, socklen_t optionLen)
191 throw(SocketException)
193 if (::setsockopt(sockDesc, SOL_SOCKET, optionName, optionValue, optionLen) < 0) {
194 throw SocketException("setSockopt failed", true);
198 void Socket::cleanUp() throw(SocketException) {
199 #ifdef WIN32
200 if (WSACleanup() != 0) {
201 throw SocketException("WSACleanup() failed");
203 #endif
206 unsigned short Socket::resolveService(const string &service,
207 const string &protocol) {
208 struct servent *serv; /* Structure containing service information */
210 if ((serv = getservbyname(service.c_str(), protocol.c_str())) == NULL)
211 return atoi(service.c_str()); /* Service is port number */
212 else
213 return ntohs(serv->s_port); /* Found port (network byte order) by name */
216 // CommunicatingSocket Code
218 CommunicatingSocket::CommunicatingSocket(int type, int protocol)
219 throw(SocketException) : Socket(type, protocol) {
222 CommunicatingSocket::CommunicatingSocket(int newConnSD) : Socket(newConnSD) {
225 void CommunicatingSocket::connect(const string &foreignAddress,
226 unsigned short foreignPort) throw(SocketException) {
227 // Get the address of the requested host
228 sockaddr_in destAddr;
229 fillAddr(foreignAddress, foreignPort, destAddr);
231 // Try to connect to the given port
232 if (::connect(sockDesc, (sockaddr *) &destAddr, sizeof(destAddr)) < 0) {
233 throw SocketException("Connect failed (connect())", true);
237 void CommunicatingSocket::send(const void *buffer, int bufferLen)
238 throw(SocketException) {
239 if (::send(sockDesc, (raw_type *) buffer, bufferLen, 0) < 0) {
240 throw SocketException("Send failed (send())", true);
244 int CommunicatingSocket::recv(void *buffer, int bufferLen)
245 throw(SocketException) {
246 int rtn;
247 if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
248 throw SocketException("Received failed (recv())", true);
251 return rtn;
254 int CommunicatingSocket::recvNonBlocking(void *buffer, int bufferLen, int timeOut)
255 throw(SocketException)
257 struct pollfd pfd[1];
258 pfd[0].fd = sockDesc;
259 pfd[0].events = POLLIN;
260 int rtn = poll(pfd,1,timeOut);
261 if(rtn > 0) {
262 if ((rtn = ::recv(sockDesc, (raw_type *) buffer, bufferLen, 0)) < 0) {
263 throw SocketException("non blocking receive failed", true);
265 if(!rtn) {
266 throw SocketException("connection closed by peer", false);
269 return rtn;
272 string CommunicatingSocket::getForeignAddress()
273 throw(SocketException) {
274 sockaddr_in addr;
275 unsigned int addr_len = sizeof(addr);
277 if (getpeername(sockDesc, (sockaddr *) &addr,(socklen_t *) &addr_len) < 0) {
278 throw SocketException("Fetch of foreign address failed (getpeername())", true);
280 return inet_ntoa(addr.sin_addr);
283 unsigned short CommunicatingSocket::getForeignPort() throw(SocketException) {
284 sockaddr_in addr;
285 unsigned int addr_len = sizeof(addr);
287 if (getpeername(sockDesc, (sockaddr *) &addr, (socklen_t *) &addr_len) < 0) {
288 throw SocketException("Fetch of foreign port failed (getpeername())", true);
290 return ntohs(addr.sin_port);
293 // TCPSocket Code
295 TCPSocket::TCPSocket()
296 throw(SocketException) : CommunicatingSocket(SOCK_STREAM,
297 IPPROTO_TCP) {
300 TCPSocket::TCPSocket(const string &foreignAddress, unsigned short foreignPort)
301 throw(SocketException) : CommunicatingSocket(SOCK_STREAM, IPPROTO_TCP) {
302 connect(foreignAddress, foreignPort);
305 TCPSocket::TCPSocket(int newConnSD) : CommunicatingSocket(newConnSD) {
308 // TCPServerSocket Code
310 TCPServerSocket::TCPServerSocket(unsigned short localPort, int queueLen)
311 throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
312 const int opt = 1;
313 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
314 setLocalPort(localPort);
315 setListen(queueLen);
318 TCPServerSocket::TCPServerSocket(const string &localAddress,
319 unsigned short localPort, int queueLen)
320 throw(SocketException) : Socket(SOCK_STREAM, IPPROTO_TCP) {
321 const int opt = 1;
322 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
323 setLocalAddressAndPort(localAddress, localPort);
324 setListen(queueLen);
327 TCPSocket *TCPServerSocket::accept() throw(SocketException) {
328 int newConnSD;
329 if ((newConnSD = ::accept(sockDesc, NULL, 0)) < 0) {
330 throw SocketException("Accept failed (accept())", true);
333 return new TCPSocket(newConnSD);
336 void TCPServerSocket::setListen(int queueLen) throw(SocketException) {
337 if (listen(sockDesc, queueLen) < 0) {
338 throw SocketException("Set listening socket failed (listen())", true);
342 // UDPSocket Code
344 UDPSocket::UDPSocket() throw(SocketException) : CommunicatingSocket(SOCK_DGRAM,
345 IPPROTO_UDP) {
347 const int opt = 1;
348 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
349 setBroadcast();
352 UDPSocket::UDPSocket(unsigned short localPort) throw(SocketException) :
353 CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
354 const int opt = 1;
355 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
356 setLocalPort(localPort);
357 setBroadcast();
360 UDPSocket::UDPSocket(const string &localAddress, unsigned short localPort)
361 throw(SocketException) : CommunicatingSocket(SOCK_DGRAM, IPPROTO_UDP) {
362 const int opt = 1;
363 setSocketOpt(SO_REUSEADDR, &opt, sizeof(opt));
364 setLocalAddressAndPort(localAddress, localPort);
365 setBroadcast();
368 void UDPSocket::setBroadcast() {
369 // If this fails, we'll hear about it when we try to send. This will allow
370 // system that cannot broadcast to continue if they don't plan to broadcast
371 int broadcastPermission = 1;
372 setsockopt(sockDesc, SOL_SOCKET, SO_BROADCAST,
373 (raw_type *) &broadcastPermission, sizeof(broadcastPermission));
376 void UDPSocket::disconnect() throw(SocketException) {
377 sockaddr_in nullAddr;
378 memset(&nullAddr, 0, sizeof(nullAddr));
379 nullAddr.sin_family = AF_UNSPEC;
381 // Try to disconnect
382 if (::connect(sockDesc, (sockaddr *) &nullAddr, sizeof(nullAddr)) < 0) {
383 #ifdef WIN32
384 if (errno != WSAEAFNOSUPPORT) {
385 #else
386 if (errno != EAFNOSUPPORT) {
387 #endif
388 throw SocketException("Disconnect failed (connect())", true);
393 void UDPSocket::sendTo(const void *buffer, int bufferLen,
394 const string &foreignAddress, unsigned short foreignPort)
395 throw(SocketException) {
396 sockaddr_in destAddr;
397 fillAddr(foreignAddress, foreignPort, destAddr);
399 // Write out the whole buffer as a single message.
400 if (sendto(sockDesc, (raw_type *) buffer, bufferLen, 0,
401 (sockaddr *) &destAddr, sizeof(destAddr)) != bufferLen) {
402 throw SocketException("Send failed (sendto())", true);
406 int UDPSocket::recvFrom(void *buffer, int bufferLen, string &sourceAddress,
407 unsigned short &sourcePort) throw(SocketException) {
408 sockaddr_in clntAddr;
409 socklen_t addrLen = sizeof(clntAddr);
410 int rtn;
411 if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0,
412 (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
413 throw SocketException("Receive failed (recvfrom())", true);
415 sourceAddress = inet_ntoa(clntAddr.sin_addr);
416 sourcePort = ntohs(clntAddr.sin_port);
418 return rtn;
421 int UDPSocket::recvFromNonBlocking(void *buffer, int bufferLen, string &sourceAddress,
422 unsigned short &sourcePort, int timeOut) throw(SocketException) {
423 sockaddr_in clntAddr;
424 socklen_t addrLen = sizeof(clntAddr);
425 struct pollfd pfd[1];
426 pfd[0].fd = sockDesc;
427 pfd[0].events = POLLIN;
428 int rtn = poll(pfd,1,timeOut);
429 if(rtn > 0) {
430 if ((rtn = recvfrom(sockDesc, (raw_type *) buffer, bufferLen, 0,
431 (sockaddr *) &clntAddr, (socklen_t *) &addrLen)) < 0) {
432 throw SocketException("Receive failed (recvfrom())", true);
434 if(!rtn) {
435 throw SocketException("connection closed by peer", false);
438 sourceAddress = inet_ntoa(clntAddr.sin_addr);
439 sourcePort = ntohs(clntAddr.sin_port);
441 return rtn;
444 void UDPSocket::setMulticastTTL(unsigned char multicastTTL) throw(SocketException) {
445 if (setsockopt(sockDesc, IPPROTO_IP, IP_MULTICAST_TTL,
446 (raw_type *) &multicastTTL, sizeof(multicastTTL)) < 0) {
447 throw SocketException("Multicast TTL set failed (setsockopt())", true);
451 void UDPSocket::joinGroup(const string &multicastGroup) throw(SocketException) {
452 struct ip_mreq multicastRequest;
454 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
455 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
456 if (setsockopt(sockDesc, IPPROTO_IP, IP_ADD_MEMBERSHIP,
457 (raw_type *) &multicastRequest,
458 sizeof(multicastRequest)) < 0) {
459 throw SocketException("Multicast group join failed (setsockopt())", true);
463 void UDPSocket::leaveGroup(const string &multicastGroup) throw(SocketException) {
464 struct ip_mreq multicastRequest;
466 multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastGroup.c_str());
467 multicastRequest.imr_interface.s_addr = htonl(INADDR_ANY);
468 if (setsockopt(sockDesc, IPPROTO_IP, IP_DROP_MEMBERSHIP,
469 (raw_type *) &multicastRequest,
470 sizeof(multicastRequest)) < 0) {
471 throw SocketException("Multicast group leave failed (setsockopt())", true);