Socket.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /*
  2. This program is free software: you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation, either version 3 of the License, or
  5. (at your option) any later version.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License
  11. along with this program. If not, see <http://www.gnu.org/licenses/>.
  12. */
  13. /*
  14. simple socket handling class for systems with BSD socket API
  15. */
  16. #include <AP_HAL/AP_HAL.h>
  17. #if HAL_OS_SOCKETS
  18. #include "Socket.h"
  19. /*
  20. constructor
  21. */
  22. SocketAPM::SocketAPM(bool _datagram) :
  23. SocketAPM(_datagram,
  24. socket(AF_INET, _datagram?SOCK_DGRAM:SOCK_STREAM, 0))
  25. {}
  26. SocketAPM::SocketAPM(bool _datagram, int _fd) :
  27. datagram(_datagram),
  28. fd(_fd)
  29. {
  30. fcntl(fd, F_SETFD, FD_CLOEXEC);
  31. if (!datagram) {
  32. int one = 1;
  33. setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
  34. }
  35. }
  36. SocketAPM::~SocketAPM()
  37. {
  38. if (fd != -1) {
  39. ::close(fd);
  40. fd = -1;
  41. }
  42. }
  43. void SocketAPM::make_sockaddr(const char *address, uint16_t port, struct sockaddr_in &sockaddr)
  44. {
  45. memset(&sockaddr, 0, sizeof(sockaddr));
  46. #ifdef HAVE_SOCK_SIN_LEN
  47. sockaddr.sin_len = sizeof(sockaddr);
  48. #endif
  49. sockaddr.sin_port = htons(port);
  50. sockaddr.sin_family = AF_INET;
  51. sockaddr.sin_addr.s_addr = inet_addr(address);
  52. }
  53. /*
  54. connect the socket
  55. */
  56. bool SocketAPM::connect(const char *address, uint16_t port)
  57. {
  58. struct sockaddr_in sockaddr;
  59. make_sockaddr(address, port, sockaddr);
  60. if (::connect(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
  61. return false;
  62. }
  63. return true;
  64. }
  65. /*
  66. bind the socket
  67. */
  68. bool SocketAPM::bind(const char *address, uint16_t port)
  69. {
  70. struct sockaddr_in sockaddr;
  71. make_sockaddr(address, port, sockaddr);
  72. if (::bind(fd, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) != 0) {
  73. return false;
  74. }
  75. return true;
  76. }
  77. /*
  78. set SO_REUSEADDR
  79. */
  80. bool SocketAPM::reuseaddress(void)
  81. {
  82. int one = 1;
  83. return (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)) != -1);
  84. }
  85. /*
  86. set blocking state
  87. */
  88. bool SocketAPM::set_blocking(bool blocking)
  89. {
  90. int fcntl_ret;
  91. if (blocking) {
  92. fcntl_ret = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
  93. } else {
  94. fcntl_ret = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
  95. }
  96. return fcntl_ret != -1;
  97. }
  98. /*
  99. set cloexec state
  100. */
  101. bool SocketAPM::set_cloexec()
  102. {
  103. return (fcntl(fd, F_SETFD, FD_CLOEXEC) != -1);
  104. }
  105. /*
  106. send some data
  107. */
  108. ssize_t SocketAPM::send(const void *buf, size_t size)
  109. {
  110. return ::send(fd, buf, size, 0);
  111. }
  112. /*
  113. send some data
  114. */
  115. ssize_t SocketAPM::sendto(const void *buf, size_t size, const char *address, uint16_t port)
  116. {
  117. struct sockaddr_in sockaddr;
  118. make_sockaddr(address, port, sockaddr);
  119. return ::sendto(fd, buf, size, 0, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
  120. }
  121. /*
  122. receive some data
  123. */
  124. ssize_t SocketAPM::recv(void *buf, size_t size, uint32_t timeout_ms)
  125. {
  126. if (!pollin(timeout_ms)) {
  127. return -1;
  128. }
  129. socklen_t len = sizeof(in_addr);
  130. return ::recvfrom(fd, buf, size, MSG_DONTWAIT, (sockaddr *)&in_addr, &len);
  131. }
  132. /*
  133. return the IP address and port of the last received packet
  134. */
  135. void SocketAPM::last_recv_address(const char *&ip_addr, uint16_t &port)
  136. {
  137. ip_addr = inet_ntoa(in_addr.sin_addr);
  138. port = ntohs(in_addr.sin_port);
  139. }
  140. void SocketAPM::set_broadcast(void)
  141. {
  142. int one = 1;
  143. setsockopt(fd,SOL_SOCKET,SO_BROADCAST,(char *)&one,sizeof(one));
  144. }
  145. /*
  146. return true if there is pending data for input
  147. */
  148. bool SocketAPM::pollin(uint32_t timeout_ms)
  149. {
  150. fd_set fds;
  151. struct timeval tv;
  152. FD_ZERO(&fds);
  153. FD_SET(fd, &fds);
  154. tv.tv_sec = timeout_ms / 1000;
  155. tv.tv_usec = (timeout_ms % 1000) * 1000UL;
  156. if (select(fd+1, &fds, nullptr, nullptr, &tv) != 1) {
  157. return false;
  158. }
  159. return true;
  160. }
  161. /*
  162. return true if there is room for output data
  163. */
  164. bool SocketAPM::pollout(uint32_t timeout_ms)
  165. {
  166. fd_set fds;
  167. struct timeval tv;
  168. FD_ZERO(&fds);
  169. FD_SET(fd, &fds);
  170. tv.tv_sec = timeout_ms / 1000;
  171. tv.tv_usec = (timeout_ms % 1000) * 1000UL;
  172. if (select(fd+1, nullptr, &fds, nullptr, &tv) != 1) {
  173. return false;
  174. }
  175. return true;
  176. }
  177. /*
  178. start listening for new tcp connections
  179. */
  180. bool SocketAPM::listen(uint16_t backlog)
  181. {
  182. return ::listen(fd, (int)backlog) == 0;
  183. }
  184. /*
  185. accept a new connection. Only valid for TCP connections after
  186. listen has been used. A new socket is returned
  187. */
  188. SocketAPM *SocketAPM::accept(uint32_t timeout_ms)
  189. {
  190. if (!pollin(timeout_ms)) {
  191. return nullptr;
  192. }
  193. int newfd = ::accept(fd, nullptr, nullptr);
  194. if (newfd == -1) {
  195. return nullptr;
  196. }
  197. // turn off nagle for lower latency
  198. int one = 1;
  199. setsockopt(newfd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
  200. return new SocketAPM(false, newfd);
  201. }
  202. #endif // HAL_OS_SOCKETS