mirror of
https://github.com/Kiritow/GSock.git
synced 2024-03-22 13:10:51 +08:00
Support IPv6
There maybe many bugs in this commit. But at least it compiles successfully.
This commit is contained in:
parent
a5e1ec5560
commit
262270ba27
577
gsock.cpp
577
gsock.cpp
|
@ -7,10 +7,12 @@
|
||||||
|
|
||||||
#include "gsock.h"
|
#include "gsock.h"
|
||||||
|
|
||||||
|
#define GSOCK_DEBUG
|
||||||
|
|
||||||
#ifdef GSOCK_DEBUG
|
#ifdef GSOCK_DEBUG
|
||||||
#pragma message("GSock Debug mode compiled in")
|
#pragma message("GSock Debug mode compiled in")
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#define myliblog(fmt,...) printf("GSock: " fmt,__VA_ARGS__)
|
#define myliblog(fmt,...) printf("<GSock|%s> " fmt,__func__,__VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
#define myliblog(fmt,...)
|
#define myliblog(fmt,...)
|
||||||
#endif
|
#endif
|
||||||
|
@ -46,6 +48,7 @@ class _init_winsock2_2_class
|
||||||
public:
|
public:
|
||||||
_init_winsock2_2_class()
|
_init_winsock2_2_class()
|
||||||
{
|
{
|
||||||
|
myliblog("sockaddr %d sockaddr_in %d sockaddr_in6 %d\n", sizeof(sockaddr), sizeof(sockaddr_in), sizeof(sockaddr_in6));
|
||||||
/// Windows Platform need WinSock2.DLL initialization.
|
/// Windows Platform need WinSock2.DLL initialization.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WORD wd;
|
WORD wd;
|
||||||
|
@ -67,7 +70,7 @@ public:
|
||||||
/// Windows Platform need WinSock2.DLL clean up.
|
/// Windows Platform need WinSock2.DLL clean up.
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
myliblog("WSACleanup() called.");
|
myliblog("WSACleanup() called.\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
} _init_winsock2_2_obj;
|
} _init_winsock2_2_obj;
|
||||||
|
@ -114,6 +117,64 @@ vsock::~vsock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sock::_impl
|
||||||
|
{
|
||||||
|
static int connect_ipv4(vsock::_impl* _vp,const std::string& IPStr, int Port);
|
||||||
|
static int connect_ipv6(vsock::_impl* _vp,const std::string& IPStr, int Port);
|
||||||
|
};
|
||||||
|
|
||||||
|
int sock::_impl::connect_ipv4(vsock::_impl* _vp, const std::string& IPStr, int Port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in saddr;
|
||||||
|
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
if (inet_pton(AF_INET, IPStr.c_str(), &(saddr.sin_addr.s_addr)) != 1)
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
saddr.sin_port = htons(Port);
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
_vp->sfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (_vp->sfd<0)
|
||||||
|
{
|
||||||
|
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
myliblog("Socket <IPv4> created: [%d] with _vp %p\n", _vp->sfd, _vp);
|
||||||
|
_vp->created = true;
|
||||||
|
|
||||||
|
return ::connect(_vp->sfd, (sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock::_impl::connect_ipv6(vsock::_impl* _vp, const std::string& IPStr, int Port)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 saddr;
|
||||||
|
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
if (inet_pton(AF_INET6, IPStr.c_str(), &(saddr.sin6_addr)) != 1)
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
saddr.sin6_port = htons(Port);
|
||||||
|
saddr.sin6_family = AF_INET6;
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
_vp->sfd = socket(AF_INET6, SOCK_STREAM, 0);
|
||||||
|
if (_vp->sfd<0)
|
||||||
|
{
|
||||||
|
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
|
||||||
|
myliblog("Socket <IPv6> created: [%d] with _vp %p\n", _vp->sfd, _vp);
|
||||||
|
_vp->created = true;
|
||||||
|
|
||||||
|
return ::connect(_vp->sfd, (sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
|
||||||
int sock::connect(const std::string& IPStr,int Port)
|
int sock::connect(const std::string& IPStr,int Port)
|
||||||
{
|
{
|
||||||
myliblog("sock::connect() %p\n",this);
|
myliblog("sock::connect() %p\n",this);
|
||||||
|
@ -122,23 +183,17 @@ int sock::connect(const std::string& IPStr,int Port)
|
||||||
{
|
{
|
||||||
return -2;
|
return -2;
|
||||||
}
|
}
|
||||||
_vp->sfd=socket(AF_INET,SOCK_STREAM,0);
|
|
||||||
if(_vp->sfd<0)
|
|
||||||
{
|
|
||||||
myliblog("socket() returns %d. WSAGetLastError: %d\n",_vp->sfd,WSAGetLastError());
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
myliblog("Socket created: [%d] in %p\n",_pp->sfd,this);
|
|
||||||
_vp->created=true;
|
|
||||||
|
|
||||||
struct sockaddr_in saddr;
|
|
||||||
|
|
||||||
memset(&saddr,0,sizeof(saddr));
|
if (IPStr.find(":") != std::string::npos)
|
||||||
saddr.sin_addr.s_addr=inet_addr(IPStr.c_str());
|
{
|
||||||
saddr.sin_port=htons(Port);
|
// Maybe IPv6
|
||||||
saddr.sin_family=AF_INET;
|
return sock::_impl::connect_ipv6(_vp, IPStr, Port);
|
||||||
|
}
|
||||||
return ::connect(_vp->sfd,(sockaddr*)&saddr,sizeof(saddr));
|
else
|
||||||
|
{
|
||||||
|
// Maybe IPv4
|
||||||
|
return sock::_impl::connect_ipv4(_vp, IPStr, Port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock::send(const void* Buffer,int Length)
|
int sock::send(const void* Buffer,int Length)
|
||||||
|
@ -222,14 +277,50 @@ using _sock_getname_callback_t = decltype(getsockname);
|
||||||
|
|
||||||
static int _sock_getname_call(int sfd,std::string& ip,int& port,_sock_getname_callback_t fn)
|
static int _sock_getname_call(int sfd,std::string& ip,int& port,_sock_getname_callback_t fn)
|
||||||
{
|
{
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr saddr;
|
||||||
socklen_t saddrlen=sizeof(saddr);
|
socklen_t saddrlen=sizeof(saddr);
|
||||||
memset(&saddr,0,saddrlen);
|
memset(&saddr,0,saddrlen);
|
||||||
int ret=fn(sfd,(sockaddr*)&saddr,&saddrlen);
|
int ret=fn(sfd,&saddr,&saddrlen);
|
||||||
if(ret<0) return ret; //don't bother errno. stop here.
|
if(ret<0) return ret; //don't bother errno. stop here.
|
||||||
ip=inet_ntoa(saddr.sin_addr);
|
if (saddr.sa_family == AF_INET)
|
||||||
port=ntohs(saddr.sin_port);
|
{
|
||||||
return ret;
|
struct sockaddr_in* paddr = (sockaddr_in*)&saddr;
|
||||||
|
char ip_buff[64] = { 0 };
|
||||||
|
const char* pret = inet_ntop(AF_INET, paddr, ip_buff, 64);
|
||||||
|
if (pret)
|
||||||
|
{
|
||||||
|
ip = std::string(ip_buff);
|
||||||
|
port = ntohs(paddr->sin_port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// inet_ntop call failed.
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (saddr.sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
struct sockaddr_in6* paddr = (sockaddr_in6*)&saddr;
|
||||||
|
char ip_buff[128] = { 0 };
|
||||||
|
const char* pret = inet_ntop(AF_INET6, paddr, ip_buff, 128);
|
||||||
|
if (pret)
|
||||||
|
{
|
||||||
|
ip = std::string(ip_buff);
|
||||||
|
port = ntohs(paddr->sin6_port);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// inet_ntop call failed.
|
||||||
|
return -3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// protocol not supported.
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sock::getlocal(std::string& IPStr,int& Port)
|
int sock::getlocal(std::string& IPStr,int& Port)
|
||||||
|
@ -265,7 +356,7 @@ public:
|
||||||
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
myliblog("Socket created: [%d] in %p\n", _vp->sfd, this);
|
myliblog("Socket created: [%d] with _vp %p\n", _vp->sfd, _vp);
|
||||||
_vp->created = true;
|
_vp->created = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -332,7 +423,7 @@ int serversock::accept(sock& _out_s)
|
||||||
s._vp->sfd=ret;
|
s._vp->sfd=ret;
|
||||||
s._vp->created=true;
|
s._vp->created=true;
|
||||||
|
|
||||||
myliblog("Socket opened: [%d] in %p by serversock %p\n",s._vp->sfd,&s,this);
|
myliblog("Socket opened: [%d] in %p by serversock _vp: %p\n",s._vp->sfd,&s,_vp);
|
||||||
|
|
||||||
/// Move resource.
|
/// Move resource.
|
||||||
_out_s=std::move(s);
|
_out_s=std::move(s);
|
||||||
|
@ -340,94 +431,376 @@ int serversock::accept(sock& _out_s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
udpsock::udpsock()
|
struct udpsock::_impl
|
||||||
{
|
{
|
||||||
_vp->sfd = socket(AF_INET, SOCK_DGRAM, 0);
|
int protocol;
|
||||||
_vp->created = true;
|
bool is_protocol_decided;
|
||||||
|
|
||||||
|
int make_decided(vsock::_impl* _vp)
|
||||||
|
{
|
||||||
|
if (_vp->created)
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_vp->sfd = socket(protocol, SOCK_DGRAM, 0);
|
||||||
|
_vp->created = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline const char* get_family_name(int family)
|
||||||
|
{
|
||||||
|
switch (family)
|
||||||
|
{
|
||||||
|
case AF_INET:
|
||||||
|
return "AF_INET";
|
||||||
|
case AF_INET6:
|
||||||
|
return "AF_INET6";
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
udpsock::udpsock(int use_family) : _pp(new _impl)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (use_family == 1)
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
}
|
||||||
|
else if (use_family == 2)
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET6;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->is_protocol_decided = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from IPStr to sockaddr
|
||||||
|
// Parameters:
|
||||||
|
// flag_ipv46:
|
||||||
|
// -1: Undecided
|
||||||
|
// 0: IPv4
|
||||||
|
// 1: IPv6
|
||||||
|
// Return:
|
||||||
|
// -1: inet_pton() call failed.
|
||||||
|
// 0: Success, IPv4
|
||||||
|
// 1: Success, IPv6
|
||||||
|
static int convert_ipv46(const std::string& IPStr, int Port,
|
||||||
|
struct sockaddr*& _out_psockaddr, int& _out_szsockaddr,
|
||||||
|
struct sockaddr_in* paddr, struct sockaddr_in6* paddr6, int flag_ipv46)
|
||||||
|
{
|
||||||
|
if ( (flag_ipv46==1) ||
|
||||||
|
( (flag_ipv46==-1) && (IPStr.find(":") != std::string::npos) )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// Maybe IPv6
|
||||||
|
memset(paddr6, 0, sizeof(sockaddr_in6));
|
||||||
|
if (inet_pton(AF_INET6, IPStr.c_str(), &(paddr6->sin6_addr)) != 1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
paddr6->sin6_port = htons(Port);
|
||||||
|
paddr6->sin6_family = AF_INET6;
|
||||||
|
|
||||||
|
_out_psockaddr = (sockaddr*)&paddr6;
|
||||||
|
_out_szsockaddr = sizeof(sockaddr_in6);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else // flag_ipv46==-1 && IPStr.find(":")==string::npos, flag_ipv46==0
|
||||||
|
{
|
||||||
|
// Maybe IPv4
|
||||||
|
memset(paddr, 0, sizeof(sockaddr_in));
|
||||||
|
if (inet_pton(AF_INET, IPStr.c_str(), &(paddr->sin_addr)) != 1)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
paddr->sin_port = htons(Port);
|
||||||
|
paddr->sin_family = AF_INET;
|
||||||
|
|
||||||
|
_out_psockaddr = (sockaddr*)&paddr;
|
||||||
|
_out_szsockaddr = sizeof(sockaddr_in);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert from sockaddr to IPStr
|
||||||
|
// Return:
|
||||||
|
// -1: inet_ntop() call failed.
|
||||||
|
// -2: Unsupported protocol
|
||||||
|
// 0: Success, IPv4
|
||||||
|
// 1: Success, IPv6
|
||||||
|
static int convertback_ipv46(const sockaddr* paddr, std::string& _out_IPStr)
|
||||||
|
{
|
||||||
|
char buff[128] = { 0 };
|
||||||
|
if (paddr->sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
if (inet_ntop(AF_INET, paddr, buff, 128)!=NULL)
|
||||||
|
{
|
||||||
|
_out_IPStr = std::move(std::string(buff));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
else if (paddr->sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (inet_ntop(AF_INET6, paddr, buff, 128) != NULL)
|
||||||
|
{
|
||||||
|
_out_IPStr = std::move(std::string(buff));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else return -1;
|
||||||
|
}
|
||||||
|
else return -2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::connect(const std::string& IPStr,int Port)
|
int udpsock::connect(const std::string& IPStr,int Port)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
sockaddr_in saddr;
|
||||||
memset(&saddr, 0, sizeof(saddr));
|
sockaddr_in6 saddr6;
|
||||||
saddr.sin_family = AF_INET;
|
sockaddr* paddr;
|
||||||
saddr.sin_port = htons(Port);
|
int addrsz;
|
||||||
saddr.sin_addr.s_addr = inet_addr(IPStr.c_str());
|
|
||||||
|
int ret = convert_ipv46(IPStr, Port, paddr, addrsz, &saddr, &saddr6,
|
||||||
|
(_pp->is_protocol_decided) ? ((_pp->protocol == AF_INET) ? 0 : 1) : -1);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = (ret == 0) ? (AF_INET) : (AF_INET6);
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
}
|
||||||
|
|
||||||
return ::connect(_vp->sfd,(const sockaddr*)&saddr,sizeof(saddr));
|
return ::connect(_vp->sfd, (const sockaddr*)paddr, addrsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::broadcast_at(int Port)
|
int udpsock::broadcast_at(int Port)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
if (_pp->is_protocol_decided)
|
||||||
memset(&saddr, 0, sizeof(saddr));
|
{
|
||||||
saddr.sin_family = AF_INET;
|
if (_pp->protocol == AF_INET)
|
||||||
saddr.sin_port = htons(Port);
|
{
|
||||||
saddr.sin_addr.s_addr = INADDR_BROADCAST;
|
sockaddr_in saddr;
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
return ::connect(_vp->sfd,(const sockaddr*)&saddr,sizeof(saddr));
|
saddr.sin_family = AF_INET;
|
||||||
|
saddr.sin_port = htons(Port);
|
||||||
|
saddr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
|
||||||
|
return ::connect(_vp->sfd, (const sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
myliblog("IPv6 does not support broadcast!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return broadcast_at(Port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::set_broadcast()
|
int udpsock::set_broadcast()
|
||||||
{
|
{
|
||||||
socklen_t opt=1;
|
if (_pp->is_protocol_decided)
|
||||||
return ::setsockopt(_vp->sfd,SOL_SOCKET,SO_BROADCAST,(const char*)&opt,sizeof(opt));
|
{
|
||||||
|
socklen_t opt = 1;
|
||||||
|
return ::setsockopt(_vp->sfd, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, sizeof(opt));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return set_broadcast();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::bind(int Port)
|
int udpsock::bind(int Port)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
if (_pp->is_protocol_decided)
|
||||||
memset(&saddr, 0, sizeof(saddr));
|
{
|
||||||
saddr.sin_family = AF_INET;
|
if (_pp->protocol == AF_INET)
|
||||||
saddr.sin_port = htons(Port);
|
{
|
||||||
saddr.sin_addr.s_addr = INADDR_ANY;
|
sockaddr_in saddr;
|
||||||
return ::bind(_vp->sfd, (const sockaddr*)&saddr, sizeof(saddr));
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
saddr.sin_port = htons(Port);
|
||||||
|
saddr.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
|
||||||
|
return ::bind(_vp->sfd, (const sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sockaddr_in6 saddr;
|
||||||
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
saddr.sin6_family = AF_INET6;
|
||||||
|
saddr.sin6_port = htons(Port);
|
||||||
|
saddr.sin6_addr = in6addr_any;
|
||||||
|
|
||||||
|
return ::bind(_vp->sfd, (const sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return bind(Port);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::sendto(const std::string& IPStr, int Port, const void* buffer, int length)
|
int udpsock::sendto(const std::string& IPStr, int Port, const void* buffer, int length)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
sockaddr_in saddr;
|
||||||
memset(&saddr, 0, sizeof(saddr));
|
sockaddr_in6 saddr6;
|
||||||
saddr.sin_family = AF_INET;
|
sockaddr* paddr;
|
||||||
saddr.sin_port = htons(Port);
|
int addrsz;
|
||||||
saddr.sin_addr.s_addr = inet_addr(IPStr.c_str());
|
|
||||||
return ::sendto(_vp->sfd, (const char*)buffer, length, 0, (const sockaddr*)&saddr, sizeof(saddr));
|
int ret = convert_ipv46(IPStr, Port, paddr, addrsz, &saddr, &saddr6,
|
||||||
|
(_pp->is_protocol_decided) ? ((_pp->protocol == AF_INET) ? 0 : 1) : -1);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return -4;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = (ret == 0) ? (AF_INET) : (AF_INET6);
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ::sendto(_vp->sfd, (const char*)buffer, length, 0, (const sockaddr*)paddr, addrsz);
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::broadcast(int Port,const void* buffer,int length)
|
int udpsock::broadcast(int Port,const void* buffer,int length)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
if (_pp->is_protocol_decided)
|
||||||
memset(&saddr, 0, sizeof(saddr));
|
{
|
||||||
saddr.sin_family = AF_INET;
|
if (_pp->protocol == AF_INET)
|
||||||
saddr.sin_port = htons(Port);
|
{
|
||||||
saddr.sin_addr.s_addr = INADDR_BROADCAST;
|
sockaddr_in saddr;
|
||||||
return ::sendto(_vp->sfd, (const char*)buffer, length, 0, (const sockaddr*)&saddr, sizeof(saddr));
|
memset(&saddr, 0, sizeof(saddr));
|
||||||
|
saddr.sin_family = AF_INET;
|
||||||
|
saddr.sin_port = htons(Port);
|
||||||
|
saddr.sin_addr.s_addr = INADDR_BROADCAST;
|
||||||
|
return ::sendto(_vp->sfd, (const char*)buffer, length, 0, (const sockaddr*)&saddr, sizeof(saddr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
myliblog("IPv6 does not support broadcast!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
|
||||||
|
return broadcast(Port, buffer, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::recvfrom(std::string& fromIP, int& fromPort, void* buffer, int bufferLength)
|
int udpsock::recvfrom(std::string& fromIP, int& fromPort, void* buffer, int bufferLength)
|
||||||
{
|
{
|
||||||
sockaddr_in saddr;
|
if (_pp->is_protocol_decided)
|
||||||
socklen_t saddrlen = sizeof(saddr);
|
|
||||||
int ret = ::recvfrom(_vp->sfd, (char*)buffer, bufferLength, 0, (sockaddr*)&saddr, &saddrlen);
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
{
|
||||||
return ret; /// don't bother errno.
|
if (_pp->protocol == AF_INET)
|
||||||
}
|
{
|
||||||
|
sockaddr_in saddr;
|
||||||
|
socklen_t saddrlen = sizeof(saddr);
|
||||||
|
int ret = ::recvfrom(_vp->sfd, (char*)buffer, bufferLength, 0, (sockaddr*)&saddr, &saddrlen);
|
||||||
|
|
||||||
fromIP = inet_ntoa(saddr.sin_addr);
|
if (ret < 0)
|
||||||
fromPort = ntohs(saddr.sin_port);
|
{
|
||||||
return ret;
|
return ret; /// don't bother errno.
|
||||||
|
}
|
||||||
|
|
||||||
|
convertback_ipv46((const sockaddr*)&saddr, fromIP);
|
||||||
|
fromPort = ntohs(saddr.sin_port);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sockaddr_in6 saddr;
|
||||||
|
socklen_t saddrlen = sizeof(saddr);
|
||||||
|
int ret = ::recvfrom(_vp->sfd, (char*)buffer, bufferLength, 0, (sockaddr*)&saddr, &saddrlen);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return ret; /// don't bother errno.
|
||||||
|
}
|
||||||
|
|
||||||
|
convertback_ipv46((const sockaddr*)&saddr, fromIP);
|
||||||
|
fromPort = ntohs(saddr.sin6_port);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return recvfrom(fromIP, fromPort, buffer, bufferLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::send(const void* buffer,int length)
|
int udpsock::send(const void* buffer,int length)
|
||||||
{
|
{
|
||||||
return ::send(_vp->sfd,(const char*)buffer,length,0);
|
if (_pp->is_protocol_decided)
|
||||||
|
{
|
||||||
|
return ::send(_vp->sfd, (const char*)buffer, length, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return send(buffer, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int udpsock::recv(void* buffer,int bufferLength)
|
int udpsock::recv(void* buffer,int bufferLength)
|
||||||
{
|
{
|
||||||
return ::recv(_vp->sfd,(char*)buffer,bufferLength,0);
|
if (_pp->is_protocol_decided)
|
||||||
|
{
|
||||||
|
return ::recv(_vp->sfd, (char*)buffer, bufferLength, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_pp->protocol = AF_INET;
|
||||||
|
_pp->is_protocol_decided = true;
|
||||||
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
||||||
|
_pp->make_decided(_vp);
|
||||||
|
return recv(buffer, bufferLength);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select
|
// Select
|
||||||
|
@ -535,8 +908,10 @@ bool selector::is_error(const vsock& v)
|
||||||
return FD_ISSET(v._vp->sfd, &_pp->errorset);
|
return FD_ISSET(v._vp->sfd, &_pp->errorset);
|
||||||
}
|
}
|
||||||
|
|
||||||
int DNSResolve(const std::string& HostName, std::string& _out_IPStr)
|
int DNSResolve(const std::string& HostName, std::vector<std::string>& _out_IPStrVec)
|
||||||
{
|
{
|
||||||
|
std::vector<std::string> vec;
|
||||||
|
|
||||||
/// Use getaddrinfo instead
|
/// Use getaddrinfo instead
|
||||||
struct addrinfo hints;
|
struct addrinfo hints;
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
@ -551,21 +926,61 @@ int DNSResolve(const std::string& HostName, std::string& _out_IPStr)
|
||||||
{
|
{
|
||||||
return -1;/// API Call Failed.
|
return -1;/// API Call Failed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
for (struct addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next)
|
for (struct addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next)
|
||||||
{
|
{
|
||||||
|
cnt++;
|
||||||
switch (ptr->ai_family)
|
switch (ptr->ai_family)
|
||||||
{
|
{
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
sockaddr_in * addr = (struct sockaddr_in*) (ptr->ai_addr);
|
{
|
||||||
_out_IPStr = inet_ntoa(addr->sin_addr);
|
sockaddr_in * paddr = (struct sockaddr_in*) (ptr->ai_addr);
|
||||||
freeaddrinfo(result);
|
char ip_buff[64] = { 0 };
|
||||||
return 0;
|
const char* ptr = inet_ntop(AF_INET, &(paddr->sin_addr), ip_buff, 64);
|
||||||
break;
|
if (ptr != NULL)
|
||||||
}
|
{
|
||||||
|
vec.push_back(ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case AF_INET6:
|
||||||
|
{
|
||||||
|
sockaddr_in6* paddr = (struct sockaddr_in6*) (ptr->ai_addr);
|
||||||
|
char ip_buff[128] = { 0 };
|
||||||
|
const char* ptr = inet_ntop(AF_INET6, &(paddr->sin6_addr), ip_buff, 128);
|
||||||
|
if (ptr != NULL)
|
||||||
|
{
|
||||||
|
vec.push_back(ptr);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}// End of switch
|
||||||
}
|
}
|
||||||
/// Unknown error.
|
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
return -2;
|
|
||||||
|
_out_IPStrVec = std::move(vec);
|
||||||
|
|
||||||
|
// if(cnt!=(int)_out_IPStrVec.size()),
|
||||||
|
// then (cnt-(int)_out_IPStrVec.size()) errors happend while calling inet_ntop().
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
int DNSResolve(const std::string& HostName, std::string& _out_IPStr)
|
||||||
|
{
|
||||||
|
std::vector<std::string> vec;
|
||||||
|
int ret = DNSResolve(HostName, vec);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (vec.empty())
|
||||||
|
{
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
_out_IPStr = vec[0];
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
26
gsock.h
26
gsock.h
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class vsock
|
class vsock
|
||||||
{
|
{
|
||||||
|
@ -35,6 +36,7 @@ public:
|
||||||
/// -1: connect() call error. See errno.
|
/// -1: connect() call error. See errno.
|
||||||
/// -2: This socket has been connected before.
|
/// -2: This socket has been connected before.
|
||||||
/// -3: socket() call error. Failed to create socket. See errno.
|
/// -3: socket() call error. Failed to create socket. See errno.
|
||||||
|
/// -4: IP Address invalid.
|
||||||
int connect(const std::string& IPStr,int Port);
|
int connect(const std::string& IPStr,int Port);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -62,6 +64,8 @@ public:
|
||||||
int getpeer(std::string& IPStr,int& Port);
|
int getpeer(std::string& IPStr,int& Port);
|
||||||
|
|
||||||
friend class serversock;
|
friend class serversock;
|
||||||
|
private:
|
||||||
|
struct _impl;
|
||||||
};
|
};
|
||||||
|
|
||||||
class serversock : public vsock
|
class serversock : public vsock
|
||||||
|
@ -92,10 +96,17 @@ private:
|
||||||
class udpsock : public vsock
|
class udpsock : public vsock
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
udpsock();
|
// use_family:
|
||||||
|
// 0: Auto (Undecided now) (default)
|
||||||
|
// 1: IPv4 (If family cannot be automatically decided, then IPv4 will be the default option)
|
||||||
|
// 2: IPv6
|
||||||
|
udpsock(int use_family=0);
|
||||||
|
|
||||||
/// Use udp socket as tcp socket. (but of course it is not).
|
/// Use udp socket as tcp socket. (but of course it is not).
|
||||||
/// connect call just copy the target socket data to kernel. See connect() for more info.
|
/// connect call just copy the target socket data to kernel. See connect() for more info.
|
||||||
|
/// Return:
|
||||||
|
/// -1: connect() error.
|
||||||
|
/// -4: IP Address Invalid.
|
||||||
int connect(const std::string& IPStr,int Port);
|
int connect(const std::string& IPStr,int Port);
|
||||||
int broadcast_at(int Port);
|
int broadcast_at(int Port);
|
||||||
|
|
||||||
|
@ -113,6 +124,9 @@ public:
|
||||||
/// send() and recv() should only be called after connect(). Or it will fail.
|
/// send() and recv() should only be called after connect(). Or it will fail.
|
||||||
int send(const void* buffer,int length);
|
int send(const void* buffer,int length);
|
||||||
int recv(void* buffer,int bufferLength);
|
int recv(void* buffer,int bufferLength);
|
||||||
|
private:
|
||||||
|
struct _impl;
|
||||||
|
_impl* _pp;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Select
|
/// Select
|
||||||
|
@ -141,6 +155,16 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Net Tools
|
/// Net Tools
|
||||||
|
// Return:
|
||||||
|
// -1: getaddrinfo() call failed.
|
||||||
|
// Other: Number of fetched results from getaddrinfo() call.
|
||||||
|
int DNSResolve(const std::string& HostName, std::vector<std::string>& _out_IPStrVec);
|
||||||
|
|
||||||
|
// A wrapper of DNSResolve(...,std::vector<std::string>&)
|
||||||
|
// Return:
|
||||||
|
// -1: getaddrinfo() call failed.
|
||||||
|
// -2: Failed to resolve. (No results in vector)
|
||||||
|
// 0: Success.
|
||||||
int DNSResolve(const std::string& HostName,std::string& _out_IPStr);
|
int DNSResolve(const std::string& HostName,std::string& _out_IPStr);
|
||||||
|
|
||||||
#endif // _gsock_h
|
#endif // _gsock_h
|
Loading…
Reference in New Issue
Block a user