PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://gitlab.com/F34140r/ros_comm
C++ | 725 lines | 570 code | 109 blank | 46 comment | 98 complexity | 3a42a4c8365f4592467c02f59fc21ba3 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/io.h"
  35. #include "ros/transport/transport_tcp.h"
  36. #include "ros/poll_set.h"
  37. #include "ros/header.h"
  38. #include "ros/file_log.h"
  39. #include <ros/assert.h>
  40. #include <sstream>
  41. #include <boost/bind.hpp>
  42. #include <fcntl.h>
  43. #include <errno.h>
  44. namespace ros
  45. {
  46. bool TransportTCP::s_use_keepalive_ = true;
  47. bool TransportTCP::s_use_ipv6_ = false;
  48. TransportTCP::TransportTCP(PollSet* poll_set, int flags)
  49. : sock_(ROS_INVALID_SOCKET)
  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. {
  58. }
  59. TransportTCP::~TransportTCP()
  60. {
  61. ROS_ASSERT_MSG(sock_ == -1, "TransportTCP socket [%d] was never closed", sock_);
  62. }
  63. bool TransportTCP::setSocket(int sock)
  64. {
  65. sock_ = sock;
  66. return initializeSocket();
  67. }
  68. bool TransportTCP::setNonBlocking()
  69. {
  70. if (!(flags_ & SYNCHRONOUS))
  71. {
  72. int result = set_non_blocking(sock_);
  73. if ( result != 0 ) {
  74. ROS_ERROR("setting socket [%d] as non_blocking failed with error [%d]", sock_, result);
  75. close();
  76. return false;
  77. }
  78. }
  79. return true;
  80. }
  81. bool TransportTCP::initializeSocket()
  82. {
  83. ROS_ASSERT(sock_ != ROS_INVALID_SOCKET);
  84. if (!setNonBlocking())
  85. {
  86. return false;
  87. }
  88. setKeepAlive(s_use_keepalive_, 60, 10, 9);
  89. // connect() will set cached_remote_host_ because it already has the host/port available
  90. if (cached_remote_host_.empty())
  91. {
  92. if (is_server_)
  93. {
  94. cached_remote_host_ = "TCPServer Socket";
  95. }
  96. else
  97. {
  98. std::stringstream ss;
  99. ss << getClientURI() << " on socket " << sock_;
  100. cached_remote_host_ = ss.str();
  101. }
  102. }
  103. #ifdef ROSCPP_USE_TCP_NODELAY
  104. setNoDelay(true);
  105. #endif
  106. ROS_ASSERT(poll_set_ || (flags_ & SYNCHRONOUS));
  107. if (poll_set_)
  108. {
  109. ROS_DEBUG("Adding tcp socket [%d] to pollset", sock_);
  110. poll_set_->addSocket(sock_, boost::bind(&TransportTCP::socketUpdate, this, _1), shared_from_this());
  111. }
  112. if (!(flags_ & SYNCHRONOUS))
  113. {
  114. //enableRead();
  115. }
  116. return true;
  117. }
  118. void TransportTCP::parseHeader(const Header& header)
  119. {
  120. std::string nodelay;
  121. if (header.getValue("tcp_nodelay", nodelay) && nodelay == "1")
  122. {
  123. ROSCPP_LOG_DEBUG("Setting nodelay on socket [%d]", sock_);
  124. setNoDelay(true);
  125. }
  126. }
  127. void TransportTCP::setNoDelay(bool nodelay)
  128. {
  129. int flag = nodelay ? 1 : 0;
  130. int result = setsockopt(sock_, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
  131. if (result < 0)
  132. {
  133. ROS_ERROR("setsockopt failed to set TCP_NODELAY on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  134. }
  135. }
  136. void TransportTCP::setKeepAlive(bool use, uint32_t idle, uint32_t interval, uint32_t count)
  137. {
  138. if (use)
  139. {
  140. int val = 1;
  141. if (setsockopt(sock_, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<const char*>(&val), sizeof(val)) != 0)
  142. {
  143. ROS_DEBUG("setsockopt failed to set SO_KEEPALIVE on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  144. }
  145. /* cygwin SOL_TCP does not seem to support TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT */
  146. #if defined(SOL_TCP) && !defined(__CYGWIN__)
  147. val = idle;
  148. if (setsockopt(sock_, SOL_TCP, TCP_KEEPIDLE, &val, sizeof(val)) != 0)
  149. {
  150. ROS_DEBUG("setsockopt failed to set TCP_KEEPIDLE on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  151. }
  152. val = interval;
  153. if (setsockopt(sock_, SOL_TCP, TCP_KEEPINTVL, &val, sizeof(val)) != 0)
  154. {
  155. ROS_DEBUG("setsockopt failed to set TCP_KEEPINTVL on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  156. }
  157. val = count;
  158. if (setsockopt(sock_, SOL_TCP, TCP_KEEPCNT, &val, sizeof(val)) != 0)
  159. {
  160. ROS_DEBUG("setsockopt failed to set TCP_KEEPCNT on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  161. }
  162. #endif
  163. }
  164. else
  165. {
  166. int val = 0;
  167. if (setsockopt(sock_, SOL_SOCKET, SO_KEEPALIVE, reinterpret_cast<const char*>(&val), sizeof(val)) != 0)
  168. {
  169. ROS_DEBUG("setsockopt failed to set SO_KEEPALIVE on socket [%d] [%s]", sock_, cached_remote_host_.c_str());
  170. }
  171. }
  172. }
  173. bool TransportTCP::connect(const std::string& host, int port)
  174. {
  175. sock_ = socket(s_use_ipv6_ ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
  176. connected_host_ = host;
  177. connected_port_ = port;
  178. if (sock_ == ROS_INVALID_SOCKET)
  179. {
  180. ROS_ERROR("socket() failed with error [%s]", last_socket_error_string());
  181. return false;
  182. }
  183. setNonBlocking();
  184. sockaddr_storage sas;
  185. socklen_t sas_len;
  186. in_addr ina;
  187. in6_addr in6a;
  188. if (inet_pton(AF_INET, host.c_str(), &ina) == 1)
  189. {
  190. sockaddr_in *address = (sockaddr_in*) &sas;
  191. sas_len = sizeof(sockaddr_in);
  192. address->sin_family = AF_INET;
  193. address->sin_port = htons(port);
  194. address->sin_addr.s_addr = ina.s_addr;
  195. }
  196. else if (inet_pton(AF_INET6, host.c_str(), &in6a) == 1)
  197. {
  198. sockaddr_in6 *address = (sockaddr_in6*) &sas;
  199. sas_len = sizeof(sockaddr_in6);
  200. address->sin6_family = AF_INET6;
  201. address->sin6_port = htons(port);
  202. memcpy(address->sin6_addr.s6_addr, in6a.s6_addr, sizeof(in6a.s6_addr));
  203. }
  204. else
  205. {
  206. struct addrinfo* addr;
  207. struct addrinfo hints;
  208. memset(&hints, 0, sizeof(hints));
  209. hints.ai_family = AF_UNSPEC;
  210. if (getaddrinfo(host.c_str(), NULL, &hints, &addr) != 0)
  211. {
  212. close();
  213. ROS_ERROR("couldn't resolve publisher host [%s]", host.c_str());
  214. return false;
  215. }
  216. bool found = false;
  217. struct addrinfo* it = addr;
  218. char namebuf[128];
  219. for (; it; it = it->ai_next)
  220. {
  221. if (!s_use_ipv6_ && it->ai_family == AF_INET)
  222. {
  223. sockaddr_in *address = (sockaddr_in*) &sas;
  224. sas_len = sizeof(*address);
  225. memcpy(address, it->ai_addr, it->ai_addrlen);
  226. address->sin_family = it->ai_family;
  227. address->sin_port = htons(port);
  228. strcpy(namebuf, inet_ntoa(address->sin_addr));
  229. found = true;
  230. break;
  231. }
  232. if (s_use_ipv6_ && it->ai_family == AF_INET6)
  233. {
  234. sockaddr_in6 *address = (sockaddr_in6*) &sas;
  235. sas_len = sizeof(*address);
  236. memcpy(address, it->ai_addr, it->ai_addrlen);
  237. address->sin6_family = it->ai_family;
  238. address->sin6_port = htons((u_short) port);
  239. // TODO IPV6: does inet_ntop need other includes for Windows?
  240. inet_ntop(AF_INET6, (void*)&(address->sin6_addr), namebuf, sizeof(namebuf));
  241. found = true;
  242. break;
  243. }
  244. }
  245. freeaddrinfo(addr);
  246. if (!found)
  247. {
  248. ROS_ERROR("Couldn't resolve an address for [%s]\n", host.c_str());
  249. return false;
  250. }
  251. ROSCPP_LOG_DEBUG("Resolved publisher host [%s] to [%s] for socket [%d]", host.c_str(), namebuf, sock_);
  252. }
  253. int ret = ::connect(sock_, (sockaddr*) &sas, sas_len);
  254. // windows might need some time to sleep (input from service robotics hack) add this if testing proves it is necessary.
  255. ROS_ASSERT((flags_ & SYNCHRONOUS) || ret != 0);
  256. if (((flags_ & SYNCHRONOUS) && ret != 0) || // synchronous, connect() should return 0
  257. (!(flags_ & SYNCHRONOUS) && last_socket_error() != ROS_SOCKETS_ASYNCHRONOUS_CONNECT_RETURN)) // asynchronous, connect() should return -1 and WSAGetLastError()=WSAEWOULDBLOCK/errno=EINPROGRESS
  258. {
  259. ROSCPP_LOG_DEBUG("Connect to tcpros publisher [%s:%d] failed with error [%d, %s]", host.c_str(), port, ret, last_socket_error_string());
  260. close();
  261. return false;
  262. }
  263. // from daniel stonier:
  264. #ifdef WIN32
  265. // This is hackish, but windows fails at recv() if its slow to connect (e.g. happens with wireless)
  266. // recv() needs to check if its connected or not when its asynchronous?
  267. Sleep(100);
  268. #endif
  269. std::stringstream ss;
  270. ss << host << ":" << port << " on socket " << sock_;
  271. cached_remote_host_ = ss.str();
  272. if (!initializeSocket())
  273. {
  274. return false;
  275. }
  276. if (flags_ & SYNCHRONOUS)
  277. {
  278. ROSCPP_LOG_DEBUG("connect() succeeded to [%s:%d] on socket [%d]", host.c_str(), port, sock_);
  279. }
  280. else
  281. {
  282. ROSCPP_LOG_DEBUG("Async connect() in progress to [%s:%d] on socket [%d]", host.c_str(), port, sock_);
  283. }
  284. return true;
  285. }
  286. bool TransportTCP::listen(int port, int backlog, const AcceptCallback& accept_cb)
  287. {
  288. is_server_ = true;
  289. accept_cb_ = accept_cb;
  290. if (s_use_ipv6_)
  291. {
  292. sock_ = socket(AF_INET6, SOCK_STREAM, 0);
  293. sockaddr_in6 *address = (sockaddr_in6 *)&server_address_;
  294. address->sin6_family = AF_INET6;
  295. address->sin6_addr = in6addr_any;
  296. address->sin6_port = htons(port);
  297. sa_len_ = sizeof(sockaddr_in6);
  298. }
  299. else
  300. {
  301. sock_ = socket(AF_INET, SOCK_STREAM, 0);
  302. sockaddr_in *address = (sockaddr_in *)&server_address_;
  303. address->sin_family = AF_INET;
  304. address->sin_addr.s_addr = INADDR_ANY;
  305. address->sin_port = htons(port);
  306. sa_len_ = sizeof(sockaddr_in);
  307. }
  308. if (sock_ <= 0)
  309. {
  310. ROS_ERROR("socket() failed with error [%s]", last_socket_error_string());
  311. return false;
  312. }
  313. if (bind(sock_, (sockaddr *)&server_address_, sa_len_) < 0)
  314. {
  315. ROS_ERROR("bind() failed with error [%s]", last_socket_error_string());
  316. return false;
  317. }
  318. ::listen(sock_, backlog);
  319. getsockname(sock_, (sockaddr *)&server_address_, &sa_len_);
  320. switch (server_address_.ss_family)
  321. {
  322. case AF_INET:
  323. server_port_ = ntohs(((sockaddr_in *)&server_address_)->sin_port);
  324. break;
  325. case AF_INET6:
  326. server_port_ = ntohs(((sockaddr_in6 *)&server_address_)->sin6_port);
  327. break;
  328. }
  329. if (!initializeSocket())
  330. {
  331. return false;
  332. }
  333. if (!(flags_ & SYNCHRONOUS))
  334. {
  335. enableRead();
  336. }
  337. return true;
  338. }
  339. void TransportTCP::close()
  340. {
  341. Callback disconnect_cb;
  342. if (!closed_)
  343. {
  344. {
  345. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  346. if (!closed_)
  347. {
  348. closed_ = true;
  349. ROS_ASSERT(sock_ != ROS_INVALID_SOCKET);
  350. if (poll_set_)
  351. {
  352. poll_set_->delSocket(sock_);
  353. }
  354. ::shutdown(sock_, ROS_SOCKETS_SHUT_RDWR);
  355. if ( close_socket(sock_) != 0 )
  356. {
  357. ROS_ERROR("Error closing socket [%d]: [%s]", sock_, last_socket_error_string());
  358. } else
  359. {
  360. ROSCPP_LOG_DEBUG("TCP socket [%d] closed", sock_);
  361. }
  362. sock_ = ROS_INVALID_SOCKET;
  363. disconnect_cb = disconnect_cb_;
  364. disconnect_cb_ = Callback();
  365. read_cb_ = Callback();
  366. write_cb_ = Callback();
  367. accept_cb_ = AcceptCallback();
  368. }
  369. }
  370. }
  371. if (disconnect_cb)
  372. {
  373. disconnect_cb(shared_from_this());
  374. }
  375. }
  376. int32_t TransportTCP::read(uint8_t* buffer, uint32_t size)
  377. {
  378. {
  379. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  380. if (closed_)
  381. {
  382. ROSCPP_LOG_DEBUG("Tried to read on a closed socket [%d]", sock_);
  383. return -1;
  384. }
  385. }
  386. ROS_ASSERT(size > 0);
  387. // never read more than INT_MAX since this is the maximum we can report back with the current return type
  388. uint32_t read_size = std::min(size, static_cast<uint32_t>(INT_MAX));
  389. int num_bytes = ::recv(sock_, reinterpret_cast<char*>(buffer), read_size, 0);
  390. if (num_bytes < 0)
  391. {
  392. if ( !last_socket_error_is_would_block() ) // !WSAWOULDBLOCK / !EAGAIN && !EWOULDBLOCK
  393. {
  394. ROSCPP_LOG_DEBUG("recv() on socket [%d] failed with error [%s]", sock_, last_socket_error_string());
  395. close();
  396. }
  397. else
  398. {
  399. num_bytes = 0;
  400. }
  401. }
  402. else if (num_bytes == 0)
  403. {
  404. ROSCPP_LOG_DEBUG("Socket [%d] received 0/%u bytes, closing", sock_, size);
  405. close();
  406. return -1;
  407. }
  408. return num_bytes;
  409. }
  410. int32_t TransportTCP::write(uint8_t* buffer, uint32_t size)
  411. {
  412. {
  413. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  414. if (closed_)
  415. {
  416. ROSCPP_LOG_DEBUG("Tried to write on a closed socket [%d]", sock_);
  417. return -1;
  418. }
  419. }
  420. ROS_ASSERT(size > 0);
  421. // never write more than INT_MAX since this is the maximum we can report back with the current return type
  422. uint32_t writesize = std::min(size, static_cast<uint32_t>(INT_MAX));
  423. int num_bytes = ::send(sock_, reinterpret_cast<const char*>(buffer), writesize, 0);
  424. if (num_bytes < 0)
  425. {
  426. if ( !last_socket_error_is_would_block() )
  427. {
  428. ROSCPP_LOG_DEBUG("send() on socket [%d] failed with error [%s]", sock_, last_socket_error_string());
  429. close();
  430. }
  431. else
  432. {
  433. num_bytes = 0;
  434. }
  435. }
  436. return num_bytes;
  437. }
  438. void TransportTCP::enableRead()
  439. {
  440. ROS_ASSERT(!(flags_ & SYNCHRONOUS));
  441. {
  442. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  443. if (closed_)
  444. {
  445. return;
  446. }
  447. }
  448. if (!expecting_read_)
  449. {
  450. poll_set_->addEvents(sock_, POLLIN);
  451. expecting_read_ = true;
  452. }
  453. }
  454. void TransportTCP::disableRead()
  455. {
  456. ROS_ASSERT(!(flags_ & SYNCHRONOUS));
  457. {
  458. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  459. if (closed_)
  460. {
  461. return;
  462. }
  463. }
  464. if (expecting_read_)
  465. {
  466. poll_set_->delEvents(sock_, POLLIN);
  467. expecting_read_ = false;
  468. }
  469. }
  470. void TransportTCP::enableWrite()
  471. {
  472. ROS_ASSERT(!(flags_ & SYNCHRONOUS));
  473. {
  474. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  475. if (closed_)
  476. {
  477. return;
  478. }
  479. }
  480. if (!expecting_write_)
  481. {
  482. poll_set_->addEvents(sock_, POLLOUT);
  483. expecting_write_ = true;
  484. }
  485. }
  486. void TransportTCP::disableWrite()
  487. {
  488. ROS_ASSERT(!(flags_ & SYNCHRONOUS));
  489. {
  490. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  491. if (closed_)
  492. {
  493. return;
  494. }
  495. }
  496. if (expecting_write_)
  497. {
  498. poll_set_->delEvents(sock_, POLLOUT);
  499. expecting_write_ = false;
  500. }
  501. }
  502. TransportTCPPtr TransportTCP::accept()
  503. {
  504. ROS_ASSERT(is_server_);
  505. sockaddr client_address;
  506. socklen_t len = sizeof(client_address);
  507. int new_sock = ::accept(sock_, (sockaddr *)&client_address, &len);
  508. if (new_sock >= 0)
  509. {
  510. ROSCPP_LOG_DEBUG("Accepted connection on socket [%d], new socket [%d]", sock_, new_sock);
  511. TransportTCPPtr transport(new TransportTCP(poll_set_, flags_));
  512. if (!transport->setSocket(new_sock))
  513. {
  514. ROS_ERROR("Failed to set socket on transport for socket %d", new_sock);
  515. }
  516. return transport;
  517. }
  518. else
  519. {
  520. ROS_ERROR("accept() on socket [%d] failed with error [%s]", sock_, last_socket_error_string());
  521. }
  522. return TransportTCPPtr();
  523. }
  524. void TransportTCP::socketUpdate(int events)
  525. {
  526. {
  527. boost::recursive_mutex::scoped_lock lock(close_mutex_);
  528. if (closed_)
  529. {
  530. return;
  531. }
  532. // Handle read events before err/hup/nval, since there may be data left on the wire
  533. if ((events & POLLIN) && expecting_read_)
  534. {
  535. if (is_server_)
  536. {
  537. // Should not block here, because poll() said that it's ready
  538. // for reading
  539. TransportTCPPtr transport = accept();
  540. if (transport)
  541. {
  542. ROS_ASSERT(accept_cb_);
  543. accept_cb_(transport);
  544. }
  545. }
  546. else
  547. {
  548. if (read_cb_)
  549. {
  550. read_cb_(shared_from_this());
  551. }
  552. }
  553. }
  554. if ((events & POLLOUT) && expecting_write_)
  555. {
  556. if (write_cb_)
  557. {
  558. write_cb_(shared_from_this());
  559. }
  560. }
  561. }
  562. if((events & POLLERR) ||
  563. (events & POLLHUP) ||
  564. (events & POLLNVAL))
  565. {
  566. uint32_t error = -1;
  567. socklen_t len = sizeof(error);
  568. if (getsockopt(sock_, SOL_SOCKET, SO_ERROR, reinterpret_cast<char*>(&error), &len) < 0)
  569. {
  570. ROSCPP_LOG_DEBUG("getsockopt failed on socket [%d]", sock_);
  571. }
  572. #ifdef _MSC_VER
  573. char err[60];
  574. strerror_s(err,60,error);
  575. ROSCPP_LOG_DEBUG("Socket %d closed with (ERR|HUP|NVAL) events %d: %s", sock_, events, err);
  576. #else
  577. ROSCPP_LOG_DEBUG("Socket %d closed with (ERR|HUP|NVAL) events %d: %s", sock_, events, strerror(error));
  578. #endif
  579. close();
  580. }
  581. }
  582. std::string TransportTCP::getTransportInfo()
  583. {
  584. return "TCPROS connection to [" + cached_remote_host_ + "]";
  585. }
  586. std::string TransportTCP::getClientURI()
  587. {
  588. ROS_ASSERT(!is_server_);
  589. sockaddr_storage sas;
  590. socklen_t sas_len = sizeof(sas);
  591. getpeername(sock_, (sockaddr *)&sas, &sas_len);
  592. sockaddr_in *sin = (sockaddr_in *)&sas;
  593. sockaddr_in6 *sin6 = (sockaddr_in6 *)&sas;
  594. char namebuf[128];
  595. int port;
  596. switch (sas.ss_family)
  597. {
  598. case AF_INET:
  599. port = ntohs(sin->sin_port);
  600. strcpy(namebuf, inet_ntoa(sin->sin_addr));
  601. break;
  602. case AF_INET6:
  603. port = ntohs(sin6->sin6_port);
  604. inet_ntop(AF_INET6, (void*)&(sin6->sin6_addr), namebuf, sizeof(namebuf));
  605. break;
  606. default:
  607. namebuf[0] = 0;
  608. port = 0;
  609. break;
  610. }
  611. std::string ip = namebuf;
  612. std::stringstream uri;
  613. uri << ip << ":" << port;
  614. return uri.str();
  615. }
  616. } // namespace ros