| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- #ifndef HV_SOCKET_H_
- #define HV_SOCKET_H_
- #include "hexport.h"
- #include "hplatform.h"
- #ifdef ENABLE_UDS
- #ifdef OS_WIN
- #include <afunix.h> // import struct sockaddr_un
- #else
- #include <sys/un.h> // import struct sockaddr_un
- #endif
- #endif
- #ifdef _MSC_VER
- #pragma comment(lib, "ws2_32.lib")
- #endif
- #define LOCALHOST "127.0.0.1"
- #define ANYADDR "0.0.0.0"
- BEGIN_EXTERN_C
- HV_INLINE int socket_errno() {
- #ifdef OS_WIN
- return WSAGetLastError();
- #else
- return errno;
- #endif
- }
- HV_EXPORT const char* socket_strerror(int err);
- #ifdef OS_WIN
- typedef SOCKET hsocket_t;
- typedef int socklen_t;
- void WSAInit();
- void WSADeinit();
- HV_INLINE int blocking(int sockfd) {
- unsigned long nb = 0;
- return ioctlsocket(sockfd, FIONBIO, &nb);
- }
- HV_INLINE int nonblocking(int sockfd) {
- unsigned long nb = 1;
- return ioctlsocket(sockfd, FIONBIO, &nb);
- }
- #undef EAGAIN
- #define EAGAIN WSAEWOULDBLOCK
- #undef EINPROGRESS
- #define EINPROGRESS WSAEINPROGRESS
- #undef EINTR
- #define EINTR WSAEINTR
- #undef ENOTSOCK
- #define ENOTSOCK WSAENOTSOCK
- #undef EMSGSIZE
- #define EMSGSIZE WSAEMSGSIZE
- #else
- typedef int hsocket_t;
- #ifndef SOCKET
- #define SOCKET int
- #endif
- #ifndef INVALID_SOCKET
- #define INVALID_SOCKET -1
- #endif
- HV_INLINE int blocking(int s) {
- return fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK);
- }
- HV_INLINE int nonblocking(int s) {
- return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
- }
- #ifndef closesocket
- HV_INLINE int closesocket(int sockfd) {
- return close(sockfd);
- }
- #endif
- #endif
- #ifndef SAFE_CLOSESOCKET
- #define SAFE_CLOSESOCKET(fd) do {if ((fd) >= 0) {closesocket(fd); (fd) = -1;}} while(0)
- #endif
- //-----------------------------sockaddr_u----------------------------------------------
- typedef union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
- #ifdef ENABLE_UDS
- struct sockaddr_un sun;
- #endif
- } sockaddr_u;
- HV_EXPORT bool is_ipv4(const char* host);
- HV_EXPORT bool is_ipv6(const char* host);
- HV_INLINE bool is_ipaddr(const char* host) {
- return is_ipv4(host) || is_ipv6(host);
- }
- // @param host: domain or ip
- // @retval 0:succeed
- HV_EXPORT int ResolveAddr(const char* host, sockaddr_u* addr);
- HV_EXPORT const char* sockaddr_ip(sockaddr_u* addr, char *ip, int len);
- HV_EXPORT uint16_t sockaddr_port(sockaddr_u* addr);
- HV_EXPORT int sockaddr_set_ip(sockaddr_u* addr, const char* host);
- HV_EXPORT void sockaddr_set_port(sockaddr_u* addr, int port);
- HV_EXPORT int sockaddr_set_ipport(sockaddr_u* addr, const char* host, int port);
- HV_EXPORT socklen_t sockaddr_len(sockaddr_u* addr);
- HV_EXPORT const char* sockaddr_str(sockaddr_u* addr, char* buf, int len);
- HV_EXPORT int sockaddr_compare(const sockaddr_u* addr1, const sockaddr_u* addr2);
- //#define INET_ADDRSTRLEN 16
- //#define INET6_ADDRSTRLEN 46
- #ifdef ENABLE_UDS
- #define SOCKADDR_STRLEN sizeof(((struct sockaddr_un*)(NULL))->sun_path)
- HV_INLINE void sockaddr_set_path(sockaddr_u* addr, const char* path) {
- addr->sa.sa_family = AF_UNIX;
- strncpy(addr->sun.sun_path, path, sizeof(addr->sun.sun_path));
- }
- #else
- #define SOCKADDR_STRLEN 64 // ipv4:port | [ipv6]:port
- #endif
- HV_INLINE void sockaddr_print(sockaddr_u* addr) {
- char buf[SOCKADDR_STRLEN] = {0};
- sockaddr_str(addr, buf, sizeof(buf));
- puts(buf);
- }
- #define SOCKADDR_LEN(addr) sockaddr_len((sockaddr_u*)addr)
- #define SOCKADDR_STR(addr, buf) sockaddr_str((sockaddr_u*)addr, buf, sizeof(buf))
- #define SOCKADDR_PRINT(addr) sockaddr_print((sockaddr_u*)addr)
- //=====================================================================================
- // socket -> setsockopt -> bind
- // @param type: SOCK_STREAM(tcp) SOCK_DGRAM(udp)
- // @return sockfd
- HV_EXPORT int Bind(int port, const char* host DEFAULT(ANYADDR), int type DEFAULT(SOCK_STREAM));
- // Bind -> listen
- // @return listenfd
- HV_EXPORT int Listen(int port, const char* host DEFAULT(ANYADDR));
- // @return connfd
- // ResolveAddr -> socket -> nonblocking -> connect
- HV_EXPORT int Connect(const char* host, int port, int nonblock DEFAULT(0));
- // Connect(host, port, 1)
- HV_EXPORT int ConnectNonblock(const char* host, int port);
- // Connect(host, port, 1) -> select -> blocking
- #define DEFAULT_CONNECT_TIMEOUT 10000 // ms
- HV_EXPORT int ConnectTimeout(const char* host, int port, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
- #ifdef ENABLE_UDS
- HV_EXPORT int BindUnix(const char* path, int type DEFAULT(SOCK_STREAM));
- HV_EXPORT int ListenUnix(const char* path);
- HV_EXPORT int ConnectUnix(const char* path, int nonblock DEFAULT(0));
- HV_EXPORT int ConnectUnixNonblock(const char* path);
- HV_EXPORT int ConnectUnixTimeout(const char* path, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
- #endif
- // Just implement Socketpair(AF_INET, SOCK_STREAM, 0, sv);
- HV_EXPORT int Socketpair(int family, int type, int protocol, int sv[2]);
- HV_INLINE int tcp_nodelay(int sockfd, int on DEFAULT(1)) {
- return setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(int));
- }
- HV_INLINE int tcp_nopush(int sockfd, int on DEFAULT(1)) {
- #ifdef TCP_NOPUSH
- return setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, (const char*)&on, sizeof(int));
- #elif defined(TCP_CORK)
- return setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (const char*)&on, sizeof(int));
- #else
- return 0;
- #endif
- }
- HV_INLINE int tcp_keepalive(int sockfd, int on DEFAULT(1), int delay DEFAULT(60)) {
- if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(int)) != 0) {
- return socket_errno();
- }
- #ifdef TCP_KEEPALIVE
- return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, (const char*)&delay, sizeof(int));
- #elif defined(TCP_KEEPIDLE)
- // TCP_KEEPIDLE => tcp_keepalive_time
- // TCP_KEEPCNT => tcp_keepalive_probes
- // TCP_KEEPINTVL => tcp_keepalive_intvl
- return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (const char*)&delay, sizeof(int));
- #else
- return 0;
- #endif
- }
- HV_INLINE int udp_broadcast(int sockfd, int on DEFAULT(1)) {
- return setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof(int));
- }
- HV_INLINE int ip_v6only(int sockfd, int on DEFAULT(1)) {
- #ifdef IPV6_V6ONLY
- return setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(int));
- #else
- return 0;
- #endif
- }
- // send timeout
- HV_INLINE int so_sndtimeo(int sockfd, int timeout) {
- #ifdef OS_WIN
- return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
- #else
- struct timeval tv = {timeout/1000, (timeout%1000)*1000};
- return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
- #endif
- }
- // recv timeout
- HV_INLINE int so_rcvtimeo(int sockfd, int timeout) {
- #ifdef OS_WIN
- return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int));
- #else
- struct timeval tv = {timeout/1000, (timeout%1000)*1000};
- return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
- #endif
- }
- // send buffer size
- HV_INLINE int so_sndbuf(int sockfd, int len) {
- return setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&len, sizeof(int));
- }
- // recv buffer size
- HV_INLINE int so_rcvbuf(int sockfd, int len) {
- return setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&len, sizeof(int));
- }
- HV_INLINE int so_reuseaddr(int sockfd, int on DEFAULT(1)) {
- #ifdef SO_REUSEADDR
- // NOTE: SO_REUSEADDR allow to reuse sockaddr of TIME_WAIT status
- return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int));
- #else
- return 0;
- #endif
- }
- HV_INLINE int so_reuseport(int sockfd, int on DEFAULT(1)) {
- #ifdef SO_REUSEPORT
- // NOTE: SO_REUSEPORT allow multiple sockets to bind same port
- return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&on, sizeof(int));
- #else
- return 0;
- #endif
- }
- HV_INLINE int so_linger(int sockfd, int timeout DEFAULT(1)) {
- #ifdef SO_LINGER
- struct linger linger;
- if (timeout >= 0) {
- linger.l_onoff = 1;
- linger.l_linger = timeout;
- } else {
- linger.l_onoff = 0;
- linger.l_linger = 0;
- }
- // NOTE: SO_LINGER change the default behavior of close, send RST, avoid TIME_WAIT
- return setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger));
- #else
- return 0;
- #endif
- }
- END_EXTERN_C
- #endif // HV_SOCKET_H_
|