hsocket.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include "hsocket.h"
  2. static inline int socket_errno_negative() {
  3. int err = socket_errno();
  4. return err > 0 ? -err : -1;
  5. }
  6. const char* socket_strerror(int err) {
  7. #ifdef OS_WIN
  8. static char buffer[128];
  9. FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  10. FORMAT_MESSAGE_IGNORE_INSERTS |
  11. FORMAT_MESSAGE_MAX_WIDTH_MASK,
  12. 0, ABS(err), 0, buffer, sizeof(buffer), NULL);
  13. return buffer;
  14. #else
  15. return strerror(ABS(err));
  16. #endif
  17. }
  18. int Resolver(const char* host, sockaddr_u* addr) {
  19. if (inet_pton(AF_INET, host, &addr->sin.sin_addr) == 1) {
  20. addr->sa.sa_family = AF_INET; // host is ipv4, so easy ;)
  21. return 0;
  22. }
  23. #ifdef ENABLE_IPV6
  24. if (inet_pton(AF_INET6, host, &addr->sin6.sin6_addr) == 1) {
  25. addr->sa.sa_family = AF_INET6; // host is ipv6
  26. return 0;
  27. }
  28. struct addrinfo* ais = NULL;
  29. struct addrinfo hint;
  30. hint.ai_flags = 0;
  31. hint.ai_family = AF_UNSPEC;
  32. hint.ai_socktype = 0;
  33. hint.ai_protocol = 0;
  34. int ret = getaddrinfo(host, NULL, NULL, &ais);
  35. if (ret != 0 || ais == NULL || ais->ai_addrlen == 0 || ais->ai_addr == NULL) {
  36. printd("unknown host: %s err:%d:%s\n", host, ret, gai_strerror(ret));
  37. return ret;
  38. }
  39. memcpy(addr, ais->ai_addr, ais->ai_addrlen);
  40. freeaddrinfo(ais);
  41. #else
  42. struct hostent* phe = gethostbyname(host);
  43. if (phe == NULL) {
  44. printd("unknown host %s err:%d\n", host, h_errno);
  45. return -h_errno;
  46. }
  47. addr->sin.sin_family = AF_INET;
  48. memcpy(&addr->sin.sin_addr, phe->h_addr_list[0], phe->h_length);
  49. #endif
  50. return 0;
  51. }
  52. static int sockaddr_bind(sockaddr_u* localaddr, int type) {
  53. // socket -> setsockopt -> bind
  54. int sockfd = socket(localaddr->sa.sa_family, type, 0);
  55. if (sockfd < 0) {
  56. perror("socket");
  57. return socket_errno_negative();
  58. }
  59. // NOTE: SO_REUSEADDR means that you can reuse sockaddr of TIME_WAIT status
  60. int reuseaddr = 1;
  61. if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuseaddr, sizeof(int)) < 0) {
  62. perror("setsockopt");
  63. goto error;
  64. }
  65. if (bind(sockfd, &localaddr->sa, sockaddr_len(localaddr)) < 0) {
  66. perror("bind");
  67. goto error;
  68. }
  69. return sockfd;
  70. error:
  71. closesocket(sockfd);
  72. return socket_errno_negative();
  73. }
  74. static int sockaddr_connect(sockaddr_u* peeraddr, int nonblock) {
  75. // socket -> nonblocking -> connect
  76. int connfd = socket(peeraddr->sa.sa_family, SOCK_STREAM, 0);
  77. if (connfd < 0) {
  78. perror("socket");
  79. return socket_errno_negative();
  80. }
  81. if (nonblock) {
  82. nonblocking(connfd);
  83. }
  84. int ret = connect(connfd, &peeraddr->sa, sockaddr_len(peeraddr));
  85. #ifdef OS_WIN
  86. if (ret < 0 && socket_errno() != WSAEWOULDBLOCK) {
  87. #else
  88. if (ret < 0 && socket_errno() != EINPROGRESS) {
  89. #endif
  90. perror("connect");
  91. closesocket(connfd);
  92. return socket_errno_negative();
  93. }
  94. return connfd;
  95. }
  96. static int ListenFD(int sockfd) {
  97. if (sockfd < 0) return sockfd;
  98. if (listen(sockfd, SOMAXCONN) < 0) {
  99. perror("listen");
  100. closesocket(sockfd);
  101. return socket_errno_negative();
  102. }
  103. return sockfd;
  104. }
  105. static int ConnectFDTimeout(int connfd, int ms) {
  106. int err;
  107. socklen_t optlen = sizeof(err);
  108. struct timeval tv = { ms / 1000, (ms % 1000) * 1000 };
  109. fd_set writefds;
  110. FD_ZERO(&writefds);
  111. FD_SET(connfd, &writefds);
  112. int ret = select(connfd+1, 0, &writefds, 0, &tv);
  113. if (ret < 0) {
  114. perror("select");
  115. goto error;
  116. }
  117. if (ret == 0) {
  118. errno = ETIMEDOUT;
  119. goto error;
  120. }
  121. if (getsockopt(connfd, SOL_SOCKET, SO_ERROR, (char*)&err, &optlen) < 0 || err != 0) {
  122. goto error;
  123. }
  124. blocking(connfd);
  125. return connfd;
  126. error:
  127. closesocket(connfd);
  128. return socket_errno_negative();
  129. }
  130. int Bind(int port, const char* host, int type) {
  131. #ifdef OS_WIN
  132. static int s_wsa_initialized = 0;
  133. if (s_wsa_initialized == 0) {
  134. s_wsa_initialized = 1;
  135. WSADATA wsadata;
  136. WSAStartup(MAKEWORD(2,2), &wsadata);
  137. }
  138. #endif
  139. sockaddr_u localaddr;
  140. memset(&localaddr, 0, sizeof(localaddr));
  141. int ret = sockaddr_set_ipport(&localaddr, host, port);
  142. if (ret != 0) {
  143. return NABS(ret);
  144. }
  145. return sockaddr_bind(&localaddr, type);
  146. }
  147. int Listen(int port, const char* host) {
  148. int sockfd = Bind(port, host, SOCK_STREAM);
  149. if (sockfd < 0) return sockfd;
  150. return ListenFD(sockfd);
  151. }
  152. int Connect(const char* host, int port, int nonblock) {
  153. sockaddr_u peeraddr;
  154. memset(&peeraddr, 0, sizeof(peeraddr));
  155. int ret = sockaddr_set_ipport(&peeraddr, host, port);
  156. if (ret != 0) {
  157. return NABS(ret);
  158. }
  159. return sockaddr_connect(&peeraddr, nonblock);
  160. }
  161. int ConnectNonblock(const char* host, int port) {
  162. return Connect(host, port, 1);
  163. }
  164. int ConnectTimeout(const char* host, int port, int ms) {
  165. int connfd = Connect(host, port, 1);
  166. if (connfd < 0) return connfd;
  167. return ConnectFDTimeout(connfd, ms);
  168. }
  169. #ifdef ENABLE_UDS
  170. int BindUnix(const char* path, int type) {
  171. sockaddr_u localaddr;
  172. memset(&localaddr, 0, sizeof(localaddr));
  173. sockaddr_set_path(&localaddr, path);
  174. return sockaddr_bind(&localaddr, type);
  175. }
  176. int ListenUnix(const char* path) {
  177. int sockfd = BindUnix(path, SOCK_STREAM);
  178. if (sockfd < 0) return sockfd;
  179. return ListenFD(sockfd);
  180. }
  181. int ConnectUnix(const char* path, int nonblock) {
  182. sockaddr_u peeraddr;
  183. memset(&peeraddr, 0, sizeof(peeraddr));
  184. sockaddr_set_path(&peeraddr, path);
  185. return sockaddr_connect(&peeraddr, nonblock);
  186. }
  187. int ConnectUnixNonblock(const char* path) {
  188. return ConnectUnix(path, 1);
  189. }
  190. int ConnectUnixTimeout(const char* path, int ms) {
  191. int connfd = ConnectUnix(path, 1);
  192. if (connfd < 0) return connfd;
  193. return ConnectFDTimeout(connfd, ms);
  194. }
  195. #endif
  196. int Socketpair(int family, int type, int protocol, int sv[2]) {
  197. #ifdef OS_UNIX
  198. if (family == AF_UNIX) {
  199. return socketpair(family, type, protocol, sv);
  200. }
  201. #endif
  202. if (family != AF_INET || type != SOCK_STREAM) {
  203. return -1;
  204. }
  205. int listenfd, connfd, acceptfd;
  206. listenfd = connfd = acceptfd = INVALID_SOCKET;
  207. struct sockaddr_in localaddr;
  208. socklen_t addrlen = sizeof(localaddr);
  209. memset(&localaddr, 0, addrlen);
  210. localaddr.sin_family = AF_INET;
  211. localaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  212. localaddr.sin_port = 0;
  213. // listener
  214. listenfd = socket(AF_INET, SOCK_STREAM, 0);
  215. if (listenfd < 0) {
  216. perror("socket");
  217. goto error;
  218. }
  219. if (bind(listenfd, (struct sockaddr*)&localaddr, addrlen) < 0) {
  220. perror("bind");
  221. goto error;
  222. }
  223. if (listen(listenfd, 1) < 0) {
  224. perror("listen");
  225. goto error;
  226. }
  227. if (getsockname(listenfd, (struct sockaddr*)&localaddr, &addrlen) < 0) {
  228. perror("getsockname");
  229. goto error;
  230. }
  231. // connector
  232. connfd = socket(AF_INET, SOCK_STREAM, 0);
  233. if (connfd < 0) {
  234. perror("socket");
  235. goto error;
  236. }
  237. if (connect(connfd, (struct sockaddr*)&localaddr, addrlen) < 0) {
  238. perror("connect");
  239. goto error;
  240. }
  241. // acceptor
  242. acceptfd = accept(listenfd, (struct sockaddr*)&localaddr, &addrlen);
  243. if (acceptfd < 0) {
  244. perror("accept");
  245. goto error;
  246. }
  247. closesocket(listenfd);
  248. sv[0] = connfd;
  249. sv[1] = acceptfd;
  250. return 0;
  251. error:
  252. if (listenfd != INVALID_SOCKET) {
  253. closesocket(listenfd);
  254. }
  255. if (connfd != INVALID_SOCKET) {
  256. closesocket(connfd);
  257. }
  258. if (acceptfd != INVALID_SOCKET) {
  259. closesocket(acceptfd);
  260. }
  261. return -1;
  262. }