From 1b2aabf076169e6d2049227188e464e95ac40514 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sat, 15 Jan 2011 18:09:48 +0000 Subject: [PATCH] Add IPv6 support --- source/datagramsocket.cpp | 20 +++++------ source/inet.cpp | 9 +++-- source/inet.h | 15 ++++---- source/inet6.cpp | 68 +++++++++++++++++++++++++++++++++++ source/inet6.h | 49 +++++++++++++++++++++++++ source/resolve.cpp | 23 ++++++++---- source/sockaddr.cpp | 16 ++++++--- source/sockaddr.h | 7 ++-- source/socket.cpp | 12 +++---- source/streamlistensocket.cpp | 8 ++--- source/streamsocket.cpp | 12 +++---- 11 files changed, 190 insertions(+), 49 deletions(-) create mode 100644 source/inet6.cpp create mode 100644 source/inet6.h diff --git a/source/datagramsocket.cpp b/source/datagramsocket.cpp index 7944532..a1b1c9e 100644 --- a/source/datagramsocket.cpp +++ b/source/datagramsocket.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -25,10 +25,10 @@ int DatagramSocket::connect(const SockAddr &addr) { check_state(false); - sockaddr sa; + sockaddr_storage sa; socklen_t size=addr.fill_sockaddr(sa); - int err=::connect(handle, &sa, size); + int err=::connect(handle, reinterpret_cast(&sa), size); if(err==-1) throw SystemError("Unable to connect", errno); @@ -36,8 +36,8 @@ int DatagramSocket::connect(const SockAddr &addr) peer_addr=addr.copy(); delete local_addr; - size=sizeof(sockaddr); - getsockname(handle, &sa, &size); + size=sizeof(sockaddr_storage); + getsockname(handle, reinterpret_cast(&sa), &size); local_addr=SockAddr::create(sa); connected=true; @@ -52,10 +52,10 @@ unsigned DatagramSocket::sendto(const char *buf, unsigned size, const SockAddr & if(size==0) return 0; - sockaddr addr; + sockaddr_storage addr; socklen_t addr_len=addr_.fill_sockaddr(addr); - int ret=::sendto(handle, buf, size, 0, &addr, addr_len); + int ret=::sendto(handle, buf, size, 0, reinterpret_cast(&addr), addr_len); if(ret<0) { if(errno==EAGAIN) @@ -74,10 +74,10 @@ unsigned DatagramSocket::recvfrom(char *buf, unsigned size, SockAddr *&addr_) if(size==0) return 0; - sockaddr addr; - socklen_t addr_len=sizeof(sockaddr); + sockaddr_storage addr; + socklen_t addr_len=sizeof(sockaddr_storage); - int ret=::recvfrom(handle, buf, size, 0, &addr, &addr_len); + int ret=::recvfrom(handle, buf, size, 0, reinterpret_cast(&addr), &addr_len); if(ret<0) { if(errno==EAGAIN) diff --git a/source/inet.cpp b/source/inet.cpp index 181c734..57d8085 100644 --- a/source/inet.cpp +++ b/source/inet.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -18,7 +18,7 @@ InetAddr::InetAddr(): port(0) { } -InetAddr::InetAddr(sockaddr_in &sa): +InetAddr::InetAddr(const sockaddr_in &sa): addr(sa.sin_addr.s_addr), port(sa.sin_port) { } @@ -31,7 +31,10 @@ InetAddr::InetAddr(in_addr_t a, in_port_t p): string InetAddr::str() const { const unsigned char *ptr=reinterpret_cast(&addr); - return format("%d.%d.%d.%d:%d", static_cast(ptr[0]), static_cast(ptr[1]), static_cast(ptr[2]), static_cast(ptr[3]), ntohs(port)); + string result = format("%d.%d.%d.%d", ptr[0], ptr[1], ptr[2], ptr[3]); + if(port) + result += format(":%d", ntohs(port)); + return result; } unsigned InetAddr::fill_sockaddr(sockaddr &sa) const diff --git a/source/inet.h b/source/inet.h index 56b9f4d..be67dee 100644 --- a/source/inet.h +++ b/source/inet.h @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -13,29 +13,28 @@ Distributed under the LGPL #else #include #endif -#include #include "sockaddr.h" namespace Msp { namespace Net { -#ifdef WIN32 -typedef u_long in_addr_t; -typedef u_short in_port_t; -#endif - /** Address class for IPv4 sockets. */ class InetAddr: public SockAddr { private: +#ifdef WIN32 + typedef u_long in_addr_t; + typedef u_short in_port_t; +#endif + in_addr_t addr; in_port_t port; public: InetAddr(); - InetAddr(sockaddr_in &); + InetAddr(const sockaddr_in &); InetAddr(in_addr_t, in_port_t); Family get_family() const { return INET; } diff --git a/source/inet6.cpp b/source/inet6.cpp new file mode 100644 index 0000000..dbbf2db --- /dev/null +++ b/source/inet6.cpp @@ -0,0 +1,68 @@ +/* $Id$ + +This file is part of libmspnet +Copyright © 2011 Mikkosoft Productions, Mikko Rasa +Distributed under the LGPL +*/ + +#include +#include +#include "inet6.h" + +using namespace std; + +namespace Msp { +namespace Net { + +Inet6Addr::Inet6Addr(): + addr(in6addr_any), + port(0) +{ } + +Inet6Addr::Inet6Addr(const sockaddr_in6 &sai6): + addr(sai6.sin6_addr), + port(sai6.sin6_port) +{ } + +Inet6Addr::Inet6Addr(unsigned char a[16], in_port_t p): + port(p) +{ + std::copy(a, a+16, addr.s6_addr); +} + +string Inet6Addr::str() const +{ + string result = "["; + for(unsigned i=0; i<16; i+=2) + { + unsigned short part = (addr.s6_addr[i]<<8) | addr.s6_addr[i+1]; + if(i>0) + result += ':'; + result += format("%x", part); + } + result += ']'; + if(port) + result += format(":%d", ntohs(port)); + + return result; +} + +unsigned Inet6Addr::fill_sockaddr(sockaddr &) const +{ + throw Exception("Inet6Addr doesn't fit in struct sockaddr"); +} + +unsigned Inet6Addr::fill_sockaddr(sockaddr_storage &sa) const +{ + sockaddr_in6 &sai6 = reinterpret_cast(sa); + sai6.sin6_family = AF_INET6; + sai6.sin6_port = port; + sai6.sin6_addr = addr; + sai6.sin6_flowinfo = 0; + sai6.sin6_scope_id = 0; + + return sizeof(sockaddr_in6); +} + +} // namespace Net +} // namespace Msp diff --git a/source/inet6.h b/source/inet6.h new file mode 100644 index 0000000..02ec450 --- /dev/null +++ b/source/inet6.h @@ -0,0 +1,49 @@ +/* $Id$ + +This file is part of libmspnet +Copyright © 2011 Mikkosoft Productions, Mikko Rasa +Distributed under the LGPL +*/ + +#ifndef MSP_NET_INET6_H_ +#define NSP_NET_INET6_H_ + +#ifdef WIN32 +#include +#include +#else +#include +#endif +#include "sockaddr.h" + +namespace Msp { +namespace Net { + +class Inet6Addr: public SockAddr +{ +private: +#ifdef WIN32 + typedef u_short in_port_t; +#endif + + in6_addr addr; + in_port_t port; + +public: + Inet6Addr(); + Inet6Addr(const sockaddr_in6 &); + Inet6Addr(unsigned char [16], in_port_t); + + virtual Family get_family() const { return INET6; } + virtual std::string str() const; + + virtual unsigned fill_sockaddr(sockaddr &) const; + virtual unsigned fill_sockaddr(sockaddr_storage &) const; + + virtual Inet6Addr *copy() const { return new Inet6Addr(*this); } +}; + +} // namespace Net +} // namespace Msp + +#endif diff --git a/source/resolve.cpp b/source/resolve.cpp index 121b152..bfe7eaa 100644 --- a/source/resolve.cpp +++ b/source/resolve.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -23,14 +23,25 @@ namespace Net { SockAddr *resolve(const string &s, Family family) { string host, serv; - unsigned colon=s.find(':'); - if(colon!=string::npos) + if(s[0]=='[') { - host=s.substr(0, colon); - serv=s.substr(colon+1); + unsigned bracket = s.find(']'); + host = s.substr(1, bracket-1); + unsigned colon = s.find(':', bracket); + if(colon!=string::npos) + serv = s.substr(colon+1); } else - host=s; + { + unsigned colon = s.find(':'); + if(colon!=string::npos) + { + host = s.substr(0, colon); + serv = s.substr(colon+1); + } + else + host = s; + } addrinfo hints={0, family, 0, 0, 0, 0, 0, 0}; addrinfo *res; diff --git a/source/sockaddr.cpp b/source/sockaddr.cpp index c3ae2db..26c77b6 100644 --- a/source/sockaddr.cpp +++ b/source/sockaddr.cpp @@ -1,22 +1,30 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ #include #include "inet.h" +#include "inet6.h" namespace Msp { namespace Net { -SockAddr *SockAddr::create(sockaddr &sa) +unsigned SockAddr::fill_sockaddr(sockaddr_storage &sa) const { - switch(sa.sa_family) + return fill_sockaddr(reinterpret_cast(sa)); +} + +SockAddr *SockAddr::create(const sockaddr_storage &sa) +{ + switch(sa.ss_family) { case AF_INET: - return new InetAddr(reinterpret_cast(sa)); + return new InetAddr(reinterpret_cast(sa)); + case AF_INET6: + return new Inet6Addr(reinterpret_cast(sa)); default: throw InvalidParameterValue("Unknown address family"); } diff --git a/source/sockaddr.h b/source/sockaddr.h index 63f2ab4..0f7a746 100644 --- a/source/sockaddr.h +++ b/source/sockaddr.h @@ -1,13 +1,14 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ #ifndef MSP_NET_SOCKADDR_H_ #define MSP_NET_SOCKADDR_H_ +#include #ifndef WIN32 #include #endif @@ -28,12 +29,14 @@ public: @return Number of bytes used */ virtual unsigned fill_sockaddr(sockaddr &) const =0; + virtual unsigned fill_sockaddr(sockaddr_storage &) const; virtual SockAddr *copy() const =0; virtual ~SockAddr() { } - static SockAddr *create(sockaddr &); + static SockAddr *create(const sockaddr &sa) { return create(reinterpret_cast(sa)); } + static SockAddr *create(const sockaddr_storage &); protected: SockAddr() { } }; diff --git a/source/socket.cpp b/source/socket.cpp index 49614df..150d836 100644 --- a/source/socket.cpp +++ b/source/socket.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2010-2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -49,9 +49,9 @@ Socket::Socket(SocketHandle h, const SockAddr &paddr): local_addr(0), peer_addr(paddr.copy()) { - sockaddr sa; - socklen_t size=sizeof(sockaddr); - getsockname(handle, &sa, &size); + sockaddr_storage sa; + socklen_t size=sizeof(sockaddr_storage); + getsockname(handle, reinterpret_cast(&sa), &size); local_addr=SockAddr::create(sa); #ifdef WIN32 @@ -105,10 +105,10 @@ void Socket::bind(const SockAddr &addr) { check_state(false); - sockaddr sa; + sockaddr_storage sa; unsigned size=addr.fill_sockaddr(sa); - int err=::bind(handle, &sa, size); + int err=::bind(handle, reinterpret_cast(&sa), size); if(err==-1) throw SystemError("Unable to bind", errno); diff --git a/source/streamlistensocket.cpp b/source/streamlistensocket.cpp index 2a8bc3d..12e98b1 100644 --- a/source/streamlistensocket.cpp +++ b/source/streamlistensocket.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008 Mikkosoft Productions, Mikko Rasa +Copyright © 2008, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -45,9 +45,9 @@ StreamSocket *StreamListenSocket::accept() if(!listening) throw InvalidState("Socket is not listening"); - sockaddr sa; - socklen_t size=sizeof(sockaddr); - SocketHandle new_h=::accept(handle, &sa, &size); + sockaddr_storage sa; + socklen_t size=sizeof(sockaddr_storage); + SocketHandle new_h=::accept(handle, reinterpret_cast(&sa), &size); RefPtr paddr=SockAddr::create(sa); return new StreamSocket(new_h, *paddr); diff --git a/source/streamsocket.cpp b/source/streamsocket.cpp index 56df993..0322f12 100644 --- a/source/streamsocket.cpp +++ b/source/streamsocket.cpp @@ -1,7 +1,7 @@ /* $Id$ This file is part of libmspnet -Copyright © 2008-2009 Mikkosoft Productions, Mikko Rasa +Copyright © 2008-2009, 2011 Mikkosoft Productions, Mikko Rasa Distributed under the LGPL */ @@ -102,11 +102,11 @@ int StreamSocket::connect(const SockAddr &addr) if(connected) throw InvalidState("Socket is already connected"); - sockaddr sa; + sockaddr_storage sa; socklen_t size=addr.fill_sockaddr(sa); #ifdef WIN32 - int err=WSAConnect(handle, &sa, size, 0, 0, 0, 0); + int err=WSAConnect(handle, reinterpret_cast(&sa), size, 0, 0, 0, 0); if(err==SOCKET_ERROR) { int err_code=WSAGetLastError(); @@ -120,7 +120,7 @@ int StreamSocket::connect(const SockAddr &addr) throw Exception(format("Unable to connect: %d", err_code)); } #else - int err=::connect(handle, &sa, size); + int err=::connect(handle, reinterpret_cast(&sa), size); if(err==-1) { if(errno==EINPROGRESS) @@ -137,8 +137,8 @@ int StreamSocket::connect(const SockAddr &addr) peer_addr=addr.copy(); delete local_addr; - size=sizeof(sockaddr); - getsockname(handle, &sa, &size); + size=sizeof(sockaddr_storage); + getsockname(handle, reinterpret_cast(&sa), &size); local_addr=SockAddr::create(sa); if(err==0) -- 2.43.0