tcp-client.cpp 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #include <stdlib.h>
  2. #include "string.h"
  3. #include "tcp-client.h"
  4. #include "../../common/MiscFunctions.h"
  5. TCPClient::TCPClient() {
  6. host[0] = '\0';
  7. port[0] = '\0';
  8. connected = false;
  9. memset(&callbacks, 0, sizeof(callbacks));
  10. error[0] = '\0';
  11. fds.fd = SOCKET_INVALID;
  12. // memset(&addr, 0, sizeof(addr));
  13. // addr_len = 0;
  14. outgoing = NULL;
  15. outgoing_size = 0;
  16. outgoing_len = 0;
  17. }
  18. TCPClient::~TCPClient() {
  19. Stop();
  20. }
  21. void TCPClient::SetHost(const char *host) {
  22. if (host == NULL)
  23. this->host[0] = '\0';
  24. else
  25. strlcpy(this->host, host, sizeof(this->host));
  26. }
  27. void TCPClient::SetPort(const char *port) {
  28. strlcpy(this->port, port, sizeof(this->port));
  29. }
  30. void TCPClient::SetCallbacks(TCPClientCallbacks *callbacks) {
  31. memcpy(&this->callbacks, callbacks, sizeof(this->callbacks));
  32. }
  33. const char * TCPClient::GetHost() {
  34. return host;
  35. }
  36. const char * TCPClient::GetPort() {
  37. return port;
  38. }
  39. bool TCPClient::IsConnected() {
  40. return connected;
  41. }
  42. bool TCPClient::HasError() {
  43. return error[0] != '\0';
  44. }
  45. const char * TCPClient::GetError() {
  46. return error;
  47. }
  48. //struct sockaddr_storage * TCPClient::GetAddress() {
  49. // return &addr;
  50. //}
  51. bool TCPClient::Start() {
  52. struct addrinfo hints, *server, *p;
  53. socket_t fd;
  54. int ret;
  55. if (connected)
  56. return true;
  57. memset(&hints, 0, sizeof(hints));
  58. hints.ai_family = AF_INET;
  59. hints.ai_socktype = SOCK_STREAM;
  60. hints.ai_flags = AI_PASSIVE;
  61. //get list of networks
  62. ret = getaddrinfo(host[0] == '\0' ? NULL : host, port, &hints, &server);
  63. if (ret != 0) {
  64. strlcpy(error, gai_strerror(ret), sizeof(error));
  65. return false;
  66. }
  67. //loop through the addresses and bind to the first one we can
  68. for (p = server; p != NULL; p = p->ai_next) {
  69. fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
  70. if (fd == SOCKET_INVALID) {
  71. TCP::StoreError(error, sizeof(error));
  72. continue;
  73. }
  74. //connect to the server
  75. if (connect(fd, p->ai_addr, (int)p->ai_addrlen) == SOCKET_ERROR) {
  76. TCP::StoreError(error, sizeof(error));
  77. SOCKET_CLOSE(fd);
  78. continue;
  79. }
  80. break;
  81. }
  82. connected = p != NULL;
  83. if (connected) {
  84. fds.fd = fd;
  85. fds.events = POLLIN | POLLOUT;
  86. fds.revents = 0;
  87. // memcpy(&addr, p->ai_addr, sizeof(addr));
  88. // addr_len = p->ai_addrlen;
  89. error[0] = '\0';
  90. }
  91. freeaddrinfo(server);
  92. return connected;
  93. }
  94. void TCPClient::Stop() {
  95. if (connected)
  96. DisconnectHelper(false);
  97. }
  98. void TCPClient::DisconnectHelper(bool silent) {
  99. if (!silent && callbacks.disconnect != NULL)
  100. callbacks.disconnect(this);
  101. connected = false;
  102. error[0] = '\0';
  103. if (fds.fd != SOCKET_INVALID)
  104. SOCKET_CLOSE(fds.fd);
  105. // memset(&addr, 0, sizeof(addr));
  106. // addr_len = 0;
  107. if (outgoing != NULL) {
  108. free(outgoing);
  109. outgoing = NULL;
  110. }
  111. outgoing_size = 0;
  112. outgoing_len = 0;
  113. }
  114. void TCPClient::Disconnect() {
  115. DisconnectHelper(true);
  116. }
  117. bool TCPClient::Read() {
  118. char buf[4096];
  119. int count;
  120. count = recv(fds.fd, buf, sizeof(buf), 0);
  121. if (count == SOCKET_ERROR) {
  122. TCP::StoreError(error, sizeof(error));
  123. return false;
  124. }
  125. //disconnected
  126. if (count == 0) {
  127. DisconnectHelper(false);
  128. return true;
  129. }
  130. callbacks.data(this, buf, count);
  131. return true;
  132. }
  133. bool TCPClient::Write() {
  134. int count;
  135. count = send(fds.fd, outgoing, outgoing_len, 0);
  136. if (count == SOCKET_ERROR) {
  137. TCP::StoreError(error, sizeof(error));
  138. return false;
  139. }
  140. outgoing_len -= count;
  141. return true;
  142. }
  143. bool TCPClient::Process(unsigned int timeout) {
  144. int count;
  145. if (!connected)
  146. return false;
  147. count = poll(&fds, 1, timeout);
  148. if (count == SOCKET_ERROR) {
  149. TCP::StoreError(error, sizeof(error));
  150. return false;
  151. }
  152. if (fds.revents == 0)
  153. return true;
  154. //socket is bad
  155. if (fds.revents & POLLERR) {
  156. DisconnectHelper(false);
  157. return false;
  158. }
  159. //hung up
  160. if (fds.revents & POLLHUP) {
  161. DisconnectHelper(false);
  162. return false;
  163. }
  164. //socket is ready for reading
  165. if (fds.revents & POLLIN) {
  166. if (!Read())
  167. return false;
  168. }
  169. //socket is ready for writing
  170. if (fds.revents & POLLOUT) {
  171. if (outgoing_len > 0) {
  172. if (!Write())
  173. return false;
  174. }
  175. }
  176. return true;
  177. }
  178. bool TCPClient::Queue(const char *buf, unsigned int len) {
  179. unsigned int new_size;
  180. char *new_outgoing;
  181. while (outgoing_len + len > outgoing_size) {
  182. new_size = outgoing_size == 0 ? 1024 : outgoing_size * 2;
  183. new_outgoing = (char *)realloc(outgoing, new_size);
  184. if (new_outgoing == NULL)
  185. return false;
  186. outgoing = new_outgoing;
  187. outgoing_size = new_size;
  188. }
  189. memcpy(outgoing + outgoing_len, buf, len);
  190. outgoing_len += len;
  191. return true;
  192. }