llpluginmessagepipe.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:8k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llpluginmessagepipe.cpp
  3.  * @brief Classes that implement connections from the plugin system to pipes/pumps.
  4.  *
  5.  * @cond
  6.  * $LicenseInfo:firstyear=2008&license=viewergpl$
  7.  * 
  8.  * Copyright (c) 2008-2010, Linden Research, Inc.
  9.  * 
  10.  * Second Life Viewer Source Code
  11.  * The source code in this file ("Source Code") is provided by Linden Lab
  12.  * to you under the terms of the GNU General Public License, version 2.0
  13.  * ("GPL"), unless you have obtained a separate licensing agreement
  14.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  15.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17.  * 
  18.  * There are special exceptions to the terms and conditions of the GPL as
  19.  * it is applied to this Source Code. View the full text of the exception
  20.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  21.  * online at
  22.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23.  * 
  24.  * By copying, modifying or distributing this software, you acknowledge
  25.  * that you have read and understood your obligations described above,
  26.  * and agree to abide by those obligations.
  27.  * 
  28.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30.  * COMPLETENESS OR PERFORMANCE.
  31.  * $/LicenseInfo$
  32.  * @endcond
  33.  */
  34. #include "linden_common.h"
  35. #include "llpluginmessagepipe.h"
  36. #include "llbufferstream.h"
  37. #include "llapr.h"
  38. static const char MESSAGE_DELIMITER = '';
  39. LLPluginMessagePipeOwner::LLPluginMessagePipeOwner() :
  40. mMessagePipe(NULL),
  41. mSocketError(APR_SUCCESS)
  42. {
  43. }
  44. // virtual 
  45. LLPluginMessagePipeOwner::~LLPluginMessagePipeOwner()
  46. {
  47. killMessagePipe();
  48. }
  49. // virtual 
  50. apr_status_t LLPluginMessagePipeOwner::socketError(apr_status_t error)
  51. mSocketError = error;
  52. return error; 
  53. };
  54. //virtual 
  55. void LLPluginMessagePipeOwner::setMessagePipe(LLPluginMessagePipe *read_pipe)
  56. {
  57. // Save a reference to this pipe
  58. mMessagePipe = read_pipe;
  59. }
  60. bool LLPluginMessagePipeOwner::canSendMessage(void)
  61. {
  62. return (mMessagePipe != NULL);
  63. }
  64. bool LLPluginMessagePipeOwner::writeMessageRaw(const std::string &message)
  65. {
  66. bool result = true;
  67. if(mMessagePipe != NULL)
  68. {
  69. result = mMessagePipe->addMessage(message);
  70. }
  71. else
  72. {
  73. LL_WARNS("Plugin") << "dropping message: " << message << LL_ENDL;
  74. result = false;
  75. }
  76. return result;
  77. }
  78. void LLPluginMessagePipeOwner::killMessagePipe(void)
  79. {
  80. if(mMessagePipe != NULL)
  81. {
  82. delete mMessagePipe;
  83. mMessagePipe = NULL;
  84. }
  85. }
  86. LLPluginMessagePipe::LLPluginMessagePipe(LLPluginMessagePipeOwner *owner, LLSocket::ptr_t socket)
  87. {
  88. mOwner = owner;
  89. mOwner->setMessagePipe(this);
  90. mSocket = socket;
  91. }
  92. LLPluginMessagePipe::~LLPluginMessagePipe()
  93. {
  94. if(mOwner != NULL)
  95. {
  96. mOwner->setMessagePipe(NULL);
  97. }
  98. }
  99. bool LLPluginMessagePipe::addMessage(const std::string &message)
  100. {
  101. // queue the message for later output
  102. mOutput += message;
  103. mOutput += MESSAGE_DELIMITER; // message separator
  104. return true;
  105. }
  106. void LLPluginMessagePipe::clearOwner(void)
  107. {
  108. // The owner is done with this pipe.  The next call to process_impl should send any remaining data and exit.
  109. mOwner = NULL;
  110. }
  111. void LLPluginMessagePipe::setSocketTimeout(apr_interval_time_t timeout_usec)
  112. {
  113. // We never want to sleep forever, so force negative timeouts to become non-blocking.
  114. // according to this page: http://dev.ariel-networks.com/apr/apr-tutorial/html/apr-tutorial-13.html
  115. // blocking/non-blocking with apr sockets is somewhat non-portable.
  116. if(timeout_usec <= 0)
  117. {
  118. // Make the socket non-blocking
  119. apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1);
  120. apr_socket_timeout_set(mSocket->getSocket(), 0);
  121. }
  122. else
  123. {
  124. // Make the socket blocking-with-timeout
  125. apr_socket_opt_set(mSocket->getSocket(), APR_SO_NONBLOCK, 1);
  126. apr_socket_timeout_set(mSocket->getSocket(), timeout_usec);
  127. }
  128. }
  129. bool LLPluginMessagePipe::pump(F64 timeout)
  130. {
  131. bool result = true;
  132. if(mSocket)
  133. {
  134. apr_status_t status;
  135. apr_size_t size;
  136. if(!mOutput.empty())
  137. {
  138. // write any outgoing messages
  139. size = (apr_size_t)mOutput.size();
  140. setSocketTimeout(0);
  141. // LL_INFOS("Plugin") << "before apr_socket_send, size = " << size << LL_ENDL;
  142. status = apr_socket_send(
  143. mSocket->getSocket(),
  144. (const char*)mOutput.data(),
  145. &size);
  146. // LL_INFOS("Plugin") << "after apr_socket_send, size = " << size << LL_ENDL;
  147. if(status == APR_SUCCESS)
  148. {
  149. // success
  150. mOutput = mOutput.substr(size);
  151. }
  152. else if(APR_STATUS_IS_EAGAIN(status))
  153. {
  154. // Socket buffer is full... 
  155. // remove the written part from the buffer and try again later.
  156. mOutput = mOutput.substr(size);
  157. }
  158. else 
  159. {
  160. // some other error
  161. // Treat this as fatal.
  162. ll_apr_warn_status(status);
  163. if(mOwner)
  164. {
  165. mOwner->socketError(status);
  166. }
  167. result = false;
  168. }
  169. }
  170. // FIXME: For some reason, the apr timeout stuff isn't working properly on windows.
  171. // Until such time as we figure out why, don't try to use the socket timeout -- just sleep here instead.
  172. #if LL_WINDOWS
  173. if(result)
  174. {
  175. if(timeout != 0.0f)
  176. {
  177. ms_sleep((int)(timeout * 1000.0f));
  178. timeout = 0.0f;
  179. }
  180. }
  181. #endif
  182. // Check for incoming messages
  183. if(result)
  184. {
  185. char input_buf[1024];
  186. apr_size_t request_size;
  187. // Start out by reading one byte, so that any data received will wake us up.
  188. request_size = 1;
  189. // and use the timeout so we'll sleep if no data is available.
  190. setSocketTimeout((apr_interval_time_t)(timeout * 1000000));
  191. while(1)
  192. {
  193. size = request_size;
  194. // LL_INFOS("Plugin") << "before apr_socket_recv, size = " << size << LL_ENDL;
  195. status = apr_socket_recv(
  196. mSocket->getSocket(), 
  197. input_buf, 
  198. &size);
  199. // LL_INFOS("Plugin") << "after apr_socket_recv, size = " << size << LL_ENDL;
  200. if(size > 0)
  201. mInput.append(input_buf, size);
  202. if(status == APR_SUCCESS)
  203. {
  204. // llinfos << "success, read " << size << llendl;
  205. if(size != request_size)
  206. {
  207. // This was a short read, so we're done.
  208. break;
  209. }
  210. }
  211. else if(APR_STATUS_IS_TIMEUP(status))
  212. {
  213. // llinfos << "TIMEUP, read " << size << llendl;
  214. // Timeout was hit.  Since the initial read is 1 byte, this should never be a partial read.
  215. break;
  216. }
  217. else if(APR_STATUS_IS_EAGAIN(status))
  218. {
  219. // llinfos << "EAGAIN, read " << size << llendl;
  220. // We've been doing partial reads, and we're done now.
  221. break;
  222. }
  223. else
  224. {
  225. // some other error
  226. // Treat this as fatal.
  227. ll_apr_warn_status(status);
  228. if(mOwner)
  229. {
  230. mOwner->socketError(status);
  231. }
  232. result = false;
  233. break;
  234. }
  235. // Second and subsequent reads should not use the timeout
  236. setSocketTimeout(0);
  237. // and should try to fill the input buffer
  238. request_size = sizeof(input_buf);
  239. }
  240. processInput();
  241. }
  242. }
  243. if(!result)
  244. {
  245. // If we got an error, we're done.
  246. LL_INFOS("Plugin") << "Error from socket, cleaning up." << LL_ENDL;
  247. delete this;
  248. }
  249. return result;
  250. }
  251. void LLPluginMessagePipe::processInput(void)
  252. {
  253. // Look for input delimiter(s) in the input buffer.
  254. int start = 0;
  255. int delim;
  256. while((delim = mInput.find(MESSAGE_DELIMITER, start)) != std::string::npos)
  257. {
  258. // Let the owner process this message
  259. if (mOwner)
  260. {
  261. mOwner->receiveMessageRaw(mInput.substr(start, delim - start));
  262. }
  263. else
  264. {
  265. LL_WARNS("Plugin") << "!mOwner" << LL_ENDL;
  266. }
  267. start = delim + 1;
  268. }
  269. // Remove delivered messages from the input buffer.
  270. if(start != 0)
  271. mInput = mInput.substr(start);
  272. }