1
0

hsocket.h 7.8 KB

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