HAL_TCP_linux.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. /*
  2. * Copyright (C) 2015-2018 Alibaba Group Holding Limited
  3. */
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <sys/time.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <netinet/tcp.h>
  13. #include <netdb.h>
  14. #include "infra_config.h"
  15. static uint64_t _linux_get_time_ms(void)
  16. {
  17. struct timeval tv = { 0 };
  18. uint64_t time_ms;
  19. gettimeofday(&tv, NULL);
  20. time_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
  21. return time_ms;
  22. }
  23. static uint64_t _linux_time_left(uint64_t t_end, uint64_t t_now)
  24. {
  25. uint64_t t_left;
  26. if (t_end > t_now) {
  27. t_left = t_end - t_now;
  28. } else {
  29. t_left = 0;
  30. }
  31. return t_left;
  32. }
  33. uintptr_t HAL_TCP_Establish(const char *host, uint16_t port)
  34. {
  35. struct addrinfo hints;
  36. struct addrinfo *addrInfoList = NULL;
  37. struct addrinfo *cur = NULL;
  38. int fd = 0;
  39. int rc = 0;
  40. char service[6];
  41. uint8_t dns_retry = 0;
  42. memset(&hints, 0, sizeof(hints));
  43. printf("establish tcp connection with server(host='%s', port=[%u])\n", host, port);
  44. hints.ai_family = AF_INET; /* only IPv4 */
  45. hints.ai_socktype = SOCK_STREAM;
  46. hints.ai_protocol = IPPROTO_TCP;
  47. sprintf(service, "%u", port);
  48. while(dns_retry++ < 8) {
  49. rc = getaddrinfo(host, service, &hints, &addrInfoList);
  50. if (rc != 0) {
  51. printf("getaddrinfo error[%d], res: %s, host: %s, port: %s\n", dns_retry, gai_strerror(rc), host, service);
  52. sleep(1);
  53. continue;
  54. }else{
  55. break;
  56. }
  57. }
  58. if (rc != 0) {
  59. printf("getaddrinfo error(%d), host = '%s', port = [%d]\n", rc, host, port);
  60. return (uintptr_t)(-1);
  61. }
  62. for (cur = addrInfoList; cur != NULL; cur = cur->ai_next) {
  63. if (cur->ai_family != AF_INET) {
  64. printf("socket type error\n");
  65. rc = -1;
  66. continue;
  67. }
  68. fd = socket(cur->ai_family, cur->ai_socktype, cur->ai_protocol);
  69. if (fd < 0) {
  70. printf("create socket error\n");
  71. rc = -1;
  72. continue;
  73. }
  74. if (connect(fd, cur->ai_addr, cur->ai_addrlen) == 0) {
  75. rc = fd;
  76. break;
  77. }
  78. close(fd);
  79. printf("connect error\n");
  80. rc = -1;
  81. }
  82. if (-1 == rc) {
  83. printf("fail to establish tcp\n");
  84. } else {
  85. printf("success to establish tcp, fd=%d\n", rc);
  86. }
  87. freeaddrinfo(addrInfoList);
  88. return (uintptr_t)rc;
  89. }
  90. int HAL_TCP_Destroy(uintptr_t fd)
  91. {
  92. int rc;
  93. /* Shutdown both send and receive operations. */
  94. rc = shutdown((int) fd, 2);
  95. if (0 != rc) {
  96. printf("shutdown error\n");
  97. return -1;
  98. }
  99. rc = close((int) fd);
  100. if (0 != rc) {
  101. printf("closesocket error\n");
  102. return -1;
  103. }
  104. return 0;
  105. }
  106. int32_t HAL_TCP_Write(uintptr_t fd, const char *buf, uint32_t len, uint32_t timeout_ms)
  107. {
  108. int ret,tcp_fd;
  109. uint32_t len_sent;
  110. uint64_t t_end, t_left;
  111. fd_set sets;
  112. int net_err = 0;
  113. t_end = _linux_get_time_ms() + timeout_ms;
  114. len_sent = 0;
  115. ret = 1; /* send one time if timeout_ms is value 0 */
  116. if (fd >= FD_SETSIZE) {
  117. return -1;
  118. }
  119. tcp_fd = (int)fd;
  120. do {
  121. t_left = _linux_time_left(t_end, _linux_get_time_ms());
  122. if (0 != t_left) {
  123. struct timeval timeout;
  124. FD_ZERO(&sets);
  125. FD_SET(tcp_fd, &sets);
  126. timeout.tv_sec = t_left / 1000;
  127. timeout.tv_usec = (t_left % 1000) * 1000;
  128. ret = select(tcp_fd + 1, NULL, &sets, NULL, &timeout);
  129. if (ret > 0) {
  130. if (0 == FD_ISSET(tcp_fd, &sets)) {
  131. printf("Should NOT arrive\n");
  132. /* If timeout in next loop, it will not sent any data */
  133. ret = 0;
  134. continue;
  135. }
  136. } else if (0 == ret) {
  137. printf("select-write timeout %d\n", tcp_fd);
  138. break;
  139. } else {
  140. if (EINTR == errno) {
  141. printf("EINTR be caught\n");
  142. continue;
  143. }
  144. printf("select-write fail, ret = select() = %d\n", ret);
  145. net_err = 1;
  146. break;
  147. }
  148. }
  149. if (ret > 0) {
  150. ret = send(tcp_fd, buf + len_sent, len - len_sent, 0);
  151. if (ret > 0) {
  152. len_sent += ret;
  153. } else if (0 == ret) {
  154. printf("No data be sent\n");
  155. } else {
  156. if (EINTR == errno) {
  157. printf("EINTR be caught\n");
  158. continue;
  159. }
  160. printf("send fail, ret = send() = %d\n", ret);
  161. net_err = 1;
  162. break;
  163. }
  164. }
  165. } while (!net_err && (len_sent < len) && (_linux_time_left(t_end, _linux_get_time_ms()) > 0));
  166. if (net_err) {
  167. return -1;
  168. } else {
  169. return len_sent;
  170. }
  171. }
  172. int32_t HAL_TCP_Read(uintptr_t fd, char *buf, uint32_t len, uint32_t timeout_ms)
  173. {
  174. int ret, err_code, tcp_fd;
  175. uint32_t len_recv;
  176. uint64_t t_end, t_left;
  177. fd_set sets;
  178. struct timeval timeout;
  179. t_end = _linux_get_time_ms() + timeout_ms;
  180. len_recv = 0;
  181. err_code = 0;
  182. if (fd >= FD_SETSIZE) {
  183. return -1;
  184. }
  185. tcp_fd = (int)fd;
  186. do {
  187. t_left = _linux_time_left(t_end, _linux_get_time_ms());
  188. if (0 == t_left) {
  189. break;
  190. }
  191. FD_ZERO(&sets);
  192. FD_SET(tcp_fd, &sets);
  193. timeout.tv_sec = t_left / 1000;
  194. timeout.tv_usec = (t_left % 1000) * 1000;
  195. ret = select(tcp_fd + 1, &sets, NULL, NULL, &timeout);
  196. if (ret > 0) {
  197. ret = recv(tcp_fd, buf + len_recv, len - len_recv, 0);
  198. if (ret > 0) {
  199. len_recv += ret;
  200. } else if (0 == ret) {
  201. printf("connection is closed\n");
  202. err_code = -1;
  203. break;
  204. } else {
  205. if (EINTR == errno) {
  206. continue;
  207. }
  208. printf("recv fail\n");
  209. err_code = -2;
  210. break;
  211. }
  212. } else if (0 == ret) {
  213. break;
  214. } else {
  215. if (EINTR == errno) {
  216. continue;
  217. }
  218. printf("select-recv fail\n");
  219. err_code = -2;
  220. break;
  221. }
  222. } while ((len_recv < len));
  223. /* priority to return data bytes if any data be received from TCP connection. */
  224. /* It will get error code on next calling */
  225. return (0 != len_recv) ? len_recv : err_code;
  226. }