cs_tcp.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /**
  2. * cs_tcp.h
  3. * Copyright (c) 2007-2018 ls
  4. **/
  5. #include "../inc/cs.h"
  6. #include "../inc/cs_str.h"
  7. #include "../inc/cs_tcp.h"
  8. #ifdef _WIN32
  9. #pragma comment(lib,"ws2_32.lib")
  10. //#define EINPROGRESS WSAEWOULDBLOCK
  11. CS_API int cs_tcp_init() {
  12. WSADATA wsaData;
  13. WSAStartup(MAKEWORD(2, 2), &wsaData);
  14. return (CS_OK);
  15. }
  16. CS_API void cs_tcp_cleanup() {
  17. WSACleanup();
  18. }
  19. #endif
  20. static int cs_tcp_v6_only(cs_sock_t s) {
  21. int yes = 1;
  22. if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) == -1) {
  23. cs_tcp_close(s);
  24. return (CS_ERR);
  25. }
  26. return (CS_OK);
  27. }
  28. static int cs_tcp_reuseaddr(cs_sock_t fd) {
  29. int yes = 1;
  30. /* Make sure connection-intensive things like the redis benckmark
  31. * will be able to close/open sockets a zillion of times */
  32. if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) == -1) {
  33. // cs_strerror(err, "setsockopt SO_REUSEADDR: %s", strerror(errno));
  34. return (CS_ERR);
  35. }
  36. return (CS_OK);
  37. }
  38. static int _cs_tcp_listen(
  39. cs_sock_t s, struct sockaddr *sa, socklen_t len, int backlog) {
  40. if (bind(s,sa,len) == -1) {
  41. // cs_strerror(err, "bind: %s", strerror(errno));
  42. cs_tcp_close(s);
  43. return (CS_ERR);
  44. }
  45. if (listen(s, backlog) == -1) {
  46. // cs_strerror(err, "listen: %s", strerror(errno));
  47. cs_tcp_close(s);
  48. return (CS_ERR);
  49. }
  50. return (CS_OK);
  51. }
  52. static cs_sock_t _cs_tcp_server(
  53. int port, char *bindaddr, int af, int backlog) {
  54. cs_sock_t s = -1;
  55. int rv;
  56. char _port[6]; /* strlen("65535") */
  57. struct addrinfo hints, *servinfo, *p;
  58. #ifdef _WIN32
  59. sprintf_s(_port, 6, "%d", port);
  60. #else
  61. snprintf(_port, 6, "%d", port);
  62. #endif
  63. cs_bzero(&hints, sizeof(hints));
  64. hints.ai_family = af;
  65. hints.ai_socktype = SOCK_STREAM;
  66. hints.ai_flags = AI_PASSIVE; /* No effect if bindaddr != NULL */
  67. if ((rv = getaddrinfo(bindaddr, _port, &hints, &servinfo)) != 0) {
  68. // cs_strerror(err, "%s", gai_strerror(rv));
  69. return (CS_ERR);
  70. }
  71. for (p = servinfo; p != NULL; p = p->ai_next) {
  72. #ifdef _WIN32
  73. if ((s = WSASocket(
  74. p->ai_family,
  75. p->ai_socktype,
  76. p->ai_protocol,
  77. NULL,
  78. 0,
  79. WSA_FLAG_OVERLAPPED)) == -1) {
  80. continue;
  81. }
  82. #else
  83. if ((s = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
  84. continue;
  85. }
  86. #endif
  87. if (af == AF_INET6 && cs_tcp_v6_only(s) == CS_ERR) {
  88. goto error;
  89. }
  90. if (cs_tcp_reuseaddr(s) == CS_ERR) {
  91. goto error;
  92. }
  93. if (_cs_tcp_listen(s, p->ai_addr, p->ai_addrlen, backlog) == CS_ERR) {
  94. goto error;
  95. }
  96. goto end;
  97. }
  98. if (p == NULL) {
  99. // cs_strerror(err, "unable to bind socket, errno: %d", errno);
  100. goto error;
  101. }
  102. error:
  103. if (s != -1) {
  104. cs_tcp_close(s);
  105. }
  106. s = CS_ERR;
  107. end:
  108. freeaddrinfo(servinfo);
  109. return (s);
  110. }
  111. /*
  112. static cs_sock_t cs_tcp_v4_create() {
  113. cs_sock_t s;
  114. int flag = 1;
  115. #ifdef _WIN32
  116. if ((s = WSASocket(
  117. AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == -1) {
  118. return (CS_ERR);
  119. }
  120. #else
  121. if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  122. return (CS_ERR);
  123. }
  124. #endif
  125. if (setsockopt(
  126. s, SOL_SOCKET, SO_REUSEADDR, (void *)&flag, sizeof(flag)) == 1) {
  127. return (CS_ERR);
  128. }
  129. return (s);
  130. }
  131. static int cs_tcp_v4_listen(
  132. cs_sock_t s, struct sockaddr *sa, unsigned int len) {
  133. if (bind(s, sa, len) == -1) {
  134. cs_tcp_close(s);
  135. return (CS_ERR);
  136. }
  137. if (listen(s, 511) == -1) { // 511 is from nginx
  138. cs_tcp_close(s);
  139. return (CS_ERR);
  140. }
  141. return (CS_OK);
  142. }
  143. // */
  144. CS_API cs_sock_t cs_tcp_v4_server(int port, char *bindaddr) {
  145. return _cs_tcp_server(port, bindaddr, AF_INET, 511);
  146. }
  147. CS_API cs_sock_t cs_tcp_v6_server(int port, char *bindaddr) {
  148. return _cs_tcp_server(port, bindaddr, AF_INET6, 511);
  149. }
  150. static cs_inline cs_sock_t _cs_tcp_generic_accept(
  151. cs_sock_t s, struct sockaddr *sa, unsigned int *len) {
  152. cs_sock_t fd;
  153. while (1) {
  154. fd = accept(s, sa, len);
  155. if (fd == -1) {
  156. if (cs_sock_errno == EINTR) {
  157. continue;
  158. } else {
  159. // cs_strerror(err, "accept: %s", strerror(errno));
  160. return (CS_ERR);
  161. }
  162. }
  163. break;
  164. }
  165. return (fd);
  166. }
  167. CS_API cs_sock_t cs_tcp_accept(
  168. cs_sock_t s, u_char *ip, size_t ip_len, int *port) {
  169. cs_sock_t fd;
  170. struct sockaddr_storage sa;
  171. socklen_t salen = sizeof(sa);
  172. if ((fd = _cs_tcp_generic_accept(s, (struct sockaddr*)&sa, &salen)) == -1) {
  173. return CS_ERR;
  174. }
  175. if (sa.ss_family == AF_INET) {
  176. struct sockaddr_in *s = (struct sockaddr_in *)&sa;
  177. if (ip) {
  178. inet_ntop(AF_INET, (void*)&(s->sin_addr), (char *)ip, ip_len);
  179. }
  180. if (port) {
  181. *port = ntohs(s->sin_port);
  182. }
  183. } else {
  184. struct sockaddr_in6 *s = (struct sockaddr_in6 *)&sa;
  185. if (ip) {
  186. inet_ntop(AF_INET6, (void*)&(s->sin6_addr), (char *)ip, ip_len);
  187. }
  188. if (port) {
  189. *port = ntohs(s->sin6_port);
  190. }
  191. }
  192. return (fd);
  193. }
  194. static int _cs_tcp_nodelay(cs_sock_t fd, int yes) {
  195. if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&yes, sizeof(yes))
  196. == -1) {
  197. // cs_strerror(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
  198. return (CS_ERR);
  199. }
  200. return (CS_OK);
  201. }
  202. CS_API int cs_tcp_enable_nodelay(cs_sock_t fd) {
  203. return _cs_tcp_nodelay(fd, 1);
  204. }
  205. CS_API int cs_tcp_disable_nodelay(cs_sock_t fd) {
  206. return _cs_tcp_nodelay(fd, 0);
  207. }
  208. CS_API int cs_tcp_keepalive(cs_sock_t fd) {
  209. int yes = 1;
  210. if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&yes, sizeof(yes))
  211. == -1) {
  212. return (CS_ERR);
  213. }
  214. return (CS_OK);
  215. }
  216. /* Set the socket send timeout (SO_SNDTIMEO socket option) to the specified
  217. * number of milliseconds, or disable it if the 'ms' argument is zero. */
  218. CS_API int cs_tcp_sndtimeo(cs_sock_t fd, long long ms) {
  219. struct timeval tv;
  220. tv.tv_sec = ms / 1000;
  221. tv.tv_usec = (ms % 1000) * 1000;
  222. if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) == -1) {
  223. // cs_strerror(err, "setsockopt SO_SNDTIMEO: %s", strerror(errno));
  224. return (CS_ERR);
  225. }
  226. return (CS_OK);
  227. }
  228. CS_API int cs_tcp_rcvtimeo(cs_sock_t fd, long long ms) {
  229. struct timeval tv;
  230. tv.tv_sec = ms / 1000;
  231. tv.tv_usec = (ms % 1000) * 1000;
  232. if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
  233. // cs_strerror(err, "setsockopt SO_RCVTIMEO: %s", strerror(errno));
  234. return (CS_ERR);
  235. }
  236. return (CS_OK);
  237. }
  238. static int _cs_tcp_blocking(cs_sock_t fd, int yes) {
  239. int flags;
  240. /* Set the socket blocking (if yes is zero) or non-blocking.
  241. * Note that fcntl(2) for F_GETFL and F_SETFL can't be
  242. * interrupted by a signal. */
  243. #ifdef _WIN32
  244. u_long arg = yes;
  245. if (ioctlsocket(fd, FIONBIO, &arg) == SOCKET_ERROR){
  246. return (CS_ERR);
  247. }
  248. #else
  249. if ((flags = fcntl(fd, F_GETFL)) == -1) {
  250. // cs_strerror(err, "fcntl(F_GETFL): %s", strerror(errno));
  251. return (CS_ERR);
  252. }
  253. if (yes) {
  254. flags |= O_NONBLOCK;
  255. } else {
  256. flags &= ~O_NONBLOCK;
  257. }
  258. if (fcntl(fd, F_SETFL, flags) == -1) {
  259. // cs_strerror(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
  260. return (CS_ERR);
  261. }
  262. #endif
  263. return (CS_OK);
  264. }
  265. CS_API int cs_tcp_nonblocking(cs_sock_t fd) {
  266. return _cs_tcp_blocking(fd, 1);
  267. }
  268. CS_API int cs_tcp_blocking(cs_sock_t fd) {
  269. return _cs_tcp_blocking(fd, 0);
  270. }
  271. CS_API int cs_tcp_close(cs_sock_t fd) {
  272. #ifdef _WIN32
  273. shutdown(fd, SD_BOTH);
  274. closesocket(fd);
  275. #else
  276. shutdown(fd, SHUT_RDWR);
  277. close(fd);
  278. #endif
  279. return (CS_OK);
  280. }