PageRenderTime 25ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/clients/roscpp/src/libros/transport/transport_udp.cpp

https://gitlab.com/F34140r/ros_comm
C++ | 670 lines | 537 code | 90 blank | 43 comment | 86 complexity | ab16dbcd552f4bf0ca282206ffbf93f0 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /*
  2. * Software License Agreement (BSD License)
  3. *
  4. * Copyright (c) 2008, Willow Garage, Inc.
  5. * All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * * Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * * Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following
  15. * disclaimer in the documentation and/or other materials provided
  16. * with the distribution.
  17. * * Neither the name of Willow Garage, Inc. nor the names of its
  18. * contributors may be used to endorse or promote products derived
  19. * from this software without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. */
  34. #include "ros/transport/transport_udp.h"
  35. #include "ros/poll_set.h"
  36. #include "ros/file_log.h"
  37. #include <ros/assert.h>
  38. #include <boost/bind.hpp>
  39. #include <fcntl.h>
  40. #if defined(__APPLE__)
  41. // For readv() and writev()
  42. #include <sys/types.h>
  43. #include <sys/uio.h>
  44. #include <unistd.h>
  45. #endif
  46. namespace ros
  47. {
  48. TransportUDP::TransportUDP(PollSet* poll_set, int flags, int max_datagram_size)
  49. : sock_(-1)
  50. , closed_(false)
  51. , expecting_read_(false)
  52. , expecting_write_(false)
  53. , is_server_(false)
  54. , server_port_(-1)
  55. , poll_set_(poll_set)
  56. , flags_(flags)
  57. , connection_id_(0)
  58. , current_message_id_(0)
  59. , total_blocks_(0)
  60. , last_block_(0)
  61. , max_datagram_size_(max_datagram_size)
  62. , data_filled_(0)
  63. , reorder_buffer_(0)
  64. , reorder_bytes_(0)
  65. {
  66. // This may eventually be machine dependent
  67. if (max_datagram_size_ == 0)
  68. max_datagram_size_ = 1500;
  69. reorder_buffer_ = new uint8_t[max_datagram_size_];
  70. reorder_start_ = reorder_buffer_;
  71. data_buffer_ = new uint8_t[max_datagram_size_];
  72. data_start_ = data_buffer_;
  73. }
  74. TransportUDP::~TransportUDP()
  75. {
  76. ROS_ASSERT_MSG(sock_ == ROS_INVALID_SOCKET, "TransportUDP socket [%d] was never closed", sock_);
  77. delete [] reorder_buffer_;
  78. delete [] data_buffer_;
  79. }
  80. bool TransportUDP::setSocket(int sock)
  81. {
  82. sock_ = sock;
  83. return initializeSocket();
  84. }
  85. void TransportUDP::socketUpdate(int events)
  86. {
  87. {
  88. boost::mutex::scoped_lock lock(close_mutex_);
  89. if (closed_)
  90. {
  91. return;
  92. }
  93. }
  94. if((events & POLLERR) ||
  95. (events & POLLHUP) ||
  96. (events & POLLNVAL))
  97. {
  98. ROSCPP_LOG_DEBUG("Socket %d closed with (ERR|HUP|NVAL) events %d", sock_, events);
  99. close();
  100. }
  101. else
  102. {
  103. if ((events & POLLIN) && expecting_read_)
  104. {
  105. if (read_cb_)
  106. {
  107. read_cb_(shared_from_this());
  108. }
  109. }
  110. if ((events & POLLOUT) && expecting_write_)
  111. {
  112. if (write_cb_)
  113. {
  114. write_cb_(shared_from_this());
  115. }
  116. }
  117. }
  118. }
  119. std::string TransportUDP::getTransportInfo()
  120. {
  121. return "UDPROS connection to [" + cached_remote_host_ + "]";
  122. }
  123. bool TransportUDP::connect(const std::string& host, int port, int connection_id)
  124. {
  125. sock_ = socket(AF_INET, SOCK_DGRAM, 0);
  126. connection_id_ = connection_id;
  127. if (sock_ == ROS_INVALID_SOCKET)
  128. {
  129. ROS_ERROR("socket() failed with error [%s]", last_socket_error_string());
  130. return false;
  131. }
  132. sockaddr_in sin;
  133. sin.sin_family = AF_INET;
  134. if (inet_addr(host.c_str()) == INADDR_NONE)
  135. {
  136. struct addrinfo* addr;
  137. struct addrinfo hints;
  138. memset(&hints, 0, sizeof(hints));
  139. hints.ai_family = AF_UNSPEC;
  140. if (getaddrinfo(host.c_str(), NULL, &hints, &addr) != 0)
  141. {
  142. close();
  143. ROS_ERROR("couldn't resolve host [%s]", host.c_str());
  144. return false;
  145. }
  146. bool found = false;
  147. struct addrinfo* it = addr;
  148. for (; it; it = it->ai_next)
  149. {
  150. if (it->ai_family == AF_INET)
  151. {
  152. memcpy(&sin, it->ai_addr, it->ai_addrlen);
  153. sin.sin_family = it->ai_family;
  154. sin.sin_port = htons(port);
  155. found = true;
  156. break;
  157. }
  158. }
  159. freeaddrinfo(addr);
  160. if (!found)
  161. {
  162. ROS_ERROR("Couldn't find an AF_INET address for [%s]\n", host.c_str());
  163. return false;
  164. }
  165. ROSCPP_LOG_DEBUG("Resolved host [%s] to [%s]", host.c_str(), inet_ntoa(sin.sin_addr));
  166. }
  167. else
  168. {
  169. sin.sin_addr.s_addr = inet_addr(host.c_str()); // already an IP addr
  170. }
  171. sin.sin_port = htons(port);
  172. if (::connect(sock_, (sockaddr *)&sin, sizeof(sin)))
  173. {
  174. ROSCPP_LOG_DEBUG("Connect to udpros host [%s:%d] failed with error [%s]", host.c_str(), port, last_socket_error_string());
  175. close();
  176. return false;
  177. }
  178. // from daniel stonier:
  179. #ifdef WIN32
  180. // This is hackish, but windows fails at recv() if its slow to connect (e.g. happens with wireless)
  181. // recv() needs to check if its connected or not when its asynchronous?
  182. Sleep(100);
  183. #endif
  184. if (!initializeSocket())
  185. {
  186. return false;
  187. }
  188. ROSCPP_LOG_DEBUG("Connect succeeded to [%s:%d] on socket [%d]", host.c_str(), port, sock_);
  189. return true;
  190. }
  191. bool TransportUDP::createIncoming(int port, bool is_server)
  192. {
  193. is_server_ = is_server;
  194. sock_ = socket(AF_INET, SOCK_DGRAM, 0);
  195. if (sock_ <= 0)
  196. {
  197. ROS_ERROR("socket() failed with error [%s]", last_socket_error_string());
  198. return false;
  199. }
  200. server_address_.sin_family = AF_INET;
  201. server_address_.sin_port = htons(port);
  202. server_address_.sin_addr.s_addr = INADDR_ANY;
  203. if (bind(sock_, (sockaddr *)&server_address_, sizeof(server_address_)) < 0)
  204. {
  205. ROS_ERROR("bind() failed with error [%s]", last_socket_error_string());
  206. return false;
  207. }
  208. socklen_t len = sizeof(server_address_);
  209. getsockname(sock_, (sockaddr *)&server_address_, &len);
  210. server_port_ = ntohs(server_address_.sin_port);
  211. ROSCPP_LOG_DEBUG("UDPROS server listening on port [%d]", server_port_);
  212. if (!initializeSocket())
  213. {
  214. return false;
  215. }
  216. enableRead();
  217. return true;
  218. }
  219. bool TransportUDP::initializeSocket()
  220. {
  221. ROS_ASSERT(sock_ != ROS_INVALID_SOCKET);
  222. if (!(flags_ & SYNCHRONOUS))
  223. {
  224. int result = set_non_blocking(sock_);
  225. if ( result != 0 ) {
  226. ROS_ERROR("setting socket [%d] as non_blocking failed with error [%d]", sock_, result);
  227. close();
  228. return false;
  229. }
  230. }
  231. ROS_ASSERT(poll_set_ || (flags_ & SYNCHRONOUS));
  232. if (poll_set_)
  233. {
  234. poll_set_->addSocket(sock_, boost::bind(&TransportUDP::socketUpdate, this, _1), shared_from_this());
  235. }
  236. return true;
  237. }
  238. void TransportUDP::close()
  239. {
  240. Callback disconnect_cb;
  241. if (!closed_)
  242. {
  243. {
  244. boost::mutex::scoped_lock lock(close_mutex_);
  245. if (!closed_)
  246. {
  247. closed_ = true;
  248. ROSCPP_LOG_DEBUG("UDP socket [%d] closed", sock_);
  249. ROS_ASSERT(sock_ != ROS_INVALID_SOCKET);
  250. if (poll_set_)
  251. {
  252. poll_set_->delSocket(sock_);
  253. }
  254. if ( close_socket(sock_) != 0 )
  255. {
  256. ROS_ERROR("Error closing socket [%d]: [%s]", sock_, last_socket_error_string());
  257. }
  258. sock_ = ROS_INVALID_SOCKET;
  259. disconnect_cb = disconnect_cb_;
  260. disconnect_cb_ = Callback();
  261. read_cb_ = Callback();
  262. write_cb_ = Callback();
  263. }
  264. }
  265. }
  266. if (disconnect_cb)
  267. {
  268. disconnect_cb(shared_from_this());
  269. }
  270. }
  271. int32_t TransportUDP::read(uint8_t* buffer, uint32_t size)
  272. {
  273. {
  274. boost::mutex::scoped_lock lock(close_mutex_);
  275. if (closed_)
  276. {
  277. ROSCPP_LOG_DEBUG("Tried to read on a closed socket [%d]", sock_);
  278. return -1;
  279. }
  280. }
  281. ROS_ASSERT((int32_t)size > 0);
  282. uint32_t bytes_read = 0;
  283. while (bytes_read < size)
  284. {
  285. TransportUDPHeader header;
  286. uint32_t copy_bytes = 0;
  287. bool from_previous = false;
  288. if (reorder_bytes_)
  289. {
  290. if (reorder_start_ != reorder_buffer_)
  291. {
  292. from_previous = true;
  293. }
  294. copy_bytes = std::min(size - bytes_read, reorder_bytes_);
  295. header = reorder_header_;
  296. memcpy(buffer + bytes_read, reorder_start_, copy_bytes);
  297. reorder_bytes_ -= copy_bytes;
  298. reorder_start_ += copy_bytes;
  299. }
  300. else
  301. {
  302. if (data_filled_ == 0)
  303. {
  304. #if defined(WIN32)
  305. SSIZE_T num_bytes = 0;
  306. DWORD received_bytes = 0;
  307. DWORD flags = 0;
  308. WSABUF iov[2];
  309. iov[0].buf = reinterpret_cast<char*>(&header);
  310. iov[0].len = sizeof(header);
  311. iov[1].buf = reinterpret_cast<char*>(data_buffer_);
  312. iov[1].len = max_datagram_size_ - sizeof(header);
  313. int rc = WSARecv(sock_, iov, 2, &received_bytes, &flags, NULL, NULL);
  314. if ( rc == SOCKET_ERROR) {
  315. num_bytes = -1;
  316. } else {
  317. num_bytes = received_bytes;
  318. }
  319. #else
  320. ssize_t num_bytes;
  321. struct iovec iov[2];
  322. iov[0].iov_base = &header;
  323. iov[0].iov_len = sizeof(header);
  324. iov[1].iov_base = data_buffer_;
  325. iov[1].iov_len = max_datagram_size_ - sizeof(header);
  326. // Read a datagram with header
  327. num_bytes = readv(sock_, iov, 2);
  328. #endif
  329. if (num_bytes < 0)
  330. {
  331. if ( last_socket_error_is_would_block() )
  332. {
  333. num_bytes = 0;
  334. break;
  335. }
  336. else
  337. {
  338. ROSCPP_LOG_DEBUG("readv() failed with error [%s]", last_socket_error_string());
  339. close();
  340. break;
  341. }
  342. }
  343. else if (num_bytes == 0)
  344. {
  345. ROSCPP_LOG_DEBUG("Socket [%d] received 0/%d bytes, closing", sock_, size);
  346. close();
  347. return -1;
  348. }
  349. else if (num_bytes < (unsigned) sizeof(header))
  350. {
  351. ROS_ERROR("Socket [%d] received short header (%d bytes): %s", sock_, int(num_bytes), last_socket_error_string());
  352. close();
  353. return -1;
  354. }
  355. num_bytes -= sizeof(header);
  356. data_filled_ = num_bytes;
  357. data_start_ = data_buffer_;
  358. }
  359. else
  360. {
  361. from_previous = true;
  362. }
  363. copy_bytes = std::min(size - bytes_read, data_filled_);
  364. // Copy from the data buffer, whether it has data left in it from a previous datagram or
  365. // was just filled by readv()
  366. memcpy(buffer + bytes_read, data_start_, copy_bytes);
  367. data_filled_ = std::max((int64_t)0, (int64_t)data_filled_ - (int64_t)size);
  368. data_start_ += copy_bytes;
  369. }
  370. if (from_previous)
  371. {
  372. bytes_read += copy_bytes;
  373. }
  374. else
  375. {
  376. // Process header
  377. switch (header.op_)
  378. {
  379. case ROS_UDP_DATA0:
  380. if (current_message_id_)
  381. {
  382. ROS_DEBUG("Received new message [%d:%d], while still working on [%d] (block %d of %d)", header.message_id_, header.block_, current_message_id_, last_block_ + 1, total_blocks_);
  383. reorder_header_ = header;
  384. reorder_bytes_ = copy_bytes;
  385. memcpy(reorder_buffer_, buffer + bytes_read, copy_bytes);
  386. reorder_start_ = reorder_buffer_;
  387. current_message_id_ = 0;
  388. total_blocks_ = 0;
  389. last_block_ = 0;
  390. data_filled_ = 0;
  391. data_start_ = data_buffer_;
  392. return -1;
  393. }
  394. total_blocks_ = header.block_;
  395. last_block_ = 0;
  396. current_message_id_ = header.message_id_;
  397. break;
  398. case ROS_UDP_DATAN:
  399. if (header.message_id_ != current_message_id_)
  400. {
  401. ROS_DEBUG("Message Id mismatch: %d != %d", header.message_id_, current_message_id_);
  402. return 0;
  403. }
  404. if (header.block_ != last_block_ + 1)
  405. {
  406. ROS_DEBUG("Expected block %d, received %d", last_block_ + 1, header.block_);
  407. return 0;
  408. }
  409. last_block_ = header.block_;
  410. break;
  411. default:
  412. ROS_ERROR("Unexpected UDP header OP [%d]", header.op_);
  413. return -1;
  414. }
  415. bytes_read += copy_bytes;
  416. if (last_block_ == (total_blocks_ - 1))
  417. {
  418. current_message_id_ = 0;
  419. break;
  420. }
  421. }
  422. }
  423. return bytes_read;
  424. }
  425. int32_t TransportUDP::write(uint8_t* buffer, uint32_t size)
  426. {
  427. {
  428. boost::mutex::scoped_lock lock(close_mutex_);
  429. if (closed_)
  430. {
  431. ROSCPP_LOG_DEBUG("Tried to write on a closed socket [%d]", sock_);
  432. return -1;
  433. }
  434. }
  435. ROS_ASSERT((int32_t)size > 0);
  436. const uint32_t max_payload_size = max_datagram_size_ - sizeof(TransportUDPHeader);
  437. uint32_t bytes_sent = 0;
  438. uint32_t this_block = 0;
  439. if (++current_message_id_ == 0)
  440. ++current_message_id_;
  441. while (bytes_sent < size)
  442. {
  443. TransportUDPHeader header;
  444. header.connection_id_ = connection_id_;
  445. header.message_id_ = current_message_id_;
  446. if (this_block == 0)
  447. {
  448. header.op_ = ROS_UDP_DATA0;
  449. header.block_ = (size + max_payload_size - 1) / max_payload_size;
  450. }
  451. else
  452. {
  453. header.op_ = ROS_UDP_DATAN;
  454. header.block_ = this_block;
  455. }
  456. ++this_block;
  457. #if defined(WIN32)
  458. WSABUF iov[2];
  459. DWORD sent_bytes;
  460. SSIZE_T num_bytes = 0;
  461. DWORD flags = 0;
  462. int rc;
  463. iov[0].buf = reinterpret_cast<char*>(&header);
  464. iov[0].len = sizeof(header);
  465. iov[1].buf = reinterpret_cast<char*>(buffer + bytes_sent);
  466. iov[1].len = std::min(max_payload_size, size - bytes_sent);
  467. rc = WSASend(sock_, iov, 2, &sent_bytes, flags, NULL, NULL);
  468. num_bytes = sent_bytes;
  469. if (rc == SOCKET_ERROR) {
  470. num_bytes = -1;
  471. }
  472. #else
  473. struct iovec iov[2];
  474. iov[0].iov_base = &header;
  475. iov[0].iov_len = sizeof(header);
  476. iov[1].iov_base = buffer + bytes_sent;
  477. iov[1].iov_len = std::min(max_payload_size, size - bytes_sent);
  478. ssize_t num_bytes = writev(sock_, iov, 2);
  479. #endif
  480. //usleep(100);
  481. if (num_bytes < 0)
  482. {
  483. if( !last_socket_error_is_would_block() ) // Actually EAGAIN or EWOULDBLOCK on posix
  484. {
  485. ROSCPP_LOG_DEBUG("writev() failed with error [%s]", last_socket_error_string());
  486. close();
  487. break;
  488. }
  489. else
  490. {
  491. num_bytes = 0;
  492. }
  493. }
  494. else if (num_bytes < (unsigned) sizeof(header))
  495. {
  496. ROSCPP_LOG_DEBUG("Socket [%d] short write (%d bytes), closing", sock_, int(num_bytes));
  497. close();
  498. break;
  499. }
  500. else
  501. {
  502. num_bytes -= sizeof(header);
  503. }
  504. bytes_sent += num_bytes;
  505. }
  506. return bytes_sent;
  507. }
  508. void TransportUDP::enableRead()
  509. {
  510. {
  511. boost::mutex::scoped_lock lock(close_mutex_);
  512. if (closed_)
  513. {
  514. return;
  515. }
  516. }
  517. if (!expecting_read_)
  518. {
  519. poll_set_->addEvents(sock_, POLLIN);
  520. expecting_read_ = true;
  521. }
  522. }
  523. void TransportUDP::disableRead()
  524. {
  525. ROS_ASSERT(!(flags_ & SYNCHRONOUS));
  526. {
  527. boost::mutex::scoped_lock lock(close_mutex_);
  528. if (closed_)
  529. {
  530. return;
  531. }
  532. }
  533. if (expecting_read_)
  534. {
  535. poll_set_->delEvents(sock_, POLLIN);
  536. expecting_read_ = false;
  537. }
  538. }
  539. void TransportUDP::enableWrite()
  540. {
  541. {
  542. boost::mutex::scoped_lock lock(close_mutex_);
  543. if (closed_)
  544. {
  545. return;
  546. }
  547. }
  548. if (!expecting_write_)
  549. {
  550. poll_set_->addEvents(sock_, POLLOUT);
  551. expecting_write_ = true;
  552. }
  553. }
  554. void TransportUDP::disableWrite()
  555. {
  556. {
  557. boost::mutex::scoped_lock lock(close_mutex_);
  558. if (closed_)
  559. {
  560. return;
  561. }
  562. }
  563. if (expecting_write_)
  564. {
  565. poll_set_->delEvents(sock_, POLLOUT);
  566. expecting_write_ = false;
  567. }
  568. }
  569. TransportUDPPtr TransportUDP::createOutgoing(std::string host, int port, int connection_id, int max_datagram_size)
  570. {
  571. ROS_ASSERT(is_server_);
  572. TransportUDPPtr transport(new TransportUDP(poll_set_, flags_, max_datagram_size));
  573. if (!transport->connect(host, port, connection_id))
  574. {
  575. ROS_ERROR("Failed to create outgoing connection");
  576. return TransportUDPPtr();
  577. }
  578. return transport;
  579. }
  580. }