lliosocket.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /**
  2. * @file lliosocket.cpp
  3. * @author Phoenix
  4. * @date 2005-07-31
  5. * @brief Sockets declarations for use with the io pipes
  6. *
  7. * $LicenseInfo:firstyear=2005&license=viewergpl$
  8. *
  9. * Copyright (c) 2005-2009, Linden Research, Inc.
  10. *
  11. * Second Life Viewer Source Code
  12. * The source code in this file ("Source Code") is provided by Linden Lab
  13. * to you under the terms of the GNU General Public License, version 2.0
  14. * ("GPL"), unless you have obtained a separate licensing agreement
  15. * ("Other License"), formally executed by you and Linden Lab. Terms of
  16. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  17. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  18. *
  19. * There are special exceptions to the terms and conditions of the GPL as
  20. * it is applied to this Source Code. View the full text of the exception
  21. * in the file doc/FLOSS-exception.txt in this software distribution, or
  22. * online at
  23. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  24. *
  25. * By copying, modifying or distributing this software, you acknowledge
  26. * that you have read and understood your obligations described above,
  27. * and agree to abide by those obligations.
  28. *
  29. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  30. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  31. * COMPLETENESS OR PERFORMANCE.
  32. * $/LicenseInfo$
  33. */
  34. #include "linden_common.h"
  35. #include "lliosocket.h"
  36. #include "llapr.h"
  37. #include "llbuffer.h"
  38. #include "llfasttimer.h"
  39. #include "llhost.h"
  40. #include "llhttpconstants.h"
  41. #include "llpumpio.h"
  42. // Constants
  43. constexpr S32 LL_DEFAULT_LISTEN_BACKLOG = 10;
  44. constexpr S32 LL_SEND_BUFFER_SIZE = 40000;
  45. constexpr S32 LL_RECV_BUFFER_SIZE = 40000;
  46. ///////////////////////////////////////////////////////////////////////////////
  47. // LLSocket class
  48. ///////////////////////////////////////////////////////////////////////////////
  49. //static
  50. LLSocket::ptr_t LLSocket::create(apr_pool_t* pool, EType type, U16 port)
  51. {
  52. LLSocket::ptr_t rv;
  53. apr_socket_t* socket = NULL;
  54. apr_pool_t* new_pool = NULL;
  55. apr_status_t status = APR_EGENERAL;
  56. // create a pool for the socket
  57. status = apr_pool_create(&new_pool, pool);
  58. if (ll_apr_warn_status(status))
  59. {
  60. llwarns << "Socket creation failure (step 1)" << llendl;
  61. if (new_pool)
  62. {
  63. apr_pool_destroy(new_pool);
  64. }
  65. return rv;
  66. }
  67. if (STREAM_TCP == type)
  68. {
  69. status = apr_socket_create(&socket, APR_INET, SOCK_STREAM,
  70. APR_PROTO_TCP, new_pool);
  71. }
  72. else if (DATAGRAM_UDP == type)
  73. {
  74. status = apr_socket_create(&socket, APR_INET, SOCK_DGRAM,
  75. APR_PROTO_UDP, new_pool);
  76. }
  77. else
  78. {
  79. llwarns << "Socket creation aborted. Bad stream type: " << type
  80. << llendl;
  81. if (new_pool)
  82. {
  83. apr_pool_destroy(new_pool);
  84. }
  85. return rv;
  86. }
  87. if (ll_apr_warn_status(status))
  88. {
  89. llwarns << "Socket creation failure (step 2)" << llendl;
  90. if (new_pool)
  91. {
  92. apr_pool_destroy(new_pool);
  93. }
  94. return rv;
  95. }
  96. // NOTE: cannot use std::make_shared here because LLSocket() constructor
  97. // is protected...
  98. rv = ptr_t(new LLSocket(socket, new_pool));
  99. if (port > 0)
  100. {
  101. apr_sockaddr_t* sa = NULL;
  102. status = apr_sockaddr_info_get(&sa, APR_ANYADDR, APR_UNSPEC, port, 0,
  103. new_pool);
  104. if (ll_apr_warn_status(status))
  105. {
  106. llwarns << "Socket creation failure (step 3)" << llendl;
  107. rv.reset();
  108. return rv;
  109. }
  110. // This allows us to reuse the address on quick down/up. This is
  111. // unlikely to create problems.
  112. ll_apr_warn_status(apr_socket_opt_set(socket, APR_SO_REUSEADDR, 1));
  113. status = apr_socket_bind(socket, sa);
  114. if (ll_apr_warn_status(status))
  115. {
  116. llwarns << "Socket creation failure (step 4)" << llendl;
  117. rv.reset();
  118. return rv;
  119. }
  120. LL_DEBUGS("IOSocket") << "Bound "
  121. << (DATAGRAM_UDP == type ? "udp" : "tcp")
  122. << " socket to port: " << sa->port << LL_ENDL;
  123. if (STREAM_TCP == type)
  124. {
  125. // If it is a stream based socket, we need to tell the OS to keep a
  126. // queue of incoming connections for ACCEPT.
  127. LL_DEBUGS("IOSocket") << "Setting listen state for socket."
  128. << LL_ENDL;
  129. status = apr_socket_listen(socket, LL_DEFAULT_LISTEN_BACKLOG);
  130. if (ll_apr_warn_status(status))
  131. {
  132. llwarns << "Socket creation failure (step 5)" << llendl;
  133. rv.reset();
  134. return rv;
  135. }
  136. }
  137. }
  138. else
  139. {
  140. // We need to indicate that we have an ephemeral port if the previous
  141. // calls were successful. It will
  142. port = PORT_EPHEMERAL;
  143. }
  144. rv->mPort = port;
  145. rv->setNonBlocking();
  146. return rv;
  147. }
  148. //static
  149. LLSocket::ptr_t LLSocket::create(apr_socket_t* socket, apr_pool_t* pool)
  150. {
  151. LLSocket::ptr_t rv;
  152. if (!socket)
  153. {
  154. return rv;
  155. }
  156. // NOTE: cannot use std::make_shared here because LLSocket() constructor
  157. // is protected...
  158. rv = ptr_t(new LLSocket(socket, pool));
  159. rv->mPort = PORT_EPHEMERAL;
  160. rv->setNonBlocking();
  161. return rv;
  162. }
  163. bool LLSocket::blockingConnect(const LLHost& host)
  164. {
  165. if (!mSocket || !host.isOk()) return false;
  166. apr_sockaddr_t* sa = NULL;
  167. std::string ip_address;
  168. ip_address = host.getIPString();
  169. if (ll_apr_warn_status(apr_sockaddr_info_get(&sa, ip_address.c_str(),
  170. APR_UNSPEC, host.getPort(),
  171. 0, mPool)))
  172. {
  173. return false;
  174. }
  175. setBlocking(1000);
  176. LL_DEBUGS("IOSocket") << "Blocking connect " << std::hex
  177. << (intptr_t)mSocket << std::dec << LL_ENDL;
  178. if (ll_apr_warn_status(apr_socket_connect(mSocket, sa))) return false;
  179. setNonBlocking();
  180. return true;
  181. }
  182. LLSocket::LLSocket(apr_socket_t* socket, apr_pool_t* pool)
  183. : mSocket(socket),
  184. mPool(pool),
  185. mPort(PORT_INVALID)
  186. {
  187. LL_DEBUGS("IOSocket") << "Constructing wholely formed socket " << std::hex
  188. << (intptr_t)mSocket << std::dec << LL_ENDL;
  189. }
  190. LLSocket::~LLSocket()
  191. {
  192. // *FIX: clean up memory we are holding.
  193. if (mSocket)
  194. {
  195. LL_DEBUGS("IOSocket") << "Destroying socket " << std::hex
  196. << (intptr_t)mSocket << std::dec << LL_ENDL;
  197. apr_socket_close(mSocket);
  198. mSocket = NULL;
  199. }
  200. if (mPool)
  201. {
  202. apr_pool_destroy(mPool);
  203. }
  204. }
  205. // See http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html#ss13.4
  206. // for an explanation of how to get non-blocking sockets and timeouts with
  207. // consistent behavior across platforms.
  208. void LLSocket::setBlocking(S32 timeout)
  209. {
  210. // set up the socket options
  211. ll_apr_warn_status(apr_socket_timeout_set(mSocket, timeout));
  212. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 0));
  213. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF,
  214. LL_SEND_BUFFER_SIZE));
  215. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF,
  216. LL_RECV_BUFFER_SIZE));
  217. }
  218. void LLSocket::setNonBlocking()
  219. {
  220. // set up the socket options
  221. ll_apr_warn_status(apr_socket_timeout_set(mSocket, 0));
  222. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_NONBLOCK, 1));
  223. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_SNDBUF,
  224. LL_SEND_BUFFER_SIZE));
  225. ll_apr_warn_status(apr_socket_opt_set(mSocket, APR_SO_RCVBUF,
  226. LL_RECV_BUFFER_SIZE));
  227. }
  228. ///////////////////////////////////////////////////////////////////////////////
  229. // LLIOSocketReader class
  230. ///////////////////////////////////////////////////////////////////////////////
  231. LLIOSocketReader::LLIOSocketReader(LLSocket::ptr_t socket)
  232. : mSource(socket),
  233. mInitialized(false)
  234. {
  235. }
  236. //virtual
  237. LLIOPipe::EStatus LLIOSocketReader::process_impl(const LLChannelDescriptors& channels,
  238. buffer_ptr_t& buffer,
  239. bool& eos,
  240. LLSD& context,
  241. LLPumpIO* pump)
  242. {
  243. LL_FAST_TIMER(FTM_PROCESS_SOCKET_READER);
  244. PUMP_DEBUG;
  245. if (!mSource) return STATUS_PRECONDITION_NOT_MET;
  246. if (!mInitialized)
  247. {
  248. PUMP_DEBUG;
  249. // Since the read will not block, it's ok to initialize and
  250. // attempt to read off the descriptor immediately.
  251. mInitialized = true;
  252. if (pump)
  253. {
  254. PUMP_DEBUG;
  255. LL_DEBUGS("IOSocket") << "Initializing poll descriptor for LLIOSocketReader."
  256. << LL_ENDL;
  257. apr_pollfd_t poll_fd;
  258. poll_fd.p = NULL;
  259. poll_fd.desc_type = APR_POLL_SOCKET;
  260. poll_fd.reqevents = APR_POLLIN;
  261. poll_fd.rtnevents = 0x0;
  262. poll_fd.desc.s = mSource->getSocket();
  263. poll_fd.client_data = NULL;
  264. pump->setConditional(this, &poll_fd);
  265. }
  266. }
  267. #if 0
  268. if (!buffer)
  269. {
  270. buffer = new LLBufferArray;
  271. }
  272. #endif
  273. PUMP_DEBUG;
  274. const apr_size_t READ_BUFFER_SIZE = 1024;
  275. char read_buf[READ_BUFFER_SIZE];
  276. apr_size_t len;
  277. apr_status_t status = APR_SUCCESS;
  278. do
  279. {
  280. PUMP_DEBUG;
  281. len = READ_BUFFER_SIZE;
  282. status = apr_socket_recv(mSource->getSocket(), read_buf, &len);
  283. buffer->append(channels.out(), (U8*)read_buf, len);
  284. }
  285. while (APR_SUCCESS == status && READ_BUFFER_SIZE == len);
  286. LL_DEBUGS("IOSocket") << "socket read status: " << status << LL_ENDL;
  287. LLIOPipe::EStatus rv = STATUS_OK;
  288. PUMP_DEBUG;
  289. // *FIX: Also need to check for broken pipe
  290. if (APR_STATUS_IS_EOF(status))
  291. {
  292. // *FIX: Should we shut down the socket read ?
  293. if (pump)
  294. {
  295. pump->setConditional(this, NULL);
  296. }
  297. rv = STATUS_DONE;
  298. eos = true;
  299. }
  300. else if (APR_STATUS_IS_EAGAIN(status))
  301. {
  302. #if 0 // Disabled by Aura 9-9-8 for DEV-19961.
  303. // Everything is fine, but we can terminate this process pump.
  304. rv = STATUS_BREAK;
  305. #endif
  306. }
  307. else
  308. {
  309. if (ll_apr_warn_status(status))
  310. {
  311. rv = STATUS_ERROR;
  312. }
  313. }
  314. PUMP_DEBUG;
  315. return rv;
  316. }
  317. //
  318. // LLIOSocketWriter
  319. //
  320. LLIOSocketWriter::LLIOSocketWriter(LLSocket::ptr_t socket)
  321. : mDestination(socket),
  322. mLastWritten(NULL),
  323. mInitialized(false)
  324. {
  325. }
  326. //virtual
  327. LLIOPipe::EStatus LLIOSocketWriter::process_impl(const LLChannelDescriptors& channels,
  328. buffer_ptr_t& buffer,
  329. bool& eos,
  330. LLSD& context,
  331. LLPumpIO* pump)
  332. {
  333. LL_FAST_TIMER(FTM_PROCESS_SOCKET_WRITER);
  334. PUMP_DEBUG;
  335. if (!mDestination) return STATUS_PRECONDITION_NOT_MET;
  336. if (!mInitialized)
  337. {
  338. PUMP_DEBUG;
  339. // Since the write will not block, it's ok to initialize and
  340. // attempt to write immediately.
  341. mInitialized = true;
  342. if (pump)
  343. {
  344. PUMP_DEBUG;
  345. LL_DEBUGS("IOSocket") << "Initializing poll descriptor for LLIOSocketWriter."
  346. << LL_ENDL;
  347. apr_pollfd_t poll_fd;
  348. poll_fd.p = NULL;
  349. poll_fd.desc_type = APR_POLL_SOCKET;
  350. poll_fd.reqevents = APR_POLLOUT;
  351. poll_fd.rtnevents = 0x0;
  352. poll_fd.desc.s = mDestination->getSocket();
  353. poll_fd.client_data = NULL;
  354. pump->setConditional(this, &poll_fd);
  355. }
  356. }
  357. PUMP_DEBUG;
  358. // *FIX: Some sort of writev implementation would be much more efficient -
  359. // not only because writev() is better, but also because we won't have to
  360. // do as much work to find the start address.
  361. buffer->lock();
  362. LLBufferArray::segment_iterator_t it;
  363. LLBufferArray::segment_iterator_t end = buffer->endSegment();
  364. LLSegment segment;
  365. it = buffer->constructSegmentAfter(mLastWritten, segment);
  366. #if 0
  367. if (mLastWritten == NULL)
  368. {
  369. it = buffer->beginSegment();
  370. segment = (*it);
  371. }
  372. else
  373. {
  374. it = buffer->getSegment(mLastWritten);
  375. segment = (*it);
  376. S32 size = segment.size();
  377. U8* data = segment.data();
  378. if (mLastWritten == data + size)
  379. {
  380. segment = *++it;
  381. }
  382. else
  383. {
  384. // *FIX: check the math on this one
  385. segment = LLSegment(it->getChannelMask(), mLastWritten + 1,
  386. size - (mLastWritten - data));
  387. }
  388. }
  389. #endif
  390. PUMP_DEBUG;
  391. apr_size_t len;
  392. bool done = false;
  393. apr_status_t status = APR_SUCCESS;
  394. while (it != end)
  395. {
  396. PUMP_DEBUG;
  397. if (it->isOnChannel(channels.in()))
  398. {
  399. PUMP_DEBUG;
  400. len = (apr_size_t)segment.size();
  401. status = apr_socket_send(
  402. mDestination->getSocket(),
  403. (const char*)segment.data(),
  404. &len);
  405. // We sometimes get a 'non-blocking socket operation could not be
  406. // completed immediately' error from apr_socket_send. In this
  407. // case we break and the data will be sent the next time the chain
  408. // is pumped.
  409. if (APR_STATUS_IS_EAGAIN(status))
  410. {
  411. ll_apr_warn_status(status);
  412. break;
  413. }
  414. mLastWritten = segment.data() + len - 1;
  415. PUMP_DEBUG;
  416. if (len < (apr_size_t)segment.size())
  417. {
  418. break;
  419. }
  420. }
  421. if (++it != end)
  422. {
  423. segment = *it;
  424. }
  425. else
  426. {
  427. done = true;
  428. }
  429. }
  430. buffer->unlock();
  431. PUMP_DEBUG;
  432. if (done && eos)
  433. {
  434. return STATUS_DONE;
  435. }
  436. return STATUS_OK;
  437. }