src/socket.cpp
Namespaces
Name |
---|
std |
Functions
Name | |
---|---|
int64_t | socket_create(const addrinfo & hint) create a socket without error check |
uint32_t | socket_create(const addrinfo & hint, int64_t & sd) create 1 socket |
uint32_t | socket_bind(int64_t sd, const sockaddr_in & local) bind the socket to given address |
uint32_t | socket_bind(int64_t sd, const sockaddr_in6 & local) bind the socket to given address |
uint32_t | socket_listen(int64_t sd) start listening with the socket |
uint32_t | socket_connect(int64_t sd, const sockaddr_in & remote) try connect to given endpoint(IPv4) |
uint32_t | socket_connect(int64_t sd, const sockaddr_in6 & remote) try connect to given endpoint(IPv6) |
uint32_t | socket_accept(int64_t ln, int64_t & sd) accept a connection request and return client socket |
uint32_t | socket_get_name(int64_t sd, sockaddr_in & local) get the socket's address |
uint32_t | socket_get_name(int64_t sd, sockaddr_in6 & local) get the socket's address |
uint32_t | socket_get_peer(int64_t sd, sockaddr_in & remote) get connected peer's address |
uint32_t | socket_get_peer(int64_t sd, sockaddr_in6 & remote) get connected peer's address |
uint32_t | socket_set_option(int64_t sd, int64_t level, int64_t option, int64_t value) change the socket's option |
uint32_t | socket_set_option_reuse_address(int64_t sd) make socket to reuse address |
uint32_t | socket_set_option_nodelay(int64_t sd) make tcp send without delay |
uint32_t | socket_set_option_timout(int64_t sd, chrono::microseconds us, int64_t option) |
uint32_t | socket_set_option_timout(int64_t sd, uint32_t us, int64_t option) |
uint32_t | socket_set_option_send_timout(int64_t sd, uint32_t us) set the socket's send timeout |
uint32_t | socket_set_option_recv_timout(int64_t sd, uint32_t us) set the socket's recv timeout |
Functions Documentation
function socket_create
int64_t socket_create(
const addrinfo & hint
)
create a socket without error check
function socket_create
uint32_t socket_create(
const addrinfo & hint,
int64_t & sd
)
create 1 socket
Parameters:
- hint family, type, protocol
- sd reference to save the new socket
Return: error code from errno
or WSAGetLastError
function socket_bind
uint32_t socket_bind(
int64_t sd,
const sockaddr_in & local
)
bind the socket to given address
Parameters:
- sd socket to bind
- local IPv4 address
Return: error code from errno
or WSAGetLastError
function socket_bind
uint32_t socket_bind(
int64_t sd,
const sockaddr_in6 & local
)
bind the socket to given address
Parameters:
- sd socket to bind
- local IPv6 address
Return: error code from errno
or WSAGetLastError
function socket_listen
uint32_t socket_listen(
int64_t sd
)
start listening with the socket
Parameters:
- sd socket to start listen
Return: error code from errno
or WSAGetLastError
The backlog
value is fixed to 7.
function socket_connect
uint32_t socket_connect(
int64_t sd,
const sockaddr_in & remote
)
try connect to given endpoint(IPv4)
Parameters:
- sd socket to start connect
- remote IPv4 address
Return: error code from errno
or WSAGetLastError
function socket_connect
uint32_t socket_connect(
int64_t sd,
const sockaddr_in6 & remote
)
try connect to given endpoint(IPv6)
Parameters:
- sd socket to start connect
- remote IPv6 address
Return: error code from errno
or WSAGetLastError
function socket_accept
uint32_t socket_accept(
int64_t ln,
int64_t & sd
)
accept a connection request and return client socket
Parameters:
- ln listener socket
- sd reference to descriptor to save the new connected socket
Return: error code from errno
or WSAGetLastError
function socket_get_name
uint32_t socket_get_name(
int64_t sd,
sockaddr_in & local
)
get the socket's address
Parameters:
- sd socket to query the bound address
- local object to receive IPv4 address
Return: error code from errno
or WSAGetLastError
function socket_get_name
uint32_t socket_get_name(
int64_t sd,
sockaddr_in6 & local
)
get the socket's address
Parameters:
- sd socket to query the bound address
- local object to receive IPv6 address
Return: error code from errno
or WSAGetLastError
function socket_get_peer
uint32_t socket_get_peer(
int64_t sd,
sockaddr_in & remote
)
get connected peer's address
Parameters:
- sd socket to query the peer address
- remote object to receive IPv4 address
Return: error code from errno
or WSAGetLastError
function socket_get_peer
uint32_t socket_get_peer(
int64_t sd,
sockaddr_in6 & remote
)
get connected peer's address
Parameters:
- sd socket to query the peer address
- remote object to receive IPv6 address
Return: error code from errno
or WSAGetLastError
function socket_set_option
uint32_t socket_set_option(
int64_t sd,
int64_t level,
int64_t option,
int64_t value
)
change the socket's option
Parameters:
- sd
- level
- option
- value
Return: error code from errno
or WSAGetLastError
function socket_set_option_reuse_address
uint32_t socket_set_option_reuse_address(
int64_t sd
)
make socket to reuse address
Return: error code from errno
or WSAGetLastError
function socket_set_option_nodelay
uint32_t socket_set_option_nodelay(
int64_t sd
)
make tcp send without delay
Return: error code from errno
or WSAGetLastError
function socket_set_option_timout
uint32_t socket_set_option_timout(
int64_t sd,
chrono::microseconds us,
int64_t option
)
function socket_set_option_timout
uint32_t socket_set_option_timout(
int64_t sd,
uint32_t us,
int64_t option
)
function socket_set_option_send_timout
uint32_t socket_set_option_send_timout(
int64_t sd,
uint32_t us
)
set the socket's send timeout
Parameters:
- sd socket to change timeout
- us microsecond fot the duration
Return: error code from errno
or WSAGetLastError
function socket_set_option_recv_timout
uint32_t socket_set_option_recv_timout(
int64_t sd,
uint32_t us
)
set the socket's recv timeout
Parameters:
- sd socket to change timeout
- us microsecond fot the duration
Return: error code from errno
or WSAGetLastError
Source code
#include <cerrno>
#include <chrono>
#include <system_error>
#include "socket.hpp"
#if __has_include(<WinSock2.h>) // use winsock
#include <WS2tcpip.h>
#include <WinSock2.h>
#include <ws2def.h>
#elif __has_include(<netinet/in.h>) // use netinet
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#endif
using namespace std;
int64_t socket_create(const addrinfo& hint) noexcept {
return ::socket(hint.ai_family, //
hint.ai_socktype, hint.ai_protocol);
}
uint32_t socket_create(const addrinfo& hint, int64_t& sd) noexcept {
sd = socket_create(hint);
return sd < 0 ? socket_recent() : 0;
}
uint32_t socket_bind(int64_t sd, const sockaddr_in& local) noexcept {
if (::bind(sd, (const sockaddr*)&local, sizeof(sockaddr_in)))
return socket_recent();
return 0;
}
uint32_t socket_bind(int64_t sd, const sockaddr_in6& local) noexcept {
// bind socket and address
if (::bind(sd, (const sockaddr*)&local, sizeof(sockaddr_in6)))
return socket_recent();
return 0;
}
uint32_t socket_listen(int64_t sd) noexcept {
::listen(sd, 7);
return socket_recent();
}
uint32_t socket_connect(int64_t sd, const sockaddr_in& remote) noexcept {
auto* ptr = reinterpret_cast<const sockaddr*>(&remote);
if (::connect(sd, ptr, sizeof(sockaddr_in)) < 0)
return socket_recent();
return 0;
}
uint32_t socket_connect(int64_t sd, const sockaddr_in6& remote) noexcept {
auto* ptr = reinterpret_cast<const sockaddr*>(&remote);
if (::connect(sd, ptr, sizeof(sockaddr_in6)) < 0)
return socket_recent();
return 0;
}
uint32_t socket_accept(int64_t ln, int64_t& sd) noexcept {
sd = ::accept(ln, nullptr, nullptr);
return socket_recent();
}
uint32_t socket_get_name(int64_t sd, sockaddr_in& local) noexcept {
socklen_t len = sizeof(sockaddr_in);
if (::getsockname(sd, (sockaddr*)&local, &len))
return socket_recent();
return 0;
}
uint32_t socket_get_name(int64_t sd, sockaddr_in6& local) noexcept {
socklen_t len = sizeof(sockaddr_in6);
if (::getsockname(sd, (sockaddr*)&local, &len))
return socket_recent();
return 0;
}
uint32_t socket_get_peer(int64_t sd, sockaddr_in& local) noexcept {
socklen_t len = sizeof(sockaddr_in);
if (::getpeername(sd, (sockaddr*)&local, &len))
return socket_recent();
return 0;
}
uint32_t socket_get_peer(int64_t sd, sockaddr_in6& local) noexcept {
socklen_t len = sizeof(sockaddr_in6);
if (::getpeername(sd, (sockaddr*)&local, &len))
return socket_recent();
return 0;
}
uint32_t socket_set_option(int64_t sd, int64_t level, //
int64_t option, int64_t value) noexcept {
if (auto ec = ::setsockopt(sd, static_cast<int>(level), static_cast<int>(option), (char*)&value, sizeof(value)))
return socket_recent();
return 0;
}
uint32_t socket_set_option_reuse_address(int64_t sd) noexcept {
return socket_set_option(sd, SOL_SOCKET, SO_REUSEADDR, true);
}
uint32_t socket_set_option_nodelay(int64_t sd) noexcept {
return socket_set_option(sd, IPPROTO_TCP, TCP_NODELAY, true);
}
uint32_t socket_set_option_timout(int64_t sd, chrono::microseconds us, int64_t option) noexcept {
const auto s = chrono::duration_cast<chrono::seconds>(us);
us -= s;
timeval timeout{};
timeout.tv_sec = static_cast<decltype(timeout.tv_sec)>(s.count());
timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(us.count());
if (::setsockopt(sd, SOL_SOCKET, static_cast<int>(option), //
(char*)&timeout, sizeof(timeval)) != 0) {
return socket_recent();
}
return 0;
}
uint32_t socket_set_option_timout(int64_t sd, uint32_t us, int64_t option) noexcept {
return socket_set_option_timout(sd, chrono::microseconds{us}, option);
}
uint32_t socket_set_option_send_timout(int64_t sd, //
uint32_t us) noexcept {
return socket_set_option_timout(sd, chrono::microseconds{us}, SO_SNDTIMEO);
}
uint32_t socket_set_option_recv_timout(int64_t sd, //
uint32_t us) noexcept {
return socket_set_option_timout(sd, chrono::microseconds{us}, SO_RCVTIMEO);
}
#if __has_include(<WinSock2.h>) // using winsock
bool socket_is_valid(int64_t h) noexcept {
return h != INVALID_SOCKET;
}
WSADATA wsa_data{};
void socket_setup() noexcept(false) {
if (wsa_data.wVersion) // already initialized
return;
// init version 2.2
if (::WSAStartup(MAKEWORD(2, 2), &wsa_data)) {
auto errc = WSAGetLastError();
throw system_error{errc, system_category(), "WSAStartup"};
}
}
void socket_teardown() noexcept {
// not initialized or released
if (wsa_data.wVersion == 0)
return;
::WSACleanup();
wsa_data.wVersion = 0;
}
uint32_t socket_recent() noexcept {
return static_cast<uint32_t>(WSAGetLastError());
}
bool socket_would_block(int ec) noexcept {
return ec == WSAEWOULDBLOCK || ec == EWOULDBLOCK || ec == EINPROGRESS || ec == ERROR_IO_PENDING;
}
uint32_t socket_close(int64_t sd) noexcept {
return ::shutdown(sd, SD_BOTH), ::closesocket(sd);
}
uint32_t socket_set_option_nonblock(int64_t sd) noexcept {
u_long mode = TRUE;
return ::ioctlsocket(sd, FIONBIO, &mode);
}
#elif __has_include(<netinet/in.h>) // using netinet
bool socket_is_valid(int64_t h) noexcept {
return h > 0;
}
void socket_setup() noexcept(false) {
// do nothing for posix system. network operation already available
}
void socket_teardown() noexcept {
}
uint32_t socket_recent() noexcept {
return static_cast<uint32_t>(errno);
}
bool socket_would_block(int ec) noexcept {
return ec == EINPROGRESS;
}
uint32_t socket_close(int64_t sd) noexcept {
return shutdown(sd, SHUT_RDWR), close(sd), errno;
}
uint32_t socket_set_option_nonblock(int64_t sd) noexcept {
// make non-block/async
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
return errno;
return 0;
}
#endif
Updated on 2023-06-05 at 18:28:33 +0900