2017-07-27 19:52:58 +08:00
|
|
|
/** General Socket Wrapper
|
|
|
|
* Created By Kiritow. (https://github.com/kiritow)
|
|
|
|
* Licensed under MIT
|
|
|
|
*/
|
|
|
|
|
2018-04-23 15:56:05 +08:00
|
|
|
/** See VERSION for version information */
|
2017-07-27 19:52:58 +08:00
|
|
|
|
|
|
|
#include "gsock.h"
|
|
|
|
|
2017-08-15 09:54:10 +08:00
|
|
|
#ifdef GSOCK_DEBUG
|
|
|
|
#pragma message("GSock Debug mode compiled in")
|
|
|
|
#include <cstdio>
|
2018-06-06 08:42:54 +08:00
|
|
|
#define myliblog(fmt,...) printf("<GSock|%s> " fmt,__func__,##__VA_ARGS__)
|
|
|
|
#define myliblog_ex(cond,fmt,...) do{if(cond){myliblog(fmt,##__VA_ARGS__);}}while(0)
|
2017-08-15 09:54:10 +08:00
|
|
|
#else
|
2018-04-23 15:56:05 +08:00
|
|
|
#define myliblog(fmt,...)
|
2018-06-06 01:18:32 +08:00
|
|
|
#define myliblog_ex(cond,fmt,...)
|
2017-08-15 09:54:10 +08:00
|
|
|
#endif
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-08-25 23:35:37 +08:00
|
|
|
/* _WIN32_WINNT defines
|
|
|
|
Windows XP = 0x0501
|
|
|
|
Windows Server 2003 = 0x0502
|
|
|
|
Windows Vista, Windows Server 2008 = 0x0600
|
|
|
|
Windows 7 = 0x0601
|
|
|
|
Windows 8 = 0x0602
|
|
|
|
Windows 8.1 = 0x0603
|
|
|
|
Windows 10 = 0x0A00
|
|
|
|
*/
|
|
|
|
// Using Win10 by default
|
|
|
|
#define _WIN32_WINNT 0x0A00
|
2017-07-27 19:52:58 +08:00
|
|
|
#include <winsock2.h>
|
|
|
|
#include <ws2tcpip.h>
|
2018-06-12 09:41:15 +08:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
#pragma comment(lib,"ws2_32.lib")
|
|
|
|
#endif
|
2017-07-27 19:52:58 +08:00
|
|
|
#else
|
|
|
|
#include <arpa/inet.h>
|
|
|
|
#include <netinet/in.h>
|
|
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <netdb.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/epoll.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2018-07-05 01:56:22 +08:00
|
|
|
#include <sys/epoll.h>
|
2017-07-27 19:52:58 +08:00
|
|
|
#define closesocket close
|
|
|
|
using BYTE = unsigned char;
|
2018-06-06 08:42:54 +08:00
|
|
|
#define WSAGetLastError() errno
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
|
|
|
|
2018-02-10 13:06:45 +08:00
|
|
|
#include <cstring> /// memset
|
2017-07-27 19:52:58 +08:00
|
|
|
#include <string>
|
|
|
|
#include <stdexcept>
|
2018-05-29 13:36:38 +08:00
|
|
|
#include <vector>
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-09-09 16:11:28 +08:00
|
|
|
int InitNativeSocket()
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-09-09 16:11:28 +08:00
|
|
|
myliblog("sockaddr %d sockaddr_in %d sockaddr_in6 %d\n", sizeof(sockaddr), sizeof(sockaddr_in), sizeof(sockaddr_in6));
|
|
|
|
/// Windows Platform need WinSock2.DLL initialization.
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-09-09 16:11:28 +08:00
|
|
|
WORD wd;
|
|
|
|
WSAData wdt;
|
|
|
|
wd = MAKEWORD(2, 2);
|
|
|
|
int ret = WSAStartup(wd, &wdt);
|
2017-08-15 09:54:10 +08:00
|
|
|
|
2018-09-09 16:11:28 +08:00
|
|
|
myliblog("WSAStartup() Returns: %d\n", ret);
|
2017-08-15 09:54:10 +08:00
|
|
|
|
2018-09-09 16:11:28 +08:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
myliblog("WSAGetLastError: %d\n", WSAGetLastError());
|
|
|
|
return -1;
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
2018-09-09 16:11:28 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
class _init_winsock2_2_class
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
_init_winsock2_2_class()
|
|
|
|
{
|
|
|
|
if (InitNativeSocket() < 0)
|
|
|
|
{
|
|
|
|
throw std::runtime_error("Unable to Initialize native socket libray.");
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
~_init_winsock2_2_class()
|
|
|
|
{
|
|
|
|
/// Windows Platform need WinSock2.DLL clean up.
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2017-07-27 19:52:58 +08:00
|
|
|
WSACleanup();
|
2018-06-02 13:47:28 +08:00
|
|
|
myliblog("WSACleanup() called.\n");
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
} _init_winsock2_2_obj;
|
|
|
|
|
2018-06-05 13:13:06 +08:00
|
|
|
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";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
int GetNativeErrCode()
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
return WSAGetLastError();
|
|
|
|
#else
|
|
|
|
return errno;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:49:08 +08:00
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
|
|
|
|
gerrno TranslateNativeErrToGErr(int native_errcode)
|
|
|
|
{
|
|
|
|
switch (native_errcode)
|
|
|
|
{
|
|
|
|
#ifdef _WIN32
|
|
|
|
case WSAEWOULDBLOCK:
|
|
|
|
return gerrno::WouldBlock;
|
|
|
|
case WSAEINPROGRESS:
|
|
|
|
return gerrno::InProgress;
|
|
|
|
case WSAEALREADY:
|
|
|
|
return gerrno::Already;
|
|
|
|
case WSAEISCONN:
|
|
|
|
return gerrno::IsConnected;
|
2018-09-09 23:34:11 +08:00
|
|
|
case WSAEINTR:
|
|
|
|
return gerrno::Interrupted;
|
2018-09-09 22:35:18 +08:00
|
|
|
#else
|
2018-09-10 00:54:56 +08:00
|
|
|
case EWOULDBLOCK: // EAGAIN == EWOULDBLOCK
|
2018-09-09 22:35:18 +08:00
|
|
|
return gerrno::WouldBlock;
|
|
|
|
case EINPROGRESS:
|
|
|
|
return gerrno::InProgress;
|
|
|
|
case EALREADY:
|
|
|
|
return gerrno::Already;
|
|
|
|
case EISCONN:
|
|
|
|
return gerrno::IsConnected;
|
2018-09-09 23:34:11 +08:00
|
|
|
case EINTR:
|
|
|
|
return gerrno::Interrupted;
|
2018-09-09 22:35:18 +08:00
|
|
|
#endif
|
|
|
|
default:
|
|
|
|
myliblog("Unknown Error Code: %d\n", native_errcode);
|
|
|
|
return gerrno::UnknownError;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
struct vsock::_impl
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
int sfd;
|
|
|
|
bool created;
|
2018-09-09 22:35:18 +08:00
|
|
|
bool nonblocking;
|
|
|
|
|
|
|
|
// Does not set "nonblocking" flag.
|
|
|
|
int doSetNonblocking()
|
|
|
|
{
|
2018-09-10 00:54:56 +08:00
|
|
|
#ifdef _WIN32
|
2018-09-09 22:35:18 +08:00
|
|
|
u_long mode = 1;
|
|
|
|
if (ioctlsocket(sfd, FIONBIO, &mode) == 0)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2018-09-10 00:54:56 +08:00
|
|
|
#else
|
|
|
|
int flag = fcntl(sfd, F_GETFL, 0);
|
|
|
|
if (flag < 0) return -1;
|
|
|
|
flag |= O_NONBLOCK;
|
|
|
|
if (fcntl(sfd, F_SETFL, flag) < 0) return -1;
|
|
|
|
return 0;
|
|
|
|
#endif
|
2018-09-09 22:35:18 +08:00
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
};
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
vsock::vsock() : _vp(new _impl)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
_vp->created=false;
|
2018-09-09 22:35:18 +08:00
|
|
|
_vp->nonblocking = false;
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
vsock::vsock(vsock&& v)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
_vp=v._vp;
|
|
|
|
v._vp=nullptr;
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
vsock& vsock::operator = (vsock&& v)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
this->~vsock();
|
|
|
|
_vp=v._vp;
|
|
|
|
v._vp=nullptr;
|
|
|
|
return *this;
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
int vsock::setNonblocking()
|
|
|
|
{
|
|
|
|
if (!_vp->nonblocking)
|
|
|
|
{
|
|
|
|
if (_vp->created)
|
|
|
|
{
|
|
|
|
if (_vp->doSetNonblocking() == 0)
|
|
|
|
{
|
|
|
|
_vp->nonblocking = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Failed to set non-blocking.
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Socket is not created yet. Just mark it.
|
|
|
|
_vp->nonblocking = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Socket is already in non-blocking mode.
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
vsock::~vsock()
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
if(_vp)
|
|
|
|
{
|
|
|
|
if(_vp->created)
|
|
|
|
{
|
2018-06-06 01:18:32 +08:00
|
|
|
myliblog("Socket closed: [%d] with _vp %p\n",_vp->sfd,_vp);
|
2018-05-05 15:37:50 +08:00
|
|
|
closesocket(_vp->sfd);
|
|
|
|
|
|
|
|
_vp->created=false;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete _vp;
|
|
|
|
_vp=nullptr;
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
struct sock::_impl
|
|
|
|
{
|
2018-09-09 22:35:18 +08:00
|
|
|
static int create_socket(vsock::_impl* _vp, int af_protocol);
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
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);
|
2018-09-09 22:35:18 +08:00
|
|
|
|
|
|
|
static int connect_real(vsock::_impl* _vp, int af_protocol, const sockaddr* paddr, int size);
|
2018-06-02 13:47:28 +08:00
|
|
|
};
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
// static
|
|
|
|
int sock::_impl::create_socket(vsock::_impl* _vp, int af_protocol)
|
|
|
|
{
|
|
|
|
// If socket is not created, then create it.
|
|
|
|
if (!_vp->created)
|
|
|
|
{
|
|
|
|
_vp->sfd = socket(af_protocol, SOCK_STREAM, 0);
|
|
|
|
if (_vp->sfd < 0)
|
|
|
|
{
|
|
|
|
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
|
|
|
return GSOCK_ERROR_CREAT;
|
|
|
|
}
|
|
|
|
if (_vp->nonblocking && _vp->doSetNonblocking() != 0)
|
|
|
|
{
|
|
|
|
myliblog("Failed to set socket to nonblocking with _vp %p\n", _vp);
|
|
|
|
// close this socket to avoid fd leak.
|
|
|
|
closesocket(_vp->sfd);
|
|
|
|
return GSOCK_ERROR_SETMODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
myliblog("Socket <%s> created: [%d] with _vp %p. %s\n",
|
|
|
|
(af_protocol == AF_INET ? "IPv4" : "IPv6"),
|
|
|
|
_vp->sfd, _vp, (_vp->nonblocking ? "NonBlocking" : "Blocking"));
|
|
|
|
_vp->created = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// static
|
2018-06-02 13:47:28 +08:00
|
|
|
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)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_IP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
saddr.sin_port = htons(Port);
|
|
|
|
saddr.sin_family = AF_INET;
|
|
|
|
|
2018-06-03 10:08:03 +08:00
|
|
|
// only returns -1 or 0
|
2018-09-09 22:35:18 +08:00
|
|
|
return connect_real(_vp, AF_INET, (sockaddr*)&saddr, sizeof(saddr));
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
// static
|
2018-06-02 13:47:28 +08:00
|
|
|
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)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_IP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
saddr.sin6_port = htons(Port);
|
|
|
|
saddr.sin6_family = AF_INET6;
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
// only returns -1 or 0
|
|
|
|
return connect_real(_vp, AF_INET6, (sockaddr*)&saddr, sizeof(saddr));
|
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
// static
|
|
|
|
int sock::_impl::connect_real(vsock::_impl* _vp, int af_protocol, const sockaddr* paddr, int namelen)
|
|
|
|
{
|
|
|
|
// Create socket
|
|
|
|
int ret = create_socket(_vp, af_protocol);
|
|
|
|
if (ret != 0) return ret;
|
|
|
|
return ::connect(_vp->sfd, paddr, namelen);
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
|
2017-07-27 19:52:58 +08:00
|
|
|
int sock::connect(const std::string& IPStr,int Port)
|
|
|
|
{
|
2017-08-15 09:54:10 +08:00
|
|
|
myliblog("sock::connect() %p\n",this);
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
if (_vp->nonblocking)
|
|
|
|
{
|
|
|
|
return GSOCK_MISMATCH_MODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_vp->created)
|
|
|
|
{
|
|
|
|
return GSOCK_INVALID_SOCKET;
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
if (IPStr.find(":") != std::string::npos)
|
|
|
|
{
|
|
|
|
// Maybe IPv6
|
|
|
|
return sock::_impl::connect_ipv6(_vp, IPStr, Port);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Maybe IPv4
|
|
|
|
return sock::_impl::connect_ipv4(_vp, IPStr, Port);
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
struct NBConnectResult::_impl
|
|
|
|
{
|
|
|
|
int sfd;
|
|
|
|
struct sockaddr_in saddr;
|
|
|
|
struct sockaddr_in6 saddr6;
|
|
|
|
bool isv4;
|
|
|
|
// 0: Not used.
|
|
|
|
// 1: running
|
|
|
|
// 2: finished, connected.
|
|
|
|
// 3: finished, failed.
|
|
|
|
int status;
|
|
|
|
|
2018-09-10 01:35:48 +08:00
|
|
|
gerrno errcode;
|
2018-09-09 22:35:18 +08:00
|
|
|
|
|
|
|
void update();
|
|
|
|
};
|
|
|
|
|
|
|
|
void NBConnectResult::_impl::update()
|
|
|
|
{
|
|
|
|
// Already finished.
|
|
|
|
if (status > 1) return;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
if (isv4)
|
|
|
|
{
|
|
|
|
ret = connect(sfd, (sockaddr*)&saddr, sizeof(saddr));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = connect(sfd, (sockaddr*)&saddr6, sizeof(saddr6));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret == 0)
|
|
|
|
{
|
|
|
|
status = 2;
|
|
|
|
}
|
2018-09-09 23:34:11 +08:00
|
|
|
else // ret == -1
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
|
|
|
gerrno err = TranslateNativeErrToGErr(GetNativeErrCode());
|
2018-09-09 23:34:11 +08:00
|
|
|
errcode = err;
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
if (err == gerrno::InProgress || err == gerrno::WouldBlock || err == gerrno::Already)
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
else if (err == gerrno::IsConnected)
|
|
|
|
{
|
|
|
|
status = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
myliblog("NBConnectResult Status updated to %d\n", status);
|
2018-09-09 22:35:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
NBConnectResult::NBConnectResult() : _p(new _impl)
|
|
|
|
{
|
|
|
|
_p->status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBConnectResult::isFinished()
|
|
|
|
{
|
|
|
|
_p->update();
|
|
|
|
return (_p->status > 1);
|
|
|
|
}
|
|
|
|
|
2018-09-10 01:35:48 +08:00
|
|
|
bool NBConnectResult::isSuccess()
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
|
|
|
return (_p->status == 2);
|
|
|
|
}
|
|
|
|
|
2018-09-10 01:35:48 +08:00
|
|
|
gerrno NBConnectResult::getErrCode()
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
|
|
|
return _p->errcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NBConnectResult::wait()
|
|
|
|
{
|
|
|
|
while (!isFinished());
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
struct NBSendResult::_impl
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
|
|
|
int sfd;
|
2018-09-09 23:34:11 +08:00
|
|
|
const char* ptr;
|
|
|
|
int total;
|
|
|
|
int done;
|
|
|
|
|
|
|
|
// 0: Not started.
|
|
|
|
// 1: Data is being sent
|
|
|
|
// 2: Data sent without error.
|
|
|
|
// 3: Error occurs.
|
|
|
|
int status;
|
2018-09-09 22:35:18 +08:00
|
|
|
|
2018-09-09 23:49:08 +08:00
|
|
|
gerrno errcode;
|
2018-09-09 23:34:11 +08:00
|
|
|
|
|
|
|
void update();
|
2018-09-09 22:35:18 +08:00
|
|
|
};
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
void NBSendResult::_impl::update()
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
2018-09-10 00:54:56 +08:00
|
|
|
if (status > 1) return;
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
int ret = send(sfd, ptr + done, total - done, 0);
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
done += ret;
|
|
|
|
if (done == total)
|
|
|
|
{
|
|
|
|
status = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ret == 0)
|
|
|
|
{
|
|
|
|
status = 3;
|
2018-09-09 23:49:08 +08:00
|
|
|
errcode = gerrno::OK;
|
2018-09-09 23:34:11 +08:00
|
|
|
}
|
|
|
|
else // ret == -1
|
|
|
|
{
|
|
|
|
gerrno err = TranslateNativeErrToGErr(GetNativeErrCode());
|
|
|
|
errcode = err;
|
|
|
|
|
|
|
|
if (err == gerrno::WouldBlock)
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
myliblog("NBSendResult status updated to %d\n", status);
|
|
|
|
}
|
2018-09-09 22:35:18 +08:00
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
NBSendResult::NBSendResult() : _p(new _impl)
|
|
|
|
{
|
|
|
|
_p->status = 0;
|
2018-09-09 22:35:18 +08:00
|
|
|
}
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
bool NBSendResult::isFinished()
|
|
|
|
{
|
|
|
|
_p->update();
|
|
|
|
return (_p->status > 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NBSendResult::wait()
|
|
|
|
{
|
|
|
|
while (!isFinished());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBSendResult::isSuccess()
|
|
|
|
{
|
|
|
|
return (_p->status == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int NBSendResult::getBytesDone()
|
|
|
|
{
|
|
|
|
return _p->done;
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:49:08 +08:00
|
|
|
gerrno NBSendResult::getErrCode()
|
2018-09-09 23:34:11 +08:00
|
|
|
{
|
|
|
|
return _p->errcode;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct NBRecvResult::_impl
|
|
|
|
{
|
|
|
|
int sfd;
|
|
|
|
char* ptr;
|
|
|
|
int maxsz;
|
|
|
|
int done;
|
|
|
|
|
|
|
|
// When work together with epoll at ET mode, setting this flag can avoid infinite EAGAIN recv loop.
|
|
|
|
bool stopAtEdge;
|
|
|
|
|
|
|
|
// 0: Not started.
|
|
|
|
// 1: Data is being sent
|
|
|
|
// 2: Data sent without error.
|
|
|
|
// 3: Error occurs.
|
|
|
|
int status;
|
|
|
|
|
2018-09-09 23:49:08 +08:00
|
|
|
gerrno errcode;
|
2018-09-09 23:34:11 +08:00
|
|
|
|
|
|
|
void update();
|
|
|
|
};
|
|
|
|
|
|
|
|
void NBRecvResult::_impl::update()
|
|
|
|
{
|
2018-09-10 00:54:56 +08:00
|
|
|
if (status > 1) return;
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
int ret = recv(sfd, ptr + done, maxsz - done, 0);
|
|
|
|
if (ret > 0)
|
|
|
|
{
|
|
|
|
done += ret;
|
|
|
|
if (done == maxsz)
|
|
|
|
{
|
|
|
|
status = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ret == 0)
|
|
|
|
{
|
|
|
|
status = 3;
|
2018-09-09 23:49:08 +08:00
|
|
|
errcode = gerrno::OK;
|
2018-09-09 23:34:11 +08:00
|
|
|
}
|
|
|
|
else // ret == -1
|
|
|
|
{
|
|
|
|
gerrno err = TranslateNativeErrToGErr(GetNativeErrCode());
|
|
|
|
errcode = err;
|
|
|
|
|
|
|
|
if (err == gerrno::WouldBlock)
|
|
|
|
{
|
|
|
|
if (stopAtEdge)
|
|
|
|
{
|
|
|
|
status = 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
myliblog("NBRecvResult status updated to %d\n", status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NBRecvResult::NBRecvResult() : _p(new _impl)
|
|
|
|
{
|
|
|
|
_p->status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void NBRecvResult::setStopAtEdge(bool flag)
|
|
|
|
{
|
|
|
|
_p->stopAtEdge = flag;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBRecvResult::isFinished()
|
|
|
|
{
|
|
|
|
_p->update();
|
|
|
|
return (_p->status > 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void NBRecvResult::wait()
|
|
|
|
{
|
|
|
|
while (!isFinished());
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBRecvResult::isSuccess()
|
|
|
|
{
|
|
|
|
return (_p->status == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
int NBRecvResult::getBytesDone()
|
|
|
|
{
|
|
|
|
return _p->done;
|
|
|
|
}
|
|
|
|
|
2018-09-09 23:49:08 +08:00
|
|
|
gerrno NBRecvResult::getErrCode()
|
2018-09-09 23:34:11 +08:00
|
|
|
{
|
|
|
|
return _p->errcode;
|
|
|
|
}
|
|
|
|
|
2018-09-09 22:35:18 +08:00
|
|
|
NBConnectResult sock::connect_nb(const std::string& IPStr, int Port)
|
|
|
|
{
|
|
|
|
NBConnectResult res;
|
|
|
|
int xret;
|
|
|
|
|
|
|
|
if (IPStr.find(":") != std::string::npos)
|
|
|
|
{
|
|
|
|
// Maybe IPv6
|
|
|
|
memset(&(res._p->saddr6), 0, sizeof(res._p->saddr6));
|
|
|
|
if (inet_pton(AF_INET6, IPStr.c_str(), &(res._p->saddr6.sin6_addr)) != 1)
|
|
|
|
{
|
|
|
|
// Failed.
|
|
|
|
res._p->status = 3;
|
2018-09-10 01:35:48 +08:00
|
|
|
res._p->errcode = (gerrno)GSOCK_INVALID_IP;
|
2018-09-09 22:35:18 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res._p->saddr6.sin6_port = htons(Port);
|
|
|
|
res._p->saddr6.sin6_family = AF_INET6;
|
|
|
|
|
|
|
|
res._p->isv4 = false;
|
|
|
|
xret = _impl::connect_real(_vp, AF_INET6, (sockaddr*)&(res._p->saddr6), sizeof(res._p->saddr6));
|
|
|
|
res._p->sfd = _vp->sfd;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Maybe IPv4
|
|
|
|
memset(&(res._p->saddr), 0, sizeof(res._p->saddr));
|
|
|
|
if (inet_pton(AF_INET, IPStr.c_str(), &(res._p->saddr.sin_addr.s_addr)) != 1)
|
|
|
|
{
|
|
|
|
// Failed.
|
|
|
|
res._p->status = 3;
|
2018-09-10 01:35:48 +08:00
|
|
|
res._p->errcode = (gerrno)GSOCK_INVALID_IP;
|
2018-09-09 22:35:18 +08:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
res._p->saddr.sin_port = htons(Port);
|
|
|
|
res._p->saddr.sin_family = AF_INET;
|
|
|
|
|
|
|
|
res._p->isv4 = true;
|
|
|
|
xret = _impl::connect_real(_vp, AF_INET, (sockaddr*)&(res._p->saddr), sizeof(res._p->saddr));
|
|
|
|
res._p->sfd = _vp->sfd;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xret == 0)
|
|
|
|
{
|
|
|
|
res._p->status = 2; // Socket is connected immediately! Amazing!!
|
|
|
|
}
|
|
|
|
else if (xret == -1)
|
|
|
|
{
|
|
|
|
res._p->status = 1;
|
|
|
|
}
|
2018-09-10 01:35:48 +08:00
|
|
|
else // xret is a GSock error
|
2018-09-09 22:35:18 +08:00
|
|
|
{
|
|
|
|
// Failed
|
|
|
|
res._p->status = 3;
|
2018-09-10 01:35:48 +08:00
|
|
|
res._p->errcode = (gerrno)xret;
|
2018-09-09 22:35:18 +08:00
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-02-11 15:41:52 +08:00
|
|
|
int sock::send(const void* Buffer,int Length)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
return ::send(_vp->sfd,(const char*)Buffer,Length,0);
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-02-11 15:41:52 +08:00
|
|
|
int sock::recv(void* Buffer,int MaxToRecv)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
return ::recv(_vp->sfd,(char*)Buffer,MaxToRecv,0);
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-09-09 23:34:11 +08:00
|
|
|
NBSendResult sock::send_nb(const void* Buffer, int Length)
|
|
|
|
{
|
|
|
|
NBSendResult res;
|
|
|
|
res._p->ptr = (const char*)Buffer;
|
|
|
|
res._p->total = Length;
|
|
|
|
res._p->done = 0;
|
|
|
|
res._p->sfd = _vp->sfd;
|
|
|
|
|
|
|
|
res._p->update();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
NBRecvResult sock::recv_nb(void* Buffer, int MaxToRecv)
|
|
|
|
{
|
|
|
|
NBRecvResult res;
|
|
|
|
res._p->ptr = (char*)Buffer;
|
|
|
|
res._p->maxsz = MaxToRecv;
|
|
|
|
res._p->done = 0;
|
|
|
|
res._p->stopAtEdge = false;
|
|
|
|
res._p->sfd = _vp->sfd;
|
|
|
|
|
|
|
|
res._p->update();
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-07-27 19:52:58 +08:00
|
|
|
int sock::getsendtime(int& _out_Second, int& _out_uSecond)
|
|
|
|
{
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-06-12 09:41:15 +08:00
|
|
|
int result;
|
|
|
|
socklen_t _not_used_t = sizeof(result);
|
|
|
|
int ret = getsockopt(_vp->sfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&result, &_not_used_t);
|
|
|
|
if (ret<0) return ret;
|
|
|
|
_out_Second = result / 1000;
|
|
|
|
_out_uSecond = result % 1000;
|
2017-07-27 19:52:58 +08:00
|
|
|
#else
|
2018-06-12 09:41:15 +08:00
|
|
|
struct timeval outtime;
|
|
|
|
socklen_t _not_used_t = sizeof(outtime);
|
|
|
|
int ret = getsockopt(_vp->sfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&outtime, &_not_used_t);
|
|
|
|
if (ret<0) return ret;
|
|
|
|
_out_Second = outtime.tv_sec;
|
|
|
|
_out_uSecond = outtime.tv_usec;
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int sock::getrecvtime(int& _out_Second, int& _out_uSecond)
|
|
|
|
{
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-06-12 09:41:15 +08:00
|
|
|
int result;
|
|
|
|
socklen_t _not_used_t = sizeof(result);
|
|
|
|
int ret = getsockopt(_vp->sfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&result, &_not_used_t);
|
|
|
|
if (ret<0) return ret;
|
|
|
|
_out_Second=result/1000;
|
|
|
|
_out_uSecond = result % 1000;
|
2017-07-27 19:52:58 +08:00
|
|
|
#else
|
2018-06-12 09:41:15 +08:00
|
|
|
struct timeval outtime;
|
|
|
|
socklen_t _not_used_t = sizeof(outtime);
|
|
|
|
int ret = getsockopt(_vp->sfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&outtime, &_not_used_t);
|
|
|
|
if (ret<0) return ret;
|
2017-07-27 19:52:58 +08:00
|
|
|
_out_Second=outtime.tv_sec;
|
|
|
|
_out_uSecond=outtime.tv_usec;
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-12 09:41:15 +08:00
|
|
|
int sock::setsendtime(int Second, int Millisecond)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-06-12 09:41:15 +08:00
|
|
|
int outtime = Second * 1000 + Millisecond % 1000;
|
2017-07-27 19:52:58 +08:00
|
|
|
#else
|
2018-06-12 09:41:15 +08:00
|
|
|
struct timeval outtime;
|
|
|
|
outtime.tv_sec = Second;
|
|
|
|
outtime.tv_usec = Millisecond;
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
return setsockopt(_vp->sfd,SOL_SOCKET,SO_SNDTIMEO,(const char*)&outtime,sizeof(outtime));
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-06-12 09:41:15 +08:00
|
|
|
int sock::setrecvtime(int Second, int Millisecond)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-04-23 15:56:05 +08:00
|
|
|
#ifdef _WIN32
|
2018-06-12 09:41:15 +08:00
|
|
|
int outtime = Second * 1000 + Millisecond % 1000;
|
2017-07-27 19:52:58 +08:00
|
|
|
#else
|
2018-06-12 09:41:15 +08:00
|
|
|
struct timeval outtime;
|
|
|
|
outtime.tv_sec = Second;
|
|
|
|
outtime.tv_usec = Millisecond;
|
2017-07-27 19:52:58 +08:00
|
|
|
#endif
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
return setsockopt(_vp->sfd,SOL_SOCKET,SO_RCVTIMEO,(const char*)&outtime,sizeof(outtime));
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-06-12 09:41:15 +08:00
|
|
|
int sock::setkeepalive(bool op)
|
|
|
|
{
|
|
|
|
int option = op ? 1 : 0;
|
|
|
|
return setsockopt(_vp->sfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&option, sizeof(option));
|
|
|
|
}
|
|
|
|
|
2018-05-04 17:44:39 +08:00
|
|
|
//forgive me, but writing code in hospital is really not a good experience.
|
2018-05-09 21:30:34 +08:00
|
|
|
using _sock_getname_callback_t = decltype(getsockname);
|
2018-05-04 18:04:29 +08:00
|
|
|
|
2018-06-05 13:13:06 +08:00
|
|
|
union _sock_getname_pack
|
|
|
|
{
|
|
|
|
sockaddr saddr;
|
|
|
|
sockaddr_in saddr4;
|
|
|
|
sockaddr_in6 saddr6;
|
|
|
|
};
|
|
|
|
|
2018-05-04 18:04:29 +08:00
|
|
|
static int _sock_getname_call(int sfd,std::string& ip,int& port,_sock_getname_callback_t fn)
|
2018-05-04 17:44:39 +08:00
|
|
|
{
|
2018-06-05 13:13:06 +08:00
|
|
|
_sock_getname_pack pack;
|
|
|
|
socklen_t saddrlen=sizeof(pack);
|
|
|
|
memset(&pack,0,saddrlen);
|
|
|
|
int ret=fn(sfd,&pack.saddr,&saddrlen);
|
2018-05-04 18:04:29 +08:00
|
|
|
if(ret<0) return ret; //don't bother errno. stop here.
|
2018-06-05 13:13:06 +08:00
|
|
|
if (pack.saddr.sa_family == AF_INET)
|
2018-06-02 13:47:28 +08:00
|
|
|
{
|
2018-06-05 13:13:06 +08:00
|
|
|
struct sockaddr_in* paddr = &pack.saddr4;
|
2018-06-02 13:47:28 +08:00
|
|
|
char ip_buff[64] = { 0 };
|
2018-06-07 20:04:28 +08:00
|
|
|
const char* pret = inet_ntop(AF_INET, &(paddr->sin_addr), ip_buff, 64);
|
2018-06-02 13:47:28 +08:00
|
|
|
if (pret)
|
|
|
|
{
|
|
|
|
ip = std::string(ip_buff);
|
|
|
|
port = ntohs(paddr->sin_port);
|
2018-06-05 13:13:06 +08:00
|
|
|
return 0;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// inet_ntop call failed.
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_ERROR_NTOP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
}
|
2018-06-05 13:13:06 +08:00
|
|
|
else if (pack.saddr.sa_family == AF_INET6)
|
2018-06-02 13:47:28 +08:00
|
|
|
{
|
2018-06-05 13:13:06 +08:00
|
|
|
struct sockaddr_in6* paddr = &pack.saddr6;
|
2018-06-02 13:47:28 +08:00
|
|
|
char ip_buff[128] = { 0 };
|
2018-06-07 20:04:28 +08:00
|
|
|
const char* pret = inet_ntop(AF_INET6, &(paddr->sin6_addr), ip_buff, 128);
|
2018-06-02 13:47:28 +08:00
|
|
|
if (pret)
|
|
|
|
{
|
|
|
|
ip = std::string(ip_buff);
|
|
|
|
port = ntohs(paddr->sin6_port);
|
2018-06-05 13:13:06 +08:00
|
|
|
return 1;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// inet_ntop call failed.
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_ERROR_NTOP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// protocol not supported.
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_UNKNOWN_PROTOCOL;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
2018-05-04 17:44:39 +08:00
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-05-04 18:04:29 +08:00
|
|
|
int sock::getlocal(std::string& IPStr,int& Port)
|
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
if(!(_vp->created))
|
2018-05-04 18:04:29 +08:00
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-05-04 18:04:29 +08:00
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
return _sock_getname_call(_vp->sfd,IPStr,Port,getsockname);
|
2018-05-04 18:04:29 +08:00
|
|
|
}
|
|
|
|
|
2018-05-04 17:44:39 +08:00
|
|
|
int sock::getpeer(std::string& IPStr,int& Port)
|
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
if(!(_vp->created))
|
2018-05-04 18:04:29 +08:00
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-05-04 18:04:29 +08:00
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
return _sock_getname_call(_vp->sfd,IPStr,Port,getpeername);
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-05-17 19:38:40 +08:00
|
|
|
struct serversock::_impl
|
|
|
|
{
|
|
|
|
public:
|
2018-06-03 10:28:04 +08:00
|
|
|
int protocol;
|
|
|
|
bool is_protocol_decided;
|
|
|
|
|
|
|
|
int create_socket(vsock::_impl* _vp)
|
2018-05-17 19:38:40 +08:00
|
|
|
{
|
|
|
|
if (_vp->created)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-05-17 19:38:40 +08:00
|
|
|
}
|
2018-06-03 10:28:04 +08:00
|
|
|
_vp->sfd = socket(protocol, SOCK_STREAM, 0);
|
2018-05-17 19:38:40 +08:00
|
|
|
if (_vp->sfd<0)
|
|
|
|
{
|
|
|
|
myliblog("socket() returns %d. WSAGetLastError: %d\n", _vp->sfd, WSAGetLastError());
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_ERROR_CREAT;
|
2018-05-17 19:38:40 +08:00
|
|
|
}
|
2018-06-06 01:18:32 +08:00
|
|
|
myliblog("Socket <%s> created: [%d] with _vp %p\n", protocol == AF_INET ? "IPv4" : "IPv6", _vp->sfd, _vp);
|
2018-05-17 19:38:40 +08:00
|
|
|
_vp->created = true;
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_OK;
|
2018-05-17 19:38:40 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-06-03 10:28:04 +08:00
|
|
|
serversock::serversock(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 serversock %p\n", get_family_name(_pp->protocol), this);
|
|
|
|
}
|
|
|
|
else if (use_family == 2)
|
|
|
|
{
|
|
|
|
_pp->protocol = AF_INET6;
|
|
|
|
_pp->is_protocol_decided = true;
|
|
|
|
myliblog("Protocol decided to %s in serversock %p\n", get_family_name(_pp->protocol), this);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_pp->is_protocol_decided = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-06 01:04:41 +08:00
|
|
|
serversock::~serversock()
|
|
|
|
{
|
|
|
|
if (_pp)
|
|
|
|
{
|
|
|
|
delete _pp;
|
|
|
|
_pp = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-27 19:52:58 +08:00
|
|
|
int serversock::bind(int Port)
|
|
|
|
{
|
2017-08-15 09:54:10 +08:00
|
|
|
myliblog("serversock::bind() %p\n",this);
|
|
|
|
|
2018-05-17 19:38:40 +08:00
|
|
|
if (!_vp->created)
|
|
|
|
{
|
2018-06-03 10:28:04 +08:00
|
|
|
if (!_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
_pp->protocol = AF_INET;
|
|
|
|
_pp->is_protocol_decided = true;
|
|
|
|
myliblog("Protocol decided to %s in serversock %p\n", get_family_name(_pp->protocol), this);
|
|
|
|
}
|
|
|
|
int ret = _pp->create_socket(_vp);
|
2018-05-17 19:38:40 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
|
2018-06-03 10:28:04 +08:00
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
sockaddr_in saddr;
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-06-03 10:28:04 +08:00
|
|
|
memset(&saddr, 0, sizeof(saddr));
|
|
|
|
saddr.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
saddr.sin_port = htons(Port);
|
|
|
|
saddr.sin_family = AF_INET;
|
|
|
|
return ::bind(_vp->sfd, (sockaddr*)&saddr, sizeof(saddr));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sockaddr_in6 saddr;
|
|
|
|
|
|
|
|
memset(&saddr, 0, sizeof(saddr));
|
|
|
|
saddr.sin6_addr = in6addr_any;
|
|
|
|
saddr.sin6_port = htons(Port);
|
|
|
|
saddr.sin6_family = AF_INET6;
|
|
|
|
return ::bind(_vp->sfd, (sockaddr*)&saddr, sizeof(saddr));
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int serversock::set_reuse()
|
|
|
|
{
|
2018-05-17 19:38:40 +08:00
|
|
|
if (!_vp->created)
|
|
|
|
{
|
2018-06-03 10:28:04 +08:00
|
|
|
if (!_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
_pp->protocol = AF_INET;
|
|
|
|
_pp->is_protocol_decided = true;
|
|
|
|
myliblog("Protocol decided to %s in serversock %p\n", get_family_name(_pp->protocol), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ret = _pp->create_socket(_vp);
|
2018-05-17 19:38:40 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
socklen_t opt=1;
|
|
|
|
return setsockopt(_vp->sfd,SOL_SOCKET,SO_REUSEADDR,(const char*)&opt,sizeof(opt));
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int serversock::listen(int MaxCount)
|
|
|
|
{
|
2018-06-03 10:28:04 +08:00
|
|
|
if (!_vp->created)
|
|
|
|
{
|
|
|
|
// Socket is not created. Call bind() first.
|
|
|
|
return GSOCK_INVALID_SOCKET;
|
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
return ::listen(_vp->sfd,MaxCount);
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-09-10 01:35:48 +08:00
|
|
|
struct NBAcceptResult::_impl
|
|
|
|
{
|
|
|
|
int sfd;
|
|
|
|
|
|
|
|
// For client use
|
|
|
|
bool isv4;
|
|
|
|
sockaddr_in saddr;
|
|
|
|
sockaddr_in6 saddr6;
|
|
|
|
socklen_t saddrsz;
|
|
|
|
|
|
|
|
sock* out_binding;
|
|
|
|
int* out_binding_sfd;
|
|
|
|
bool* out_binding_created;
|
|
|
|
|
|
|
|
// 0 Not started.
|
|
|
|
// 1 Accepting
|
|
|
|
// 2 Accept success.
|
|
|
|
// 3 Accept failed.
|
|
|
|
int status;
|
|
|
|
gerrno errcode;
|
|
|
|
|
|
|
|
void update();
|
|
|
|
};
|
|
|
|
|
|
|
|
void NBAcceptResult::_impl::update()
|
|
|
|
{
|
|
|
|
if (status > 1) return;
|
|
|
|
|
|
|
|
int ret;
|
|
|
|
if (isv4)
|
|
|
|
{
|
|
|
|
ret = accept(sfd, (sockaddr*)&saddr, &saddrsz);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = accept(sfd, (sockaddr*)&saddr6, &saddrsz);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ret >= 0)
|
|
|
|
{
|
|
|
|
*out_binding_sfd = sfd;
|
|
|
|
*out_binding_created = true;
|
|
|
|
status = 2;
|
|
|
|
}
|
|
|
|
else // ret == -1
|
|
|
|
{
|
|
|
|
gerrno err = TranslateNativeErrToGErr(GetNativeErrCode());
|
|
|
|
errcode = err;
|
|
|
|
if (err == gerrno::InProgress || err == gerrno::WouldBlock || err == gerrno::Already)
|
|
|
|
{
|
|
|
|
status = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
status = 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
myliblog("NBAcceptResult status updated to %d\n", status);
|
|
|
|
}
|
|
|
|
|
|
|
|
NBAcceptResult::NBAcceptResult() : _sp(new _impl)
|
|
|
|
{
|
|
|
|
_sp->status = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBAcceptResult::isFinished()
|
|
|
|
{
|
|
|
|
_sp->update();
|
|
|
|
return (_sp->status > 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool NBAcceptResult::isSuccess()
|
|
|
|
{
|
|
|
|
return (_sp->status == 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
sock& NBAcceptResult::get()
|
|
|
|
{
|
|
|
|
return *(_sp->out_binding);
|
|
|
|
}
|
|
|
|
|
|
|
|
gerrno NBAcceptResult::getErrCode()
|
|
|
|
{
|
|
|
|
return _sp->errcode;
|
|
|
|
}
|
|
|
|
|
2017-08-15 09:54:10 +08:00
|
|
|
int serversock::accept(sock& _out_s)
|
2017-07-27 19:52:58 +08:00
|
|
|
{
|
2018-06-03 10:28:04 +08:00
|
|
|
if( (!_vp->created) || (_out_s._vp->created) )
|
2017-08-15 09:54:10 +08:00
|
|
|
{
|
|
|
|
/// _out_s has been connected.
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_SOCKET;
|
2017-08-15 09:54:10 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
sock s; /// empty socket.
|
2018-06-03 10:28:04 +08:00
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
sockaddr_in saddr;
|
2018-06-03 10:28:04 +08:00
|
|
|
sockaddr_in6 saddr6;
|
|
|
|
socklen_t saddrsz = (_pp->protocol == AF_INET) ? sizeof(saddr) : sizeof(saddr6);
|
2018-05-05 15:37:50 +08:00
|
|
|
|
2018-06-03 10:28:04 +08:00
|
|
|
int ret;
|
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
ret= ::accept(_vp->sfd, (sockaddr*)&(saddr), &saddrsz);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ret = ::accept(_vp->sfd, (sockaddr*)&(saddr6), &saddrsz);
|
|
|
|
}
|
|
|
|
|
2017-07-27 19:52:58 +08:00
|
|
|
if(ret<0)
|
|
|
|
{
|
2017-08-15 09:54:10 +08:00
|
|
|
/// accept() call failed.
|
|
|
|
myliblog("accept() returns %d. WSAGetLastError: %d\n",ret,WSAGetLastError());
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_API_ERROR;
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
s._vp->sfd=ret;
|
|
|
|
s._vp->created=true;
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-06-06 01:18:32 +08:00
|
|
|
myliblog("Socket opened: [%d] as sock::_vp %p by serversock::_vp: %p\n",s._vp->sfd,s._vp,_vp);
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2017-08-15 09:54:10 +08:00
|
|
|
/// Move resource.
|
|
|
|
_out_s=std::move(s);
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_OK;
|
2017-08-15 09:54:10 +08:00
|
|
|
}
|
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-09-10 01:35:48 +08:00
|
|
|
NBAcceptResult serversock::accept_nb(sock& _out_s)
|
|
|
|
{
|
|
|
|
NBAcceptResult res;
|
|
|
|
if ((!_vp->created) || (_out_s._vp->created))
|
|
|
|
{
|
|
|
|
/// _out_s has been connected.
|
|
|
|
res._sp->status = 3;
|
|
|
|
res._sp->errcode = (gerrno)GSOCK_INVALID_SOCKET;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
res._sp->sfd = _vp->sfd;
|
|
|
|
res._sp->out_binding = &_out_s;
|
|
|
|
res._sp->out_binding_sfd = &(_out_s._vp->sfd);
|
|
|
|
res._sp->out_binding_created = &(_out_s._vp->created);
|
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
res._sp->isv4 = true;
|
|
|
|
res._sp->saddrsz = sizeof(res._sp->saddr);
|
|
|
|
res._sp->update();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
res._sp->isv4 = false;
|
|
|
|
res._sp->saddrsz = sizeof(res._sp->saddr6);
|
|
|
|
res._sp->update();
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
struct udpsock::_impl
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
int protocol;
|
|
|
|
bool is_protocol_decided;
|
|
|
|
|
2018-06-06 00:34:22 +08:00
|
|
|
_impl()
|
|
|
|
{
|
|
|
|
is_protocol_decided = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is now an internal function and should not be called outside _impl.
|
|
|
|
int _make_decided(vsock::_impl* _vp)
|
2018-06-02 13:47:28 +08:00
|
|
|
{
|
|
|
|
if (_vp->created)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_vp->sfd = socket(protocol, SOCK_DGRAM, 0);
|
2018-06-03 10:08:03 +08:00
|
|
|
if (_vp->sfd < 0)
|
|
|
|
{
|
|
|
|
return GSOCK_ERROR_CREAT;
|
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
_vp->created = true;
|
2018-06-06 01:18:32 +08:00
|
|
|
myliblog("Socket <%s> created: [%d] with _vp %p\n", protocol == AF_INET ? "IPv4" : "IPv6", _vp->sfd, _vp);
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_OK;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
}
|
2018-06-06 00:34:22 +08:00
|
|
|
|
2018-06-06 01:04:41 +08:00
|
|
|
// Decide the protocol
|
|
|
|
// Return:
|
|
|
|
// GSOCK_OK
|
|
|
|
// GSOCK_MISMATCH_PROTOCOL
|
|
|
|
// GSOCK_INVALID_SOCKET
|
|
|
|
// GSOCK_ERROR_CREAT
|
2018-06-06 00:34:22 +08:00
|
|
|
int try_decide(vsock::_impl* _vp, int in_protocol)
|
|
|
|
{
|
|
|
|
if (is_protocol_decided)
|
|
|
|
{
|
|
|
|
if (in_protocol == protocol)
|
|
|
|
{
|
|
|
|
return GSOCK_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return GSOCK_MISMATCH_PROTOCOL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protocol = in_protocol;
|
|
|
|
|
|
|
|
// Try it
|
|
|
|
int ret = _make_decided(_vp);
|
|
|
|
if (ret == GSOCK_OK)
|
|
|
|
{
|
|
|
|
is_protocol_decided = true;
|
|
|
|
myliblog("Protocol decided to %s in udpsock with _vp %p \n", get_family_name(protocol), _vp);
|
|
|
|
}
|
2018-06-06 01:18:32 +08:00
|
|
|
|
2018-06-06 00:34:22 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
udpsock::udpsock(int use_family) : _pp(new _impl)
|
|
|
|
{
|
|
|
|
if (use_family == 1)
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
_pp->try_decide(_vp, AF_INET);
|
|
|
|
myliblog("Protocol decided to %s in udpsock %p\n", get_family_name(_pp->protocol), this);
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
else if (use_family == 2)
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
_pp->try_decide(_vp, AF_INET6);
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_pp->is_protocol_decided = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-03 10:28:04 +08:00
|
|
|
udpsock::~udpsock()
|
|
|
|
{
|
|
|
|
if (_pp)
|
|
|
|
{
|
|
|
|
delete _pp;
|
|
|
|
_pp = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
// 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;
|
|
|
|
|
2018-06-06 00:06:54 +08:00
|
|
|
_out_psockaddr = (sockaddr*)paddr6;
|
2018-06-02 13:47:28 +08:00
|
|
|
_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;
|
|
|
|
|
2018-06-06 00:06:54 +08:00
|
|
|
_out_psockaddr = (sockaddr*)paddr;
|
2018-06-02 13:47:28 +08:00
|
|
|
_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)
|
|
|
|
{
|
2018-06-06 08:42:54 +08:00
|
|
|
if (inet_ntop(AF_INET, &(((const sockaddr_in*)paddr)->sin_addr), buff, 128)!=NULL)
|
2018-06-02 13:47:28 +08:00
|
|
|
{
|
|
|
|
_out_IPStr = std::move(std::string(buff));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
else if (paddr->sa_family == AF_INET6)
|
|
|
|
{
|
2018-06-06 08:42:54 +08:00
|
|
|
if (inet_ntop(AF_INET6, &(((const sockaddr_in6*)paddr)->sin6_addr), buff, 128) != NULL)
|
2018-06-02 13:47:28 +08:00
|
|
|
{
|
|
|
|
_out_IPStr = std::move(std::string(buff));
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else return -1;
|
|
|
|
}
|
|
|
|
else return -2;
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
int udpsock::connect(const std::string& IPStr,int Port)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-05-05 15:37:50 +08:00
|
|
|
sockaddr_in saddr;
|
2018-06-02 13:47:28 +08:00
|
|
|
sockaddr_in6 saddr6;
|
|
|
|
sockaddr* paddr;
|
|
|
|
int addrsz;
|
|
|
|
|
|
|
|
int ret = convert_ipv46(IPStr, Port, paddr, addrsz, &saddr, &saddr6,
|
|
|
|
(_pp->is_protocol_decided) ? ((_pp->protocol == AF_INET) ? 0 : 1) : -1);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_INVALID_IP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
2018-06-06 00:34:22 +08:00
|
|
|
|
|
|
|
int cret = _pp->try_decide(_vp, (ret == 0) ? (AF_INET) : (AF_INET6));
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
return ::connect(_vp->sfd, (const sockaddr*)paddr, addrsz);
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
int udpsock::broadcast_at(int Port)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
sockaddr_in saddr;
|
|
|
|
memset(&saddr, 0, 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");
|
2018-06-06 01:04:41 +08:00
|
|
|
return GSOCK_BAD_PROTOCOL;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
2018-06-03 10:08:03 +08:00
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
2018-06-06 00:34:22 +08:00
|
|
|
|
|
|
|
return broadcast_at(Port);
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
2017-07-27 19:52:58 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
int udpsock::set_broadcast()
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
socklen_t opt = 1;
|
|
|
|
return ::setsockopt(_vp->sfd, SOL_SOCKET, SO_BROADCAST, (const char*)&opt, sizeof(opt));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
return set_broadcast();
|
|
|
|
}
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int udpsock::bind(int Port)
|
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
sockaddr_in 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
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
return bind(Port);
|
|
|
|
}
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int udpsock::sendto(const std::string& IPStr, int Port, const void* buffer, int length)
|
|
|
|
{
|
|
|
|
sockaddr_in saddr;
|
2018-06-02 13:47:28 +08:00
|
|
|
sockaddr_in6 saddr6;
|
|
|
|
sockaddr* paddr;
|
|
|
|
int addrsz;
|
|
|
|
|
|
|
|
int ret = convert_ipv46(IPStr, Port, paddr, addrsz, &saddr, &saddr6,
|
|
|
|
(_pp->is_protocol_decided) ? ((_pp->protocol == AF_INET) ? 0 : 1) : -1);
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
return GSOCK_INVALID_IP;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
return ::sendto(_vp->sfd, (const char*)buffer, length, 0, (const sockaddr*)paddr, addrsz);
|
2018-05-05 15:37:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int udpsock::broadcast(int Port,const void* buffer,int length)
|
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
if (_pp->protocol == AF_INET)
|
|
|
|
{
|
|
|
|
sockaddr_in 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");
|
2018-06-06 01:04:41 +08:00
|
|
|
return GSOCK_BAD_PROTOCOL;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
|
|
|
|
return broadcast(Port, buffer, length);
|
|
|
|
}
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
int udpsock::recvfrom(std::string& fromIP, int& fromPort, void* buffer, int bufferLength)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
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);
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
return GSOCK_API_ERROR; /// don't bother errno.
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
|
|
|
|
2018-06-03 10:08:03 +08:00
|
|
|
int cret = convertback_ipv46((const sockaddr*)&saddr, fromIP);
|
|
|
|
if (cret == -1)
|
|
|
|
{
|
|
|
|
return GSOCK_ERROR_NTOP;
|
|
|
|
}
|
|
|
|
else if (cret == -2)
|
|
|
|
{
|
|
|
|
return GSOCK_UNKNOWN_PROTOCOL;
|
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
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);
|
2018-04-23 15:56:05 +08:00
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
if (ret < 0)
|
|
|
|
{
|
|
|
|
return ret; /// don't bother errno.
|
|
|
|
}
|
|
|
|
|
2018-06-03 10:08:03 +08:00
|
|
|
int cret = convertback_ipv46((const sockaddr*)&saddr, fromIP);
|
|
|
|
if (cret == -1)
|
|
|
|
{
|
|
|
|
return GSOCK_ERROR_NTOP;
|
|
|
|
}
|
|
|
|
else if (cret == -2)
|
|
|
|
{
|
|
|
|
return GSOCK_UNKNOWN_PROTOCOL;
|
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
fromPort = ntohs(saddr.sin6_port);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-06 00:34:22 +08:00
|
|
|
int cret = _pp->try_decide(_vp, AF_INET);
|
|
|
|
if (cret < 0)
|
|
|
|
{
|
|
|
|
return cret;
|
|
|
|
}
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
return recvfrom(fromIP, fromPort, buffer, bufferLength);
|
|
|
|
}
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
2018-05-05 15:37:50 +08:00
|
|
|
int udpsock::send(const void* buffer,int length)
|
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
return ::send(_vp->sfd, (const char*)buffer, length, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
// if protocol is not decided, then socket is invalid. (Not Created)
|
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
2018-05-05 15:37:50 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int udpsock::recv(void* buffer,int bufferLength)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
if (_pp->is_protocol_decided)
|
|
|
|
{
|
|
|
|
return ::recv(_vp->sfd, (char*)buffer, bufferLength, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-06-03 10:08:03 +08:00
|
|
|
// same as udpsock::send
|
|
|
|
return GSOCK_INVALID_SOCKET;
|
2018-06-02 13:47:28 +08:00
|
|
|
}
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
2018-05-29 13:36:38 +08:00
|
|
|
// Select
|
|
|
|
struct selector::_impl
|
|
|
|
{
|
|
|
|
fd_set readset, writeset, errorset;
|
|
|
|
int readsz, writesz, errorsz;
|
|
|
|
};
|
|
|
|
|
|
|
|
selector::selector() : _pp(new _impl)
|
|
|
|
{
|
|
|
|
clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
selector::~selector()
|
|
|
|
{
|
|
|
|
if (_pp)
|
|
|
|
{
|
|
|
|
delete _pp;
|
|
|
|
_pp = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void selector::clear()
|
|
|
|
{
|
|
|
|
FD_ZERO(&_pp->readset);
|
|
|
|
FD_ZERO(&_pp->writeset);
|
|
|
|
FD_ZERO(&_pp->errorset);
|
|
|
|
_pp->readsz = _pp->writesz = _pp->errorsz = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void selector::add_read(const vsock& v)
|
|
|
|
{
|
|
|
|
if (v._vp->created)
|
|
|
|
{
|
|
|
|
FD_SET(v._vp->sfd, &_pp->readset);
|
|
|
|
++_pp->readsz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void selector::add_write(const vsock& v)
|
|
|
|
{
|
|
|
|
if (v._vp->created)
|
|
|
|
{
|
|
|
|
FD_SET(v._vp->sfd, &_pp->writeset);
|
|
|
|
++_pp->writesz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void selector::add_error(const vsock& v)
|
|
|
|
{
|
|
|
|
if (v._vp->created)
|
|
|
|
{
|
|
|
|
FD_SET(v._vp->sfd, &_pp->errorset);
|
|
|
|
++_pp->errorsz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int selector::wait_for(int second, int ms)
|
|
|
|
{
|
|
|
|
fd_set* pread = (_pp->readsz) ? (&_pp->readset) : NULL;
|
|
|
|
fd_set* pwrite = (_pp->writesz) ? (&_pp->writeset) : NULL;
|
|
|
|
fd_set* perr = (_pp->errorsz) ? (&_pp->errorset) : NULL;
|
|
|
|
|
|
|
|
if (!(pread || pwrite || perr))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct timeval tval;
|
|
|
|
tval.tv_sec = second;
|
|
|
|
tval.tv_usec = ms;
|
|
|
|
|
|
|
|
int ndfs = 0;
|
|
|
|
return ::select(ndfs, pread, pwrite, perr, &tval);
|
|
|
|
}
|
|
|
|
|
|
|
|
int selector::wait()
|
|
|
|
{
|
|
|
|
fd_set* pread = (_pp->readsz) ? (&_pp->readset) : NULL;
|
|
|
|
fd_set* pwrite = (_pp->writesz) ? (&_pp->writeset) : NULL;
|
|
|
|
fd_set* perr = (_pp->errorsz) ? (&_pp->errorset) : NULL;
|
|
|
|
|
|
|
|
if (!(pread || pwrite || perr))
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ndfs = 0;
|
|
|
|
return ::select(ndfs, pread, pwrite, perr, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool selector::can_read(const vsock& v)
|
|
|
|
{
|
|
|
|
return FD_ISSET(v._vp->sfd, &_pp->readset);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool selector::can_write(const vsock& v)
|
|
|
|
{
|
|
|
|
return FD_ISSET(v._vp->sfd, &_pp->writeset);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool selector::is_error(const vsock& v)
|
|
|
|
{
|
|
|
|
return FD_ISSET(v._vp->sfd, &_pp->errorset);
|
|
|
|
}
|
|
|
|
|
2018-07-05 01:56:22 +08:00
|
|
|
#ifdef WIN32 // Windows: IOCP. Coming soon...
|
|
|
|
|
|
|
|
#else // Linux: epoll
|
2018-08-26 00:19:17 +08:00
|
|
|
#include <functional>
|
|
|
|
|
|
|
|
epoll::epoll(int MaxListen) : _evec(MaxListen)
|
2018-07-05 01:56:22 +08:00
|
|
|
{
|
2018-08-26 00:19:17 +08:00
|
|
|
_fd = epoll_create(MaxListen); // this parameter is useless.
|
2018-07-05 01:56:22 +08:00
|
|
|
}
|
|
|
|
epoll::~epoll()
|
|
|
|
{
|
|
|
|
close(_fd);
|
|
|
|
}
|
2018-08-26 00:19:17 +08:00
|
|
|
int epoll::add(vsock& v, int event)
|
2018-07-05 01:56:22 +08:00
|
|
|
{
|
2018-07-05 02:14:50 +08:00
|
|
|
struct epoll_event ev;
|
2018-08-26 00:19:17 +08:00
|
|
|
ev.events = event;
|
|
|
|
ev.data.ptr = &v;
|
|
|
|
return epoll_ctl(_fd, EPOLL_CTL_ADD, v._vp->sfd, &ev);
|
2018-07-05 01:56:22 +08:00
|
|
|
}
|
2018-08-26 00:19:17 +08:00
|
|
|
int epoll::mod(vsock& v, int event)
|
2018-07-05 01:56:22 +08:00
|
|
|
{
|
2018-07-05 02:14:50 +08:00
|
|
|
struct epoll_event ev;
|
2018-08-26 00:19:17 +08:00
|
|
|
ev.events = event;
|
|
|
|
ev.data.ptr = &v;
|
|
|
|
return epoll_ctl(_fd, EPOLL_CTL_MOD, v._vp->sfd, &ev);
|
2018-07-05 01:56:22 +08:00
|
|
|
}
|
2018-08-26 00:19:17 +08:00
|
|
|
int epoll::del(vsock& v, int event)
|
2018-07-05 01:56:22 +08:00
|
|
|
{
|
2018-07-05 02:14:50 +08:00
|
|
|
struct epoll_event ev;
|
2018-08-26 00:19:17 +08:00
|
|
|
ev.events = event;
|
|
|
|
ev.data.ptr = &v;
|
|
|
|
return epoll_ctl(_fd, EPOLL_CTL_DEL, v._vp->sfd, &ev);
|
|
|
|
}
|
|
|
|
int epoll::wait(int timeout)
|
|
|
|
{
|
|
|
|
return _n = epoll_wait(_fd, _evec.data(), _evec.size(), timeout);
|
2018-07-05 01:56:22 +08:00
|
|
|
}
|
2018-08-26 00:19:17 +08:00
|
|
|
void epoll::handle(const std::function<void(vsock&, int)>& callback)
|
2018-07-05 01:56:22 +08:00
|
|
|
{
|
2018-08-26 00:19:17 +08:00
|
|
|
if (_n > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < _n; i++)
|
|
|
|
{
|
|
|
|
callback(*((vsock*)(_evec[i].data.ptr)), (int)(_evec[i].events));
|
|
|
|
}
|
|
|
|
}
|
2018-07-05 01:56:22 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2018-06-02 13:47:28 +08:00
|
|
|
int DNSResolve(const std::string& HostName, std::vector<std::string>& _out_IPStrVec)
|
2018-04-23 15:56:05 +08:00
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
std::vector<std::string> vec;
|
|
|
|
|
2018-04-23 15:56:05 +08:00
|
|
|
/// Use getaddrinfo instead
|
|
|
|
struct addrinfo hints;
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
|
|
hints.ai_protocol = IPPROTO_TCP;
|
|
|
|
|
|
|
|
struct addrinfo* result = nullptr;
|
|
|
|
|
|
|
|
int ret = getaddrinfo(HostName.c_str(), NULL, &hints, &result);
|
|
|
|
if (ret != 0)
|
|
|
|
{
|
2018-06-06 01:04:41 +08:00
|
|
|
return GSOCK_API_ERROR;/// API Call Failed.
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
|
|
|
|
int cnt = 0;
|
2018-04-23 15:56:05 +08:00
|
|
|
for (struct addrinfo* ptr = result; ptr != nullptr; ptr = ptr->ai_next)
|
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
cnt++;
|
2018-04-23 15:56:05 +08:00
|
|
|
switch (ptr->ai_family)
|
|
|
|
{
|
2018-06-02 13:47:28 +08:00
|
|
|
case AF_INET:
|
|
|
|
{
|
|
|
|
sockaddr_in * paddr = (struct sockaddr_in*) (ptr->ai_addr);
|
|
|
|
char ip_buff[64] = { 0 };
|
|
|
|
const char* ptr = inet_ntop(AF_INET, &(paddr->sin_addr), ip_buff, 64);
|
|
|
|
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
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
2018-06-02 13:47:28 +08:00
|
|
|
|
2018-04-27 13:25:32 +08:00
|
|
|
freeaddrinfo(result);
|
2018-06-02 13:47:28 +08:00
|
|
|
|
|
|
|
_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;
|
2018-04-23 15:56:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-08-15 09:54:10 +08:00
|
|
|
/// Undefine marcos
|
2018-06-06 01:18:32 +08:00
|
|
|
#undef myliblog_ex
|
2018-06-06 08:42:54 +08:00
|
|
|
#undef myliblog
|