hsocket.h 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. #ifndef HV_SOCKET_H_
  2. #define HV_SOCKET_H_
  3. #include "hexport.h"
  4. #include "hplatform.h"
  5. #ifdef ENABLE_UDS
  6. #ifdef OS_WIN
  7. #include <afunix.h> // import struct sockaddr_un
  8. #else
  9. #include <sys/un.h> // import struct sockaddr_un
  10. #endif
  11. #endif
  12. #ifdef _MSC_VER
  13. #pragma comment(lib, "ws2_32.lib")
  14. #endif
  15. #define LOCALHOST "127.0.0.1"
  16. #define ANYADDR "0.0.0.0"
  17. BEGIN_EXTERN_C
  18. HV_INLINE int socket_errno() {
  19. #ifdef OS_WIN
  20. return WSAGetLastError();
  21. #else
  22. return errno;
  23. #endif
  24. }
  25. HV_EXPORT const char* socket_strerror(int err);
  26. #ifdef OS_WIN
  27. typedef SOCKET hsocket_t;
  28. typedef int socklen_t;
  29. void WSAInit();
  30. void WSADeinit();
  31. HV_INLINE int blocking(int sockfd) {
  32. unsigned long nb = 0;
  33. return ioctlsocket(sockfd, FIONBIO, &nb);
  34. }
  35. HV_INLINE int nonblocking(int sockfd) {
  36. unsigned long nb = 1;
  37. return ioctlsocket(sockfd, FIONBIO, &nb);
  38. }
  39. #undef EAGAIN
  40. #define EAGAIN WSAEWOULDBLOCK
  41. #undef EINPROGRESS
  42. #define EINPROGRESS WSAEINPROGRESS
  43. #undef EINTR
  44. #define EINTR WSAEINTR
  45. #undef ENOTSOCK
  46. #define ENOTSOCK WSAENOTSOCK
  47. #undef EMSGSIZE
  48. #define EMSGSIZE WSAEMSGSIZE
  49. #else
  50. typedef int hsocket_t;
  51. #ifndef SOCKET
  52. #define SOCKET int
  53. #endif
  54. #ifndef INVALID_SOCKET
  55. #define INVALID_SOCKET -1
  56. #endif
  57. HV_INLINE int blocking(int s) {
  58. return fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK);
  59. }
  60. HV_INLINE int nonblocking(int s) {
  61. return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
  62. }
  63. #ifndef closesocket
  64. HV_INLINE int closesocket(int sockfd) {
  65. return close(sockfd);
  66. }
  67. #endif
  68. #endif
  69. #ifndef SAFE_CLOSESOCKET
  70. #define SAFE_CLOSESOCKET(fd) do {if ((fd) >= 0) {closesocket(fd); (fd) = -1;}} while(0)
  71. #endif
  72. //-----------------------------sockaddr_u----------------------------------------------
  73. typedef union {
  74. struct sockaddr sa;
  75. struct sockaddr_in sin;
  76. struct sockaddr_in6 sin6;
  77. #ifdef ENABLE_UDS
  78. struct sockaddr_un sun;
  79. #endif
  80. } sockaddr_u;
  81. HV_EXPORT bool is_ipv4(const char* host);
  82. HV_EXPORT bool is_ipv6(const char* host);
  83. HV_INLINE bool is_ipaddr(const char* host) {
  84. return is_ipv4(host) || is_ipv6(host);
  85. }
  86. // @param host: domain or ip
  87. // @retval 0:succeed
  88. HV_EXPORT int ResolveAddr(const char* host, sockaddr_u* addr);
  89. HV_EXPORT const char* sockaddr_ip(sockaddr_u* addr, char *ip, int len);
  90. HV_EXPORT uint16_t sockaddr_port(sockaddr_u* addr);
  91. HV_EXPORT int sockaddr_set_ip(sockaddr_u* addr, const char* host);
  92. HV_EXPORT void sockaddr_set_port(sockaddr_u* addr, int port);
  93. HV_EXPORT int sockaddr_set_ipport(sockaddr_u* addr, const char* host, int port);
  94. HV_EXPORT socklen_t sockaddr_len(sockaddr_u* addr);
  95. HV_EXPORT const char* sockaddr_str(sockaddr_u* addr, char* buf, int len);
  96. HV_EXPORT int sockaddr_compare(const sockaddr_u* addr1, const sockaddr_u* addr2);
  97. //#define INET_ADDRSTRLEN 16
  98. //#define INET6_ADDRSTRLEN 46
  99. #ifdef ENABLE_UDS
  100. #define SOCKADDR_STRLEN sizeof(((struct sockaddr_un*)(NULL))->sun_path)
  101. HV_INLINE void sockaddr_set_path(sockaddr_u* addr, const char* path) {
  102. addr->sa.sa_family = AF_UNIX;
  103. strncpy(addr->sun.sun_path, path, sizeof(addr->sun.sun_path));
  104. }
  105. #else
  106. #define SOCKADDR_STRLEN 64 // ipv4:port | [ipv6]:port
  107. #endif
  108. HV_INLINE void sockaddr_print(sockaddr_u* addr) {
  109. char buf[SOCKADDR_STRLEN] = {0};
  110. sockaddr_str(addr, buf, sizeof(buf));
  111. puts(buf);
  112. }
  113. #define SOCKADDR_LEN(addr) sockaddr_len((sockaddr_u*)addr)
  114. #define SOCKADDR_STR(addr, buf) sockaddr_str((sockaddr_u*)addr, buf, sizeof(buf))
  115. #define SOCKADDR_PRINT(addr) sockaddr_print((sockaddr_u*)addr)
  116. //=====================================================================================
  117. // socket -> setsockopt -> bind
  118. // @param type: SOCK_STREAM(tcp) SOCK_DGRAM(udp)
  119. // @return sockfd
  120. HV_EXPORT int Bind(int port, const char* host DEFAULT(ANYADDR), int type DEFAULT(SOCK_STREAM));
  121. // Bind -> listen
  122. // @return listenfd
  123. HV_EXPORT int Listen(int port, const char* host DEFAULT(ANYADDR));
  124. // @return connfd
  125. // ResolveAddr -> socket -> nonblocking -> connect
  126. HV_EXPORT int Connect(const char* host, int port, int nonblock DEFAULT(0));
  127. // Connect(host, port, 1)
  128. HV_EXPORT int ConnectNonblock(const char* host, int port);
  129. // Connect(host, port, 1) -> select -> blocking
  130. #define DEFAULT_CONNECT_TIMEOUT 10000 // ms
  131. HV_EXPORT int ConnectTimeout(const char* host, int port, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
  132. #ifdef ENABLE_UDS
  133. HV_EXPORT int BindUnix(const char* path, int type DEFAULT(SOCK_STREAM));
  134. HV_EXPORT int ListenUnix(const char* path);
  135. HV_EXPORT int ConnectUnix(const char* path, int nonblock DEFAULT(0));
  136. HV_EXPORT int ConnectUnixNonblock(const char* path);
  137. HV_EXPORT int ConnectUnixTimeout(const char* path, int ms DEFAULT(DEFAULT_CONNECT_TIMEOUT));
  138. #endif
  139. // Just implement Socketpair(AF_INET, SOCK_STREAM, 0, sv);
  140. HV_EXPORT int Socketpair(int family, int type, int protocol, int sv[2]);
  141. HV_INLINE int tcp_nodelay(int sockfd, int on DEFAULT(1)) {
  142. return setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (const char*)&on, sizeof(int));
  143. }
  144. HV_INLINE int tcp_nopush(int sockfd, int on DEFAULT(1)) {
  145. #ifdef TCP_NOPUSH
  146. return setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, (const char*)&on, sizeof(int));
  147. #elif defined(TCP_CORK)
  148. return setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (const char*)&on, sizeof(int));
  149. #else
  150. return 0;
  151. #endif
  152. }
  153. HV_INLINE int tcp_keepalive(int sockfd, int on DEFAULT(1), int delay DEFAULT(60)) {
  154. if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&on, sizeof(int)) != 0) {
  155. return socket_errno();
  156. }
  157. #ifdef TCP_KEEPALIVE
  158. return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE, (const char*)&delay, sizeof(int));
  159. #elif defined(TCP_KEEPIDLE)
  160. // TCP_KEEPIDLE => tcp_keepalive_time
  161. // TCP_KEEPCNT => tcp_keepalive_probes
  162. // TCP_KEEPINTVL => tcp_keepalive_intvl
  163. return setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, (const char*)&delay, sizeof(int));
  164. #else
  165. return 0;
  166. #endif
  167. }
  168. HV_INLINE int udp_broadcast(int sockfd, int on DEFAULT(1)) {
  169. return setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof(int));
  170. }
  171. HV_INLINE int ip_v6only(int sockfd, int on DEFAULT(1)) {
  172. #ifdef IPV6_V6ONLY
  173. return setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char*)&on, sizeof(int));
  174. #else
  175. return 0;
  176. #endif
  177. }
  178. // send timeout
  179. HV_INLINE int so_sndtimeo(int sockfd, int timeout) {
  180. #ifdef OS_WIN
  181. return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (const char*)&timeout, sizeof(int));
  182. #else
  183. struct timeval tv = {timeout/1000, (timeout%1000)*1000};
  184. return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));
  185. #endif
  186. }
  187. // recv timeout
  188. HV_INLINE int so_rcvtimeo(int sockfd, int timeout) {
  189. #ifdef OS_WIN
  190. return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(int));
  191. #else
  192. struct timeval tv = {timeout/1000, (timeout%1000)*1000};
  193. return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
  194. #endif
  195. }
  196. // send buffer size
  197. HV_INLINE int so_sndbuf(int sockfd, int len) {
  198. return setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char*)&len, sizeof(int));
  199. }
  200. // recv buffer size
  201. HV_INLINE int so_rcvbuf(int sockfd, int len) {
  202. return setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (const char*)&len, sizeof(int));
  203. }
  204. HV_INLINE int so_reuseaddr(int sockfd, int on DEFAULT(1)) {
  205. #ifdef SO_REUSEADDR
  206. // NOTE: SO_REUSEADDR allow to reuse sockaddr of TIME_WAIT status
  207. return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(int));
  208. #else
  209. return 0;
  210. #endif
  211. }
  212. HV_INLINE int so_reuseport(int sockfd, int on DEFAULT(1)) {
  213. #ifdef SO_REUSEPORT
  214. // NOTE: SO_REUSEPORT allow multiple sockets to bind same port
  215. return setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, (const char*)&on, sizeof(int));
  216. #else
  217. return 0;
  218. #endif
  219. }
  220. HV_INLINE int so_linger(int sockfd, int timeout DEFAULT(1)) {
  221. #ifdef SO_LINGER
  222. struct linger linger;
  223. if (timeout >= 0) {
  224. linger.l_onoff = 1;
  225. linger.l_linger = timeout;
  226. } else {
  227. linger.l_onoff = 0;
  228. linger.l_linger = 0;
  229. }
  230. // NOTE: SO_LINGER change the default behavior of close, send RST, avoid TIME_WAIT
  231. return setsockopt(sockfd, SOL_SOCKET, SO_LINGER, (const char*)&linger, sizeof(linger));
  232. #else
  233. return 0;
  234. #endif
  235. }
  236. END_EXTERN_C
  237. #endif // HV_SOCKET_H_