PageRenderTime 45ms CodeModel.GetById 11ms RepoModel.GetById 1ms app.codeStats 0ms

/Client/thrift/transport/TSocket.cpp

https://bitbucket.org/pawelulita/zpr_projekt
C++ | 823 lines | 617 code | 125 blank | 81 comment | 150 complexity | 847ed42a0364d5509b6cbde9e6aad3c2 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include <config.h>
  21. #endif
  22. #include <cstring>
  23. #include <sstream>
  24. #ifdef HAVE_SYS_SOCKET_H
  25. #include <sys/socket.h>
  26. #endif
  27. #ifdef HAVE_SYS_UN_H
  28. #include <sys/un.h>
  29. #endif
  30. #ifdef HAVE_SYS_POLL_H
  31. #include <sys/poll.h>
  32. #endif
  33. #include <sys/types.h>
  34. #ifdef HAVE_ARPA_INET_H
  35. #include <arpa/inet.h>
  36. #endif
  37. #ifdef HAVE_NETINET_IN_H
  38. #include <netinet/in.h>
  39. #include <netinet/tcp.h>
  40. #endif
  41. #ifdef HAVE_UNISTD_H
  42. #include <unistd.h>
  43. #endif
  44. #include <errno.h>
  45. #include <fcntl.h>
  46. #include <thrift/concurrency/Monitor.h>
  47. #include "TSocket.h"
  48. #include "TTransportException.h"
  49. #ifndef SOCKOPT_CAST_T
  50. # ifndef _WIN32
  51. # define SOCKOPT_CAST_T void
  52. # else
  53. # define SOCKOPT_CAST_T char
  54. # endif // _WIN32
  55. #endif
  56. template<class T>
  57. inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
  58. return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
  59. }
  60. template<class T>
  61. inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
  62. return reinterpret_cast<SOCKOPT_CAST_T*>(v);
  63. }
  64. namespace apache { namespace thrift { namespace transport {
  65. using namespace std;
  66. // Global var to track total socket sys calls
  67. uint32_t g_socket_syscalls = 0;
  68. /**
  69. * TSocket implementation.
  70. *
  71. */
  72. TSocket::TSocket(string host, int port) :
  73. host_(host),
  74. port_(port),
  75. path_(""),
  76. socket_(-1),
  77. connTimeout_(0),
  78. sendTimeout_(0),
  79. recvTimeout_(0),
  80. lingerOn_(1),
  81. lingerVal_(0),
  82. noDelay_(1),
  83. maxRecvRetries_(5) {
  84. recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
  85. recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
  86. }
  87. TSocket::TSocket(string path) :
  88. host_(""),
  89. port_(0),
  90. path_(path),
  91. socket_(-1),
  92. connTimeout_(0),
  93. sendTimeout_(0),
  94. recvTimeout_(0),
  95. lingerOn_(1),
  96. lingerVal_(0),
  97. noDelay_(1),
  98. maxRecvRetries_(5) {
  99. recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
  100. recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
  101. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  102. }
  103. TSocket::TSocket() :
  104. host_(""),
  105. port_(0),
  106. path_(""),
  107. socket_(-1),
  108. connTimeout_(0),
  109. sendTimeout_(0),
  110. recvTimeout_(0),
  111. lingerOn_(1),
  112. lingerVal_(0),
  113. noDelay_(1),
  114. maxRecvRetries_(5) {
  115. recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
  116. recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
  117. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  118. }
  119. TSocket::TSocket(SOCKET socket) :
  120. host_(""),
  121. port_(0),
  122. path_(""),
  123. socket_(socket),
  124. connTimeout_(0),
  125. sendTimeout_(0),
  126. recvTimeout_(0),
  127. lingerOn_(1),
  128. lingerVal_(0),
  129. noDelay_(1),
  130. maxRecvRetries_(5) {
  131. recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
  132. recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
  133. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  134. }
  135. TSocket::~TSocket() {
  136. close();
  137. }
  138. bool TSocket::isOpen() {
  139. return (socket_ != -1);
  140. }
  141. bool TSocket::peek() {
  142. if (!isOpen()) {
  143. return false;
  144. }
  145. uint8_t buf;
  146. int r = recv(socket_, cast_sockopt(&buf), 1, MSG_PEEK);
  147. if (r == -1) {
  148. int errno_copy = errno;
  149. #if defined __FreeBSD__ || defined __MACH__
  150. /* shigin:
  151. * freebsd returns -1 and ECONNRESET if socket was closed by
  152. * the other side
  153. */
  154. if (errno_copy == ECONNRESET)
  155. {
  156. close();
  157. return false;
  158. }
  159. #endif
  160. GlobalOutput.perror("TSocket::peek() recv() " + getSocketInfo(), errno_copy);
  161. throw TTransportException(TTransportException::UNKNOWN, "recv()", errno_copy);
  162. }
  163. return (r > 0);
  164. }
  165. void TSocket::openConnection(struct addrinfo *res) {
  166. if (isOpen()) {
  167. return;
  168. }
  169. if (! path_.empty()) {
  170. socket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
  171. } else {
  172. socket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  173. }
  174. if (socket_ == -1) {
  175. int errno_copy = errno;
  176. GlobalOutput.perror("TSocket::open() socket() " + getSocketInfo(), errno_copy);
  177. throw TTransportException(TTransportException::NOT_OPEN, "socket()", errno_copy);
  178. }
  179. // Send timeout
  180. if (sendTimeout_ > 0) {
  181. setSendTimeout(sendTimeout_);
  182. }
  183. // Recv timeout
  184. if (recvTimeout_ > 0) {
  185. setRecvTimeout(recvTimeout_);
  186. }
  187. // Linger
  188. setLinger(lingerOn_, lingerVal_);
  189. // No delay
  190. setNoDelay(noDelay_);
  191. // Uses a low min RTO if asked to.
  192. #ifdef TCP_LOW_MIN_RTO
  193. if (getUseLowMinRto()) {
  194. int one = 1;
  195. setsockopt(socket_, IPPROTO_TCP, TCP_LOW_MIN_RTO, &one, sizeof(one));
  196. }
  197. #endif
  198. // Set the socket to be non blocking for connect if a timeout exists
  199. int flags = fcntl(socket_, F_GETFL, 0);
  200. if (connTimeout_ > 0) {
  201. if (-1 == fcntl(socket_, F_SETFL, flags | O_NONBLOCK)) {
  202. int errno_copy = errno;
  203. GlobalOutput.perror("TSocket::open() fcntl() " + getSocketInfo(), errno_copy);
  204. throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed", errno_copy);
  205. }
  206. } else {
  207. if (-1 == fcntl(socket_, F_SETFL, flags & ~O_NONBLOCK)) {
  208. int errno_copy = errno;
  209. GlobalOutput.perror("TSocket::open() fcntl " + getSocketInfo(), errno_copy);
  210. throw TTransportException(TTransportException::NOT_OPEN, "fcntl() failed", errno_copy);
  211. }
  212. }
  213. // Connect the socket
  214. int ret;
  215. if (! path_.empty()) {
  216. #ifndef _WIN32
  217. struct sockaddr_un address;
  218. socklen_t len;
  219. if (path_.length() > sizeof(address.sun_path)) {
  220. int errno_copy = errno;
  221. GlobalOutput.perror("TSocket::open() Unix Domain socket path too long", errno_copy);
  222. throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
  223. }
  224. address.sun_family = AF_UNIX;
  225. snprintf(address.sun_path, sizeof(address.sun_path), "%s", path_.c_str());
  226. len = sizeof(address);
  227. ret = connect(socket_, (struct sockaddr *) &address, len);
  228. #else
  229. GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
  230. throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path not supported");
  231. #endif
  232. } else {
  233. ret = connect(socket_, res->ai_addr, static_cast<int>(res->ai_addrlen));
  234. }
  235. // success case
  236. if (ret == 0) {
  237. goto done;
  238. }
  239. if ((errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
  240. int errno_copy = errno;
  241. GlobalOutput.perror("TSocket::open() connect() " + getSocketInfo(), errno_copy);
  242. throw TTransportException(TTransportException::NOT_OPEN, "connect() failed", errno_copy);
  243. }
  244. struct pollfd fds[1];
  245. std::memset(fds, 0 , sizeof(fds));
  246. fds[0].fd = socket_;
  247. fds[0].events = POLLOUT;
  248. ret = poll(fds, 1, connTimeout_);
  249. if (ret > 0) {
  250. // Ensure the socket is connected and that there are no errors set
  251. int val;
  252. socklen_t lon;
  253. lon = sizeof(int);
  254. int ret2 = getsockopt(socket_, SOL_SOCKET, SO_ERROR, cast_sockopt(&val), &lon);
  255. if (ret2 == -1) {
  256. int errno_copy = errno;
  257. GlobalOutput.perror("TSocket::open() getsockopt() " + getSocketInfo(), errno_copy);
  258. throw TTransportException(TTransportException::NOT_OPEN, "getsockopt()", errno_copy);
  259. }
  260. // no errors on socket, go to town
  261. if (val == 0) {
  262. goto done;
  263. }
  264. GlobalOutput.perror("TSocket::open() error on socket (after poll) " + getSocketInfo(), val);
  265. throw TTransportException(TTransportException::NOT_OPEN, "socket open() error", val);
  266. } else if (ret == 0) {
  267. // socket timed out
  268. string errStr = "TSocket::open() timed out " + getSocketInfo();
  269. GlobalOutput(errStr.c_str());
  270. throw TTransportException(TTransportException::NOT_OPEN, "open() timed out");
  271. } else {
  272. // error on poll()
  273. int errno_copy = errno;
  274. GlobalOutput.perror("TSocket::open() poll() " + getSocketInfo(), errno_copy);
  275. throw TTransportException(TTransportException::NOT_OPEN, "poll() failed", errno_copy);
  276. }
  277. done:
  278. // Set socket back to normal mode (blocking)
  279. fcntl(socket_, F_SETFL, flags);
  280. if (path_.empty()) {
  281. setCachedAddress(res->ai_addr, static_cast<socklen_t>(res->ai_addrlen));
  282. }
  283. }
  284. void TSocket::open() {
  285. if (isOpen()) {
  286. return;
  287. }
  288. if (! path_.empty()) {
  289. unix_open();
  290. } else {
  291. local_open();
  292. }
  293. }
  294. void TSocket::unix_open(){
  295. if (! path_.empty()) {
  296. // Unix Domain SOcket does not need addrinfo struct, so we pass NULL
  297. openConnection(NULL);
  298. }
  299. }
  300. void TSocket::local_open(){
  301. #ifdef _WIN32
  302. TWinsockSingleton::create();
  303. #endif // _WIN32
  304. if (isOpen()) {
  305. return;
  306. }
  307. // Validate port number
  308. if (port_ < 0 || port_ > 0xFFFF) {
  309. throw TTransportException(TTransportException::NOT_OPEN, "Specified port is invalid");
  310. }
  311. struct addrinfo hints, *res, *res0;
  312. res = NULL;
  313. res0 = NULL;
  314. int error;
  315. char port[sizeof("65535")];
  316. std::memset(&hints, 0, sizeof(hints));
  317. hints.ai_family = PF_UNSPEC;
  318. hints.ai_socktype = SOCK_STREAM;
  319. hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
  320. sprintf(port, "%d", port_);
  321. error = getaddrinfo(host_.c_str(), port, &hints, &res0);
  322. if (error) {
  323. string errStr = "TSocket::open() getaddrinfo() " + getSocketInfo() /*+ string(gai_strerror(error))*/;
  324. GlobalOutput(errStr.c_str());
  325. close();
  326. throw TTransportException(TTransportException::NOT_OPEN, "Could not resolve host for client socket.");
  327. }
  328. // Cycle through all the returned addresses until one
  329. // connects or push the exception up.
  330. for (res = res0; res; res = res->ai_next) {
  331. try {
  332. openConnection(res);
  333. break;
  334. } catch (TTransportException&) {
  335. if (res->ai_next) {
  336. close();
  337. } else {
  338. close();
  339. freeaddrinfo(res0); // cleanup on failure
  340. throw;
  341. }
  342. }
  343. }
  344. // Free address structure memory
  345. freeaddrinfo(res0);
  346. }
  347. void TSocket::close() {
  348. if (socket_ != -1) {
  349. #ifdef _WIN32
  350. shutdown(socket_, SD_BOTH);
  351. ::closesocket(socket_);
  352. #else
  353. shutdown(socket_, SHUT_RDWR);
  354. ::close(socket_);
  355. #endif
  356. }
  357. socket_ = -1;
  358. }
  359. void TSocket::setSocketFD(int socket) {
  360. if (socket_ != -1) {
  361. close();
  362. }
  363. socket_ = socket;
  364. }
  365. uint32_t TSocket::read(uint8_t* buf, uint32_t len) {
  366. if (socket_ == -1) {
  367. throw TTransportException(TTransportException::NOT_OPEN, "Called read on non-open socket");
  368. }
  369. int32_t retries = 0;
  370. // EAGAIN can be signalled both when a timeout has occurred and when
  371. // the system is out of resources (an awesome undocumented feature).
  372. // The following is an approximation of the time interval under which
  373. // EAGAIN is taken to indicate an out of resources error.
  374. uint32_t eagainThresholdMicros = 0;
  375. if (recvTimeout_) {
  376. // if a readTimeout is specified along with a max number of recv retries, then
  377. // the threshold will ensure that the read timeout is not exceeded even in the
  378. // case of resource errors
  379. eagainThresholdMicros = (recvTimeout_*1000)/ ((maxRecvRetries_>0) ? maxRecvRetries_ : 2);
  380. }
  381. try_again:
  382. // Read from the socket
  383. struct timeval begin;
  384. if (recvTimeout_ > 0) {
  385. gettimeofday(&begin, NULL);
  386. } else {
  387. // if there is no read timeout we don't need the TOD to determine whether
  388. // an EAGAIN is due to a timeout or an out-of-resource condition.
  389. begin.tv_sec = begin.tv_usec = 0;
  390. }
  391. int got = recv(socket_, cast_sockopt(buf), len, 0);
  392. int errno_copy = errno; //gettimeofday can change errno
  393. ++g_socket_syscalls;
  394. // Check for error on read
  395. if (got < 0) {
  396. if (errno_copy == EAGAIN) {
  397. // if no timeout we can assume that resource exhaustion has occurred.
  398. if (recvTimeout_ == 0) {
  399. throw TTransportException(TTransportException::TIMED_OUT,
  400. "EAGAIN (unavailable resources)");
  401. }
  402. // check if this is the lack of resources or timeout case
  403. struct timeval end;
  404. gettimeofday(&end, NULL);
  405. uint32_t readElapsedMicros = (((end.tv_sec - begin.tv_sec) * 1000 * 1000)
  406. + (((uint64_t)(end.tv_usec - begin.tv_usec))));
  407. if (!eagainThresholdMicros || (readElapsedMicros < eagainThresholdMicros)) {
  408. if (retries++ < maxRecvRetries_) {
  409. usleep(50);
  410. goto try_again;
  411. } else {
  412. throw TTransportException(TTransportException::TIMED_OUT,
  413. "EAGAIN (unavailable resources)");
  414. }
  415. } else {
  416. // infer that timeout has been hit
  417. throw TTransportException(TTransportException::TIMED_OUT,
  418. "EAGAIN (timed out)");
  419. }
  420. }
  421. // If interrupted, try again
  422. if (errno_copy == EINTR && retries++ < maxRecvRetries_) {
  423. goto try_again;
  424. }
  425. #if defined __FreeBSD__ || defined __MACH__
  426. if (errno_copy == ECONNRESET) {
  427. /* shigin: freebsd doesn't follow POSIX semantic of recv and fails with
  428. * ECONNRESET if peer performed shutdown
  429. * edhall: eliminated close() since we do that in the destructor.
  430. */
  431. return 0;
  432. }
  433. #endif
  434. #ifdef _WIN32
  435. if(errno_copy == WSAECONNRESET) {
  436. return 0; // EOF
  437. }
  438. #endif
  439. // Now it's not a try again case, but a real probblez
  440. GlobalOutput.perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
  441. // If we disconnect with no linger time
  442. if (errno_copy == ECONNRESET) {
  443. throw TTransportException(TTransportException::NOT_OPEN, "ECONNRESET");
  444. }
  445. // This ish isn't open
  446. if (errno_copy == ENOTCONN) {
  447. throw TTransportException(TTransportException::NOT_OPEN, "ENOTCONN");
  448. }
  449. // Timed out!
  450. if (errno_copy == ETIMEDOUT) {
  451. throw TTransportException(TTransportException::TIMED_OUT, "ETIMEDOUT");
  452. }
  453. // Some other error, whatevz
  454. throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
  455. }
  456. // The remote host has closed the socket
  457. if (got == 0) {
  458. // edhall: we used to call close() here, but our caller may want to deal
  459. // with the socket fd and we'll close() in our destructor in any case.
  460. return 0;
  461. }
  462. // Pack data into string
  463. return got;
  464. }
  465. void TSocket::write(const uint8_t* buf, uint32_t len) {
  466. uint32_t sent = 0;
  467. while (sent < len) {
  468. uint32_t b = write_partial(buf + sent, len - sent);
  469. if (b == 0) {
  470. // This should only happen if the timeout set with SO_SNDTIMEO expired.
  471. // Raise an exception.
  472. throw TTransportException(TTransportException::TIMED_OUT,
  473. "send timeout expired");
  474. }
  475. sent += b;
  476. }
  477. }
  478. uint32_t TSocket::write_partial(const uint8_t* buf, uint32_t len) {
  479. if (socket_ == -1) {
  480. throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open socket");
  481. }
  482. uint32_t sent = 0;
  483. int flags = 0;
  484. #ifdef MSG_NOSIGNAL
  485. // Note the use of MSG_NOSIGNAL to suppress SIGPIPE errors, instead we
  486. // check for the EPIPE return condition and close the socket in that case
  487. flags |= MSG_NOSIGNAL;
  488. #endif // ifdef MSG_NOSIGNAL
  489. int b = send(socket_, const_cast_sockopt(buf + sent), len - sent, flags);
  490. ++g_socket_syscalls;
  491. if (b < 0) {
  492. if (errno == EWOULDBLOCK || errno == EAGAIN) {
  493. return 0;
  494. }
  495. // Fail on a send error
  496. int errno_copy = errno;
  497. GlobalOutput.perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);
  498. if (errno_copy == EPIPE || errno_copy == ECONNRESET || errno_copy == ENOTCONN) {
  499. close();
  500. throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);
  501. }
  502. throw TTransportException(TTransportException::UNKNOWN, "write() send()", errno_copy);
  503. }
  504. // Fail on blocked send
  505. if (b == 0) {
  506. throw TTransportException(TTransportException::NOT_OPEN, "Socket send returned 0.");
  507. }
  508. return b;
  509. }
  510. std::string TSocket::getHost() {
  511. return host_;
  512. }
  513. int TSocket::getPort() {
  514. return port_;
  515. }
  516. void TSocket::setHost(string host) {
  517. host_ = host;
  518. }
  519. void TSocket::setPort(int port) {
  520. port_ = port;
  521. }
  522. void TSocket::setLinger(bool on, int linger) {
  523. lingerOn_ = on;
  524. lingerVal_ = linger;
  525. if (socket_ == -1) {
  526. return;
  527. }
  528. struct linger l = {(lingerOn_ ? 1 : 0), lingerVal_};
  529. int ret = setsockopt(socket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&l), sizeof(l));
  530. if (ret == -1) {
  531. int errno_copy = errno; // Copy errno because we're allocating memory.
  532. GlobalOutput.perror("TSocket::setLinger() setsockopt() " + getSocketInfo(), errno_copy);
  533. }
  534. }
  535. void TSocket::setNoDelay(bool noDelay) {
  536. noDelay_ = noDelay;
  537. if (socket_ == -1 || !path_.empty()) {
  538. return;
  539. }
  540. // Set socket to NODELAY
  541. int v = noDelay_ ? 1 : 0;
  542. int ret = setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&v), sizeof(v));
  543. if (ret == -1) {
  544. int errno_copy = errno; // Copy errno because we're allocating memory.
  545. GlobalOutput.perror("TSocket::setNoDelay() setsockopt() " + getSocketInfo(), errno_copy);
  546. }
  547. }
  548. void TSocket::setConnTimeout(int ms) {
  549. connTimeout_ = ms;
  550. }
  551. void TSocket::setRecvTimeout(int ms) {
  552. if (ms < 0) {
  553. char errBuf[512];
  554. sprintf(errBuf, "TSocket::setRecvTimeout with negative input: %d\n", ms);
  555. GlobalOutput(errBuf);
  556. return;
  557. }
  558. recvTimeout_ = ms;
  559. if (socket_ == -1) {
  560. return;
  561. }
  562. recvTimeval_.tv_sec = (int)(recvTimeout_/1000);
  563. recvTimeval_.tv_usec = (int)((recvTimeout_%1000)*1000);
  564. // Copy because poll may modify
  565. struct timeval r = recvTimeval_;
  566. int ret = setsockopt(socket_, SOL_SOCKET, SO_RCVTIMEO, cast_sockopt(&r), sizeof(r));
  567. if (ret == -1) {
  568. int errno_copy = errno; // Copy errno because we're allocating memory.
  569. GlobalOutput.perror("TSocket::setRecvTimeout() setsockopt() " + getSocketInfo(), errno_copy);
  570. }
  571. }
  572. void TSocket::setSendTimeout(int ms) {
  573. if (ms < 0) {
  574. char errBuf[512];
  575. sprintf(errBuf, "TSocket::setSendTimeout with negative input: %d\n", ms);
  576. GlobalOutput(errBuf);
  577. return;
  578. }
  579. sendTimeout_ = ms;
  580. if (socket_ == -1) {
  581. return;
  582. }
  583. struct timeval s = {(int)(sendTimeout_/1000),
  584. (int)((sendTimeout_%1000)*1000)};
  585. int ret = setsockopt(socket_, SOL_SOCKET, SO_SNDTIMEO, cast_sockopt(&s), sizeof(s));
  586. if (ret == -1) {
  587. int errno_copy = errno; // Copy errno because we're allocating memory.
  588. GlobalOutput.perror("TSocket::setSendTimeout() setsockopt() " + getSocketInfo(), errno_copy);
  589. }
  590. }
  591. void TSocket::setMaxRecvRetries(int maxRecvRetries) {
  592. maxRecvRetries_ = maxRecvRetries;
  593. }
  594. string TSocket::getSocketInfo() {
  595. std::ostringstream oss;
  596. if (host_.empty() || port_ == 0) {
  597. oss << "<Host: " << getPeerAddress();
  598. oss << " Port: " << getPeerPort() << ">";
  599. } else {
  600. oss << "<Host: " << host_ << " Port: " << port_ << ">";
  601. }
  602. return oss.str();
  603. }
  604. std::string TSocket::getPeerHost() {
  605. if (peerHost_.empty() && path_.empty()) {
  606. struct sockaddr_storage addr;
  607. struct sockaddr* addrPtr;
  608. socklen_t addrLen;
  609. if (socket_ == -1) {
  610. return host_;
  611. }
  612. addrPtr = getCachedAddress(&addrLen);
  613. if (addrPtr == NULL) {
  614. addrLen = sizeof(addr);
  615. if (getpeername(socket_, (sockaddr*) &addr, &addrLen) != 0) {
  616. return peerHost_;
  617. }
  618. addrPtr = (sockaddr*)&addr;
  619. setCachedAddress(addrPtr, addrLen);
  620. }
  621. char clienthost[NI_MAXHOST];
  622. char clientservice[NI_MAXSERV];
  623. getnameinfo((sockaddr*) addrPtr, addrLen,
  624. clienthost, sizeof(clienthost),
  625. clientservice, sizeof(clientservice), 0);
  626. peerHost_ = clienthost;
  627. }
  628. return peerHost_;
  629. }
  630. std::string TSocket::getPeerAddress() {
  631. if (peerAddress_.empty() && path_.empty()) {
  632. struct sockaddr_storage addr;
  633. struct sockaddr* addrPtr;
  634. socklen_t addrLen;
  635. if (socket_ == -1) {
  636. return peerAddress_;
  637. }
  638. addrPtr = getCachedAddress(&addrLen);
  639. if (addrPtr == NULL) {
  640. addrLen = sizeof(addr);
  641. if (getpeername(socket_, (sockaddr*) &addr, &addrLen) != 0) {
  642. return peerAddress_;
  643. }
  644. addrPtr = (sockaddr*)&addr;
  645. setCachedAddress(addrPtr, addrLen);
  646. }
  647. char clienthost[NI_MAXHOST];
  648. char clientservice[NI_MAXSERV];
  649. getnameinfo(addrPtr, addrLen,
  650. clienthost, sizeof(clienthost),
  651. clientservice, sizeof(clientservice),
  652. NI_NUMERICHOST|NI_NUMERICSERV);
  653. peerAddress_ = clienthost;
  654. peerPort_ = std::atoi(clientservice);
  655. }
  656. return peerAddress_;
  657. }
  658. int TSocket::getPeerPort() {
  659. getPeerAddress();
  660. return peerPort_;
  661. }
  662. void TSocket::setCachedAddress(const sockaddr* addr, socklen_t len) {
  663. if (!path_.empty()) {
  664. return;
  665. }
  666. switch (addr->sa_family) {
  667. case AF_INET:
  668. if (len == sizeof(sockaddr_in)) {
  669. memcpy((void*)&cachedPeerAddr_.ipv4, (void*)addr, len);
  670. }
  671. break;
  672. case AF_INET6:
  673. if (len == sizeof(sockaddr_in6)) {
  674. memcpy((void*)&cachedPeerAddr_.ipv6, (void*)addr, len);
  675. }
  676. break;
  677. }
  678. }
  679. sockaddr* TSocket::getCachedAddress(socklen_t* len) const {
  680. switch (cachedPeerAddr_.ipv4.sin_family) {
  681. case AF_INET:
  682. *len = sizeof(sockaddr_in);
  683. return (sockaddr*) &cachedPeerAddr_.ipv4;
  684. case AF_INET6:
  685. *len = sizeof(sockaddr_in6);
  686. return (sockaddr*) &cachedPeerAddr_.ipv6;
  687. default:
  688. return NULL;
  689. }
  690. }
  691. bool TSocket::useLowMinRto_ = false;
  692. void TSocket::setUseLowMinRto(bool useLowMinRto) {
  693. useLowMinRto_ = useLowMinRto;
  694. }
  695. bool TSocket::getUseLowMinRto() {
  696. return useLowMinRto_;
  697. }
  698. }}} // apache::thrift::transport