PageRenderTime 47ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/cpp/src/thrift/transport/TSocket.cpp

https://gitlab.com/peter.tiedemann/thrift
C++ | 933 lines | 721 code | 132 blank | 80 comment | 167 complexity | f1b45ee554ab4e82e891ab0f358bdfc1 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. #include <thrift/thrift-config.h>
  20. #include <cstring>
  21. #include <sstream>
  22. #ifdef HAVE_SYS_SOCKET_H
  23. #include <sys/socket.h>
  24. #endif
  25. #ifdef HAVE_SYS_UN_H
  26. #include <sys/un.h>
  27. #endif
  28. #ifdef HAVE_SYS_POLL_H
  29. #include <sys/poll.h>
  30. #endif
  31. #include <sys/types.h>
  32. #ifdef HAVE_NETINET_IN_H
  33. #include <netinet/in.h>
  34. #include <netinet/tcp.h>
  35. #endif
  36. #ifdef HAVE_UNISTD_H
  37. #include <unistd.h>
  38. #endif
  39. #include <fcntl.h>
  40. #include <thrift/concurrency/Monitor.h>
  41. #include <thrift/transport/TSocket.h>
  42. #include <thrift/transport/TTransportException.h>
  43. #include <thrift/transport/PlatformSocket.h>
  44. #ifndef SOCKOPT_CAST_T
  45. #ifndef _WIN32
  46. #define SOCKOPT_CAST_T void
  47. #else
  48. #define SOCKOPT_CAST_T char
  49. #endif // _WIN32
  50. #endif
  51. template <class T>
  52. inline const SOCKOPT_CAST_T* const_cast_sockopt(const T* v) {
  53. return reinterpret_cast<const SOCKOPT_CAST_T*>(v);
  54. }
  55. template <class T>
  56. inline SOCKOPT_CAST_T* cast_sockopt(T* v) {
  57. return reinterpret_cast<SOCKOPT_CAST_T*>(v);
  58. }
  59. namespace apache {
  60. namespace thrift {
  61. namespace transport {
  62. using namespace std;
  63. /**
  64. * TSocket implementation.
  65. *
  66. */
  67. TSocket::TSocket(const string& host, int port)
  68. : host_(host),
  69. port_(port),
  70. path_(""),
  71. socket_(THRIFT_INVALID_SOCKET),
  72. connTimeout_(0),
  73. sendTimeout_(0),
  74. recvTimeout_(0),
  75. keepAlive_(false),
  76. lingerOn_(1),
  77. lingerVal_(0),
  78. noDelay_(1),
  79. maxRecvRetries_(5) {
  80. }
  81. TSocket::TSocket(const string& path)
  82. : host_(""),
  83. port_(0),
  84. path_(path),
  85. socket_(THRIFT_INVALID_SOCKET),
  86. connTimeout_(0),
  87. sendTimeout_(0),
  88. recvTimeout_(0),
  89. keepAlive_(false),
  90. lingerOn_(1),
  91. lingerVal_(0),
  92. noDelay_(1),
  93. maxRecvRetries_(5) {
  94. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  95. }
  96. TSocket::TSocket()
  97. : host_(""),
  98. port_(0),
  99. path_(""),
  100. socket_(THRIFT_INVALID_SOCKET),
  101. connTimeout_(0),
  102. sendTimeout_(0),
  103. recvTimeout_(0),
  104. keepAlive_(false),
  105. lingerOn_(1),
  106. lingerVal_(0),
  107. noDelay_(1),
  108. maxRecvRetries_(5) {
  109. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  110. }
  111. TSocket::TSocket(THRIFT_SOCKET socket)
  112. : host_(""),
  113. port_(0),
  114. path_(""),
  115. socket_(socket),
  116. connTimeout_(0),
  117. sendTimeout_(0),
  118. recvTimeout_(0),
  119. keepAlive_(false),
  120. lingerOn_(1),
  121. lingerVal_(0),
  122. noDelay_(1),
  123. maxRecvRetries_(5) {
  124. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  125. #ifdef SO_NOSIGPIPE
  126. {
  127. int one = 1;
  128. setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
  129. }
  130. #endif
  131. }
  132. TSocket::TSocket(THRIFT_SOCKET socket, boost::shared_ptr<THRIFT_SOCKET> interruptListener)
  133. : host_(""),
  134. port_(0),
  135. path_(""),
  136. socket_(socket),
  137. interruptListener_(interruptListener),
  138. connTimeout_(0),
  139. sendTimeout_(0),
  140. recvTimeout_(0),
  141. keepAlive_(false),
  142. lingerOn_(1),
  143. lingerVal_(0),
  144. noDelay_(1),
  145. maxRecvRetries_(5) {
  146. cachedPeerAddr_.ipv4.sin_family = AF_UNSPEC;
  147. #ifdef SO_NOSIGPIPE
  148. {
  149. int one = 1;
  150. setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
  151. }
  152. #endif
  153. }
  154. TSocket::~TSocket() {
  155. close();
  156. }
  157. bool TSocket::isOpen() {
  158. return (socket_ != THRIFT_INVALID_SOCKET);
  159. }
  160. bool TSocket::peek() {
  161. if (!isOpen()) {
  162. return false;
  163. }
  164. if (interruptListener_) {
  165. for (int retries = 0;;) {
  166. struct THRIFT_POLLFD fds[2];
  167. std::memset(fds, 0, sizeof(fds));
  168. fds[0].fd = socket_;
  169. fds[0].events = THRIFT_POLLIN;
  170. fds[1].fd = *(interruptListener_.get());
  171. fds[1].events = THRIFT_POLLIN;
  172. int ret = THRIFT_POLL(fds, 2, (recvTimeout_ == 0) ? -1 : recvTimeout_);
  173. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  174. if (ret < 0) {
  175. // error cases
  176. if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
  177. continue;
  178. }
  179. GlobalOutput.perror("TSocket::peek() THRIFT_POLL() ", errno_copy);
  180. throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
  181. } else if (ret > 0) {
  182. // Check the interruptListener
  183. if (fds[1].revents & THRIFT_POLLIN) {
  184. return false;
  185. }
  186. // There must be data or a disconnection, fall through to the PEEK
  187. break;
  188. } else {
  189. // timeout
  190. return false;
  191. }
  192. }
  193. }
  194. // Check to see if data is available or if the remote side closed
  195. uint8_t buf;
  196. int r = static_cast<int>(recv(socket_, cast_sockopt(&buf), 1, MSG_PEEK));
  197. if (r == -1) {
  198. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  199. #if defined __FreeBSD__ || defined __MACH__
  200. /* shigin:
  201. * freebsd returns -1 and THRIFT_ECONNRESET if socket was closed by
  202. * the other side
  203. */
  204. if (errno_copy == THRIFT_ECONNRESET) {
  205. close();
  206. return false;
  207. }
  208. #endif
  209. GlobalOutput.perror("TSocket::peek() recv() " + getSocketInfo(), errno_copy);
  210. throw TTransportException(TTransportException::UNKNOWN, "recv()", errno_copy);
  211. }
  212. return (r > 0);
  213. }
  214. void TSocket::openConnection(struct addrinfo* res) {
  215. if (isOpen()) {
  216. return;
  217. }
  218. if (!path_.empty()) {
  219. socket_ = socket(PF_UNIX, SOCK_STREAM, IPPROTO_IP);
  220. } else {
  221. socket_ = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  222. }
  223. if (socket_ == THRIFT_INVALID_SOCKET) {
  224. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  225. GlobalOutput.perror("TSocket::open() socket() " + getSocketInfo(), errno_copy);
  226. throw TTransportException(TTransportException::NOT_OPEN, "socket()", errno_copy);
  227. }
  228. // Send timeout
  229. if (sendTimeout_ > 0) {
  230. setSendTimeout(sendTimeout_);
  231. }
  232. // Recv timeout
  233. if (recvTimeout_ > 0) {
  234. setRecvTimeout(recvTimeout_);
  235. }
  236. if (keepAlive_) {
  237. setKeepAlive(keepAlive_);
  238. }
  239. // Linger
  240. setLinger(lingerOn_, lingerVal_);
  241. // No delay
  242. setNoDelay(noDelay_);
  243. #ifdef SO_NOSIGPIPE
  244. {
  245. int one = 1;
  246. setsockopt(socket_, SOL_SOCKET, SO_NOSIGPIPE, &one, sizeof(one));
  247. }
  248. #endif
  249. // Uses a low min RTO if asked to.
  250. #ifdef TCP_LOW_MIN_RTO
  251. if (getUseLowMinRto()) {
  252. int one = 1;
  253. setsockopt(socket_, IPPROTO_TCP, TCP_LOW_MIN_RTO, &one, sizeof(one));
  254. }
  255. #endif
  256. // Set the socket to be non blocking for connect if a timeout exists
  257. int flags = THRIFT_FCNTL(socket_, THRIFT_F_GETFL, 0);
  258. if (connTimeout_ > 0) {
  259. if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags | THRIFT_O_NONBLOCK)) {
  260. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  261. GlobalOutput.perror("TSocket::open() THRIFT_FCNTL() " + getSocketInfo(), errno_copy);
  262. throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
  263. }
  264. } else {
  265. if (-1 == THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags & ~THRIFT_O_NONBLOCK)) {
  266. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  267. GlobalOutput.perror("TSocket::open() THRIFT_FCNTL " + getSocketInfo(), errno_copy);
  268. throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_FCNTL() failed", errno_copy);
  269. }
  270. }
  271. // Connect the socket
  272. int ret;
  273. if (!path_.empty()) {
  274. #ifndef _WIN32
  275. size_t len = path_.size() + 1;
  276. if (len > sizeof(((sockaddr_un*)NULL)->sun_path)) {
  277. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  278. GlobalOutput.perror("TSocket::open() Unix Domain socket path too long", errno_copy);
  279. throw TTransportException(TTransportException::NOT_OPEN, " Unix Domain socket path too long");
  280. }
  281. struct sockaddr_un address;
  282. address.sun_family = AF_UNIX;
  283. memcpy(address.sun_path, path_.c_str(), len);
  284. socklen_t structlen = static_cast<socklen_t>(sizeof(address));
  285. if (!address.sun_path[0]) { // abstract namespace socket
  286. #ifdef __linux__
  287. // sun_path is not null-terminated in this case and structlen determines its length
  288. structlen -= sizeof(address.sun_path) - len;
  289. #else
  290. GlobalOutput.perror("TSocket::open() Abstract Namespace Domain sockets only supported on linux: ", -99);
  291. throw TTransportException(TTransportException::NOT_OPEN,
  292. " Abstract Namespace Domain socket path not supported");
  293. #endif
  294. }
  295. ret = connect(socket_, (struct sockaddr*)&address, structlen);
  296. #else
  297. GlobalOutput.perror("TSocket::open() Unix Domain socket path not supported on windows", -99);
  298. throw TTransportException(TTransportException::NOT_OPEN,
  299. " Unix Domain socket path not supported");
  300. #endif
  301. } else {
  302. ret = connect(socket_, res->ai_addr, static_cast<int>(res->ai_addrlen));
  303. }
  304. // success case
  305. if (ret == 0) {
  306. goto done;
  307. }
  308. if ((THRIFT_GET_SOCKET_ERROR != THRIFT_EINPROGRESS)
  309. && (THRIFT_GET_SOCKET_ERROR != THRIFT_EWOULDBLOCK)) {
  310. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  311. GlobalOutput.perror("TSocket::open() connect() " + getSocketInfo(), errno_copy);
  312. throw TTransportException(TTransportException::NOT_OPEN, "connect() failed", errno_copy);
  313. }
  314. struct THRIFT_POLLFD fds[1];
  315. std::memset(fds, 0, sizeof(fds));
  316. fds[0].fd = socket_;
  317. fds[0].events = THRIFT_POLLOUT;
  318. ret = THRIFT_POLL(fds, 1, connTimeout_);
  319. if (ret > 0) {
  320. // Ensure the socket is connected and that there are no errors set
  321. int val;
  322. socklen_t lon;
  323. lon = sizeof(int);
  324. int ret2 = getsockopt(socket_, SOL_SOCKET, SO_ERROR, cast_sockopt(&val), &lon);
  325. if (ret2 == -1) {
  326. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  327. GlobalOutput.perror("TSocket::open() getsockopt() " + getSocketInfo(), errno_copy);
  328. throw TTransportException(TTransportException::NOT_OPEN, "getsockopt()", errno_copy);
  329. }
  330. // no errors on socket, go to town
  331. if (val == 0) {
  332. goto done;
  333. }
  334. GlobalOutput.perror("TSocket::open() error on socket (after THRIFT_POLL) " + getSocketInfo(),
  335. val);
  336. throw TTransportException(TTransportException::NOT_OPEN, "socket open() error", val);
  337. } else if (ret == 0) {
  338. // socket timed out
  339. string errStr = "TSocket::open() timed out " + getSocketInfo();
  340. GlobalOutput(errStr.c_str());
  341. throw TTransportException(TTransportException::NOT_OPEN, "open() timed out");
  342. } else {
  343. // error on THRIFT_POLL()
  344. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  345. GlobalOutput.perror("TSocket::open() THRIFT_POLL() " + getSocketInfo(), errno_copy);
  346. throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_POLL() failed", errno_copy);
  347. }
  348. done:
  349. // Set socket back to normal mode (blocking)
  350. THRIFT_FCNTL(socket_, THRIFT_F_SETFL, flags);
  351. if (path_.empty()) {
  352. setCachedAddress(res->ai_addr, static_cast<socklen_t>(res->ai_addrlen));
  353. }
  354. }
  355. void TSocket::open() {
  356. if (isOpen()) {
  357. return;
  358. }
  359. if (!path_.empty()) {
  360. unix_open();
  361. } else {
  362. local_open();
  363. }
  364. }
  365. void TSocket::unix_open() {
  366. if (!path_.empty()) {
  367. // Unix Domain SOcket does not need addrinfo struct, so we pass NULL
  368. openConnection(NULL);
  369. }
  370. }
  371. void TSocket::local_open() {
  372. #ifdef _WIN32
  373. TWinsockSingleton::create();
  374. #endif // _WIN32
  375. if (isOpen()) {
  376. return;
  377. }
  378. // Validate port number
  379. if (port_ < 0 || port_ > 0xFFFF) {
  380. throw TTransportException(TTransportException::BAD_ARGS, "Specified port is invalid");
  381. }
  382. struct addrinfo hints, *res, *res0;
  383. res = NULL;
  384. res0 = NULL;
  385. int error;
  386. char port[sizeof("65535")];
  387. std::memset(&hints, 0, sizeof(hints));
  388. hints.ai_family = PF_UNSPEC;
  389. hints.ai_socktype = SOCK_STREAM;
  390. hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
  391. sprintf(port, "%d", port_);
  392. error = getaddrinfo(host_.c_str(), port, &hints, &res0);
  393. #ifdef _WIN32
  394. if (error == WSANO_DATA) {
  395. hints.ai_flags &= ~AI_ADDRCONFIG;
  396. error = getaddrinfo(host_.c_str(), port, &hints, &res0);
  397. }
  398. #endif
  399. if (error) {
  400. string errStr = "TSocket::open() getaddrinfo() " + getSocketInfo()
  401. + string(THRIFT_GAI_STRERROR(error));
  402. GlobalOutput(errStr.c_str());
  403. close();
  404. throw TTransportException(TTransportException::NOT_OPEN,
  405. "Could not resolve host for client socket.");
  406. }
  407. // Cycle through all the returned addresses until one
  408. // connects or push the exception up.
  409. for (res = res0; res; res = res->ai_next) {
  410. try {
  411. openConnection(res);
  412. break;
  413. } catch (TTransportException&) {
  414. if (res->ai_next) {
  415. close();
  416. } else {
  417. close();
  418. freeaddrinfo(res0); // cleanup on failure
  419. throw;
  420. }
  421. }
  422. }
  423. // Free address structure memory
  424. freeaddrinfo(res0);
  425. }
  426. void TSocket::close() {
  427. if (socket_ != THRIFT_INVALID_SOCKET) {
  428. shutdown(socket_, THRIFT_SHUT_RDWR);
  429. ::THRIFT_CLOSESOCKET(socket_);
  430. }
  431. socket_ = THRIFT_INVALID_SOCKET;
  432. }
  433. void TSocket::setSocketFD(THRIFT_SOCKET socket) {
  434. if (socket_ != THRIFT_INVALID_SOCKET) {
  435. close();
  436. }
  437. socket_ = socket;
  438. }
  439. uint32_t TSocket::read(uint8_t* buf, uint32_t len) {
  440. if (socket_ == THRIFT_INVALID_SOCKET) {
  441. throw TTransportException(TTransportException::NOT_OPEN, "Called read on non-open socket");
  442. }
  443. int32_t retries = 0;
  444. // THRIFT_EAGAIN can be signalled both when a timeout has occurred and when
  445. // the system is out of resources (an awesome undocumented feature).
  446. // The following is an approximation of the time interval under which
  447. // THRIFT_EAGAIN is taken to indicate an out of resources error.
  448. uint32_t eagainThresholdMicros = 0;
  449. if (recvTimeout_) {
  450. // if a readTimeout is specified along with a max number of recv retries, then
  451. // the threshold will ensure that the read timeout is not exceeded even in the
  452. // case of resource errors
  453. eagainThresholdMicros = (recvTimeout_ * 1000) / ((maxRecvRetries_ > 0) ? maxRecvRetries_ : 2);
  454. }
  455. try_again:
  456. // Read from the socket
  457. struct timeval begin;
  458. if (recvTimeout_ > 0) {
  459. THRIFT_GETTIMEOFDAY(&begin, NULL);
  460. } else {
  461. // if there is no read timeout we don't need the TOD to determine whether
  462. // an THRIFT_EAGAIN is due to a timeout or an out-of-resource condition.
  463. begin.tv_sec = begin.tv_usec = 0;
  464. }
  465. int got = 0;
  466. if (interruptListener_) {
  467. struct THRIFT_POLLFD fds[2];
  468. std::memset(fds, 0, sizeof(fds));
  469. fds[0].fd = socket_;
  470. fds[0].events = THRIFT_POLLIN;
  471. fds[1].fd = *(interruptListener_.get());
  472. fds[1].events = THRIFT_POLLIN;
  473. int ret = THRIFT_POLL(fds, 2, (recvTimeout_ == 0) ? -1 : recvTimeout_);
  474. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  475. if (ret < 0) {
  476. // error cases
  477. if (errno_copy == THRIFT_EINTR && (retries++ < maxRecvRetries_)) {
  478. goto try_again;
  479. }
  480. GlobalOutput.perror("TSocket::read() THRIFT_POLL() ", errno_copy);
  481. throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
  482. } else if (ret > 0) {
  483. // Check the interruptListener
  484. if (fds[1].revents & THRIFT_POLLIN) {
  485. throw TTransportException(TTransportException::INTERRUPTED, "Interrupted");
  486. }
  487. } else /* ret == 0 */ {
  488. throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_EAGAIN (timed out)");
  489. }
  490. // falling through means there is something to recv and it cannot block
  491. }
  492. got = static_cast<int>(recv(socket_, cast_sockopt(buf), len, 0));
  493. // THRIFT_GETTIMEOFDAY can change THRIFT_GET_SOCKET_ERROR
  494. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  495. // Check for error on read
  496. if (got < 0) {
  497. if (errno_copy == THRIFT_EAGAIN) {
  498. // if no timeout we can assume that resource exhaustion has occurred.
  499. if (recvTimeout_ == 0) {
  500. throw TTransportException(TTransportException::TIMED_OUT,
  501. "THRIFT_EAGAIN (unavailable resources)");
  502. }
  503. // check if this is the lack of resources or timeout case
  504. struct timeval end;
  505. THRIFT_GETTIMEOFDAY(&end, NULL);
  506. uint32_t readElapsedMicros = static_cast<uint32_t>(((end.tv_sec - begin.tv_sec) * 1000 * 1000)
  507. + (end.tv_usec - begin.tv_usec));
  508. if (!eagainThresholdMicros || (readElapsedMicros < eagainThresholdMicros)) {
  509. if (retries++ < maxRecvRetries_) {
  510. THRIFT_SLEEP_USEC(50);
  511. goto try_again;
  512. } else {
  513. throw TTransportException(TTransportException::TIMED_OUT,
  514. "THRIFT_EAGAIN (unavailable resources)");
  515. }
  516. } else {
  517. // infer that timeout has been hit
  518. throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_EAGAIN (timed out)");
  519. }
  520. }
  521. // If interrupted, try again
  522. if (errno_copy == THRIFT_EINTR && retries++ < maxRecvRetries_) {
  523. goto try_again;
  524. }
  525. if (errno_copy == THRIFT_ECONNRESET) {
  526. return 0;
  527. }
  528. // This ish isn't open
  529. if (errno_copy == THRIFT_ENOTCONN) {
  530. throw TTransportException(TTransportException::NOT_OPEN, "THRIFT_ENOTCONN");
  531. }
  532. // Timed out!
  533. if (errno_copy == THRIFT_ETIMEDOUT) {
  534. throw TTransportException(TTransportException::TIMED_OUT, "THRIFT_ETIMEDOUT");
  535. }
  536. // Now it's not a try again case, but a real probblez
  537. GlobalOutput.perror("TSocket::read() recv() " + getSocketInfo(), errno_copy);
  538. // Some other error, whatevz
  539. throw TTransportException(TTransportException::UNKNOWN, "Unknown", errno_copy);
  540. }
  541. return got;
  542. }
  543. void TSocket::write(const uint8_t* buf, uint32_t len) {
  544. uint32_t sent = 0;
  545. while (sent < len) {
  546. uint32_t b = write_partial(buf + sent, len - sent);
  547. if (b == 0) {
  548. // This should only happen if the timeout set with SO_SNDTIMEO expired.
  549. // Raise an exception.
  550. throw TTransportException(TTransportException::TIMED_OUT, "send timeout expired");
  551. }
  552. sent += b;
  553. }
  554. }
  555. uint32_t TSocket::write_partial(const uint8_t* buf, uint32_t len) {
  556. if (socket_ == THRIFT_INVALID_SOCKET) {
  557. throw TTransportException(TTransportException::NOT_OPEN, "Called write on non-open socket");
  558. }
  559. uint32_t sent = 0;
  560. int flags = 0;
  561. #ifdef MSG_NOSIGNAL
  562. // Note the use of MSG_NOSIGNAL to suppress SIGPIPE errors, instead we
  563. // check for the THRIFT_EPIPE return condition and close the socket in that case
  564. flags |= MSG_NOSIGNAL;
  565. #endif // ifdef MSG_NOSIGNAL
  566. int b = static_cast<int>(send(socket_, const_cast_sockopt(buf + sent), len - sent, flags));
  567. if (b < 0) {
  568. if (THRIFT_GET_SOCKET_ERROR == THRIFT_EWOULDBLOCK || THRIFT_GET_SOCKET_ERROR == THRIFT_EAGAIN) {
  569. return 0;
  570. }
  571. // Fail on a send error
  572. int errno_copy = THRIFT_GET_SOCKET_ERROR;
  573. GlobalOutput.perror("TSocket::write_partial() send() " + getSocketInfo(), errno_copy);
  574. if (errno_copy == THRIFT_EPIPE || errno_copy == THRIFT_ECONNRESET
  575. || errno_copy == THRIFT_ENOTCONN) {
  576. close();
  577. throw TTransportException(TTransportException::NOT_OPEN, "write() send()", errno_copy);
  578. }
  579. throw TTransportException(TTransportException::UNKNOWN, "write() send()", errno_copy);
  580. }
  581. // Fail on blocked send
  582. if (b == 0) {
  583. throw TTransportException(TTransportException::NOT_OPEN, "Socket send returned 0.");
  584. }
  585. return b;
  586. }
  587. std::string TSocket::getHost() {
  588. return host_;
  589. }
  590. int TSocket::getPort() {
  591. return port_;
  592. }
  593. void TSocket::setHost(string host) {
  594. host_ = host;
  595. }
  596. void TSocket::setPort(int port) {
  597. port_ = port;
  598. }
  599. void TSocket::setLinger(bool on, int linger) {
  600. lingerOn_ = on;
  601. lingerVal_ = linger;
  602. if (socket_ == THRIFT_INVALID_SOCKET) {
  603. return;
  604. }
  605. #ifndef _WIN32
  606. struct linger l = {(lingerOn_ ? 1 : 0), lingerVal_};
  607. #else
  608. struct linger l = {(lingerOn_ ? 1 : 0), static_cast<u_short>(lingerVal_)};
  609. #endif
  610. int ret = setsockopt(socket_, SOL_SOCKET, SO_LINGER, cast_sockopt(&l), sizeof(l));
  611. if (ret == -1) {
  612. int errno_copy
  613. = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
  614. GlobalOutput.perror("TSocket::setLinger() setsockopt() " + getSocketInfo(), errno_copy);
  615. }
  616. }
  617. void TSocket::setNoDelay(bool noDelay) {
  618. noDelay_ = noDelay;
  619. if (socket_ == THRIFT_INVALID_SOCKET || !path_.empty()) {
  620. return;
  621. }
  622. // Set socket to NODELAY
  623. int v = noDelay_ ? 1 : 0;
  624. int ret = setsockopt(socket_, IPPROTO_TCP, TCP_NODELAY, cast_sockopt(&v), sizeof(v));
  625. if (ret == -1) {
  626. int errno_copy
  627. = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
  628. GlobalOutput.perror("TSocket::setNoDelay() setsockopt() " + getSocketInfo(), errno_copy);
  629. }
  630. }
  631. void TSocket::setConnTimeout(int ms) {
  632. connTimeout_ = ms;
  633. }
  634. void setGenericTimeout(THRIFT_SOCKET s, int timeout_ms, int optname) {
  635. if (timeout_ms < 0) {
  636. char errBuf[512];
  637. sprintf(errBuf, "TSocket::setGenericTimeout with negative input: %d\n", timeout_ms);
  638. GlobalOutput(errBuf);
  639. return;
  640. }
  641. if (s == THRIFT_INVALID_SOCKET) {
  642. return;
  643. }
  644. #ifdef _WIN32
  645. DWORD platform_time = static_cast<DWORD>(timeout_ms);
  646. #else
  647. struct timeval platform_time = {(int)(timeout_ms / 1000), (int)((timeout_ms % 1000) * 1000)};
  648. #endif
  649. int ret = setsockopt(s, SOL_SOCKET, optname, cast_sockopt(&platform_time), sizeof(platform_time));
  650. if (ret == -1) {
  651. int errno_copy
  652. = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
  653. GlobalOutput.perror("TSocket::setGenericTimeout() setsockopt() ", errno_copy);
  654. }
  655. }
  656. void TSocket::setRecvTimeout(int ms) {
  657. setGenericTimeout(socket_, ms, SO_RCVTIMEO);
  658. recvTimeout_ = ms;
  659. }
  660. void TSocket::setSendTimeout(int ms) {
  661. setGenericTimeout(socket_, ms, SO_SNDTIMEO);
  662. sendTimeout_ = ms;
  663. }
  664. void TSocket::setKeepAlive(bool keepAlive) {
  665. keepAlive_ = keepAlive;
  666. if (socket_ == -1) {
  667. return;
  668. }
  669. int value = keepAlive_;
  670. int ret
  671. = setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE, const_cast_sockopt(&value), sizeof(value));
  672. if (ret == -1) {
  673. int errno_copy
  674. = THRIFT_GET_SOCKET_ERROR; // Copy THRIFT_GET_SOCKET_ERROR because we're allocating memory.
  675. GlobalOutput.perror("TSocket::setKeepAlive() setsockopt() " + getSocketInfo(), errno_copy);
  676. }
  677. }
  678. void TSocket::setMaxRecvRetries(int maxRecvRetries) {
  679. maxRecvRetries_ = maxRecvRetries;
  680. }
  681. string TSocket::getSocketInfo() {
  682. std::ostringstream oss;
  683. if (host_.empty() || port_ == 0) {
  684. oss << "<Host: " << getPeerAddress();
  685. oss << " Port: " << getPeerPort() << ">";
  686. } else {
  687. oss << "<Host: " << host_ << " Port: " << port_ << ">";
  688. }
  689. return oss.str();
  690. }
  691. std::string TSocket::getPeerHost() {
  692. if (peerHost_.empty() && path_.empty()) {
  693. struct sockaddr_storage addr;
  694. struct sockaddr* addrPtr;
  695. socklen_t addrLen;
  696. if (socket_ == THRIFT_INVALID_SOCKET) {
  697. return host_;
  698. }
  699. addrPtr = getCachedAddress(&addrLen);
  700. if (addrPtr == NULL) {
  701. addrLen = sizeof(addr);
  702. if (getpeername(socket_, (sockaddr*)&addr, &addrLen) != 0) {
  703. return peerHost_;
  704. }
  705. addrPtr = (sockaddr*)&addr;
  706. setCachedAddress(addrPtr, addrLen);
  707. }
  708. char clienthost[NI_MAXHOST];
  709. char clientservice[NI_MAXSERV];
  710. getnameinfo((sockaddr*)addrPtr,
  711. addrLen,
  712. clienthost,
  713. sizeof(clienthost),
  714. clientservice,
  715. sizeof(clientservice),
  716. 0);
  717. peerHost_ = clienthost;
  718. }
  719. return peerHost_;
  720. }
  721. std::string TSocket::getPeerAddress() {
  722. if (peerAddress_.empty() && path_.empty()) {
  723. struct sockaddr_storage addr;
  724. struct sockaddr* addrPtr;
  725. socklen_t addrLen;
  726. if (socket_ == THRIFT_INVALID_SOCKET) {
  727. return peerAddress_;
  728. }
  729. addrPtr = getCachedAddress(&addrLen);
  730. if (addrPtr == NULL) {
  731. addrLen = sizeof(addr);
  732. if (getpeername(socket_, (sockaddr*)&addr, &addrLen) != 0) {
  733. return peerAddress_;
  734. }
  735. addrPtr = (sockaddr*)&addr;
  736. setCachedAddress(addrPtr, addrLen);
  737. }
  738. char clienthost[NI_MAXHOST];
  739. char clientservice[NI_MAXSERV];
  740. getnameinfo(addrPtr,
  741. addrLen,
  742. clienthost,
  743. sizeof(clienthost),
  744. clientservice,
  745. sizeof(clientservice),
  746. NI_NUMERICHOST | NI_NUMERICSERV);
  747. peerAddress_ = clienthost;
  748. peerPort_ = std::atoi(clientservice);
  749. }
  750. return peerAddress_;
  751. }
  752. int TSocket::getPeerPort() {
  753. getPeerAddress();
  754. return peerPort_;
  755. }
  756. void TSocket::setCachedAddress(const sockaddr* addr, socklen_t len) {
  757. if (!path_.empty()) {
  758. return;
  759. }
  760. switch (addr->sa_family) {
  761. case AF_INET:
  762. if (len == sizeof(sockaddr_in)) {
  763. memcpy((void*)&cachedPeerAddr_.ipv4, (void*)addr, len);
  764. }
  765. break;
  766. case AF_INET6:
  767. if (len == sizeof(sockaddr_in6)) {
  768. memcpy((void*)&cachedPeerAddr_.ipv6, (void*)addr, len);
  769. }
  770. break;
  771. }
  772. peerAddress_.clear();
  773. peerHost_.clear();
  774. }
  775. sockaddr* TSocket::getCachedAddress(socklen_t* len) const {
  776. switch (cachedPeerAddr_.ipv4.sin_family) {
  777. case AF_INET:
  778. *len = sizeof(sockaddr_in);
  779. return (sockaddr*)&cachedPeerAddr_.ipv4;
  780. case AF_INET6:
  781. *len = sizeof(sockaddr_in6);
  782. return (sockaddr*)&cachedPeerAddr_.ipv6;
  783. default:
  784. return NULL;
  785. }
  786. }
  787. bool TSocket::useLowMinRto_ = false;
  788. void TSocket::setUseLowMinRto(bool useLowMinRto) {
  789. useLowMinRto_ = useLowMinRto;
  790. }
  791. bool TSocket::getUseLowMinRto() {
  792. return useLowMinRto_;
  793. }
  794. const std::string TSocket::getOrigin() {
  795. std::ostringstream oss;
  796. oss << getPeerHost() << ":" << getPeerPort();
  797. return oss.str();
  798. }
  799. }
  800. }
  801. } // apache::thrift::transport