tcp_socket_resource_base.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502
  1. // Copyright 2013 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ppapi/proxy/tcp_socket_resource_base.h"
  5. #include <cstring>
  6. #include <iterator>
  7. #include "base/bind.h"
  8. #include "base/check_op.h"
  9. #include "base/notreached.h"
  10. #include "ppapi/c/pp_bool.h"
  11. #include "ppapi/c/pp_errors.h"
  12. #include "ppapi/proxy/error_conversion.h"
  13. #include "ppapi/proxy/ppapi_messages.h"
  14. #include "ppapi/proxy/tcp_socket_resource_constants.h"
  15. #include "ppapi/shared_impl/ppapi_globals.h"
  16. #include "ppapi/shared_impl/private/ppb_x509_certificate_private_shared.h"
  17. #include "ppapi/shared_impl/socket_option_data.h"
  18. #include "ppapi/shared_impl/var.h"
  19. #include "ppapi/shared_impl/var_tracker.h"
  20. #include "ppapi/thunk/enter.h"
  21. #include "ppapi/thunk/ppb_x509_certificate_private_api.h"
  22. namespace ppapi {
  23. namespace proxy {
  24. TCPSocketResourceBase::TCPSocketResourceBase(Connection connection,
  25. PP_Instance instance,
  26. TCPSocketVersion version)
  27. : PluginResource(connection, instance),
  28. state_(TCPSocketState::INITIAL),
  29. read_buffer_(NULL),
  30. bytes_to_read_(-1),
  31. accepted_tcp_socket_(NULL),
  32. version_(version) {
  33. local_addr_.size = 0;
  34. memset(local_addr_.data, 0,
  35. std::size(local_addr_.data) * sizeof(*local_addr_.data));
  36. remote_addr_.size = 0;
  37. memset(remote_addr_.data, 0,
  38. std::size(remote_addr_.data) * sizeof(*remote_addr_.data));
  39. }
  40. TCPSocketResourceBase::TCPSocketResourceBase(
  41. Connection connection,
  42. PP_Instance instance,
  43. TCPSocketVersion version,
  44. const PP_NetAddress_Private& local_addr,
  45. const PP_NetAddress_Private& remote_addr)
  46. : PluginResource(connection, instance),
  47. state_(TCPSocketState::CONNECTED),
  48. read_buffer_(NULL),
  49. bytes_to_read_(-1),
  50. local_addr_(local_addr),
  51. remote_addr_(remote_addr),
  52. accepted_tcp_socket_(NULL),
  53. version_(version) {
  54. }
  55. TCPSocketResourceBase::~TCPSocketResourceBase() {
  56. CloseImpl();
  57. }
  58. int32_t TCPSocketResourceBase::BindImpl(
  59. const PP_NetAddress_Private* addr,
  60. scoped_refptr<TrackedCallback> callback) {
  61. if (!addr)
  62. return PP_ERROR_BADARGUMENT;
  63. if (state_.IsPending(TCPSocketState::BIND))
  64. return PP_ERROR_INPROGRESS;
  65. if (!state_.IsValidTransition(TCPSocketState::BIND))
  66. return PP_ERROR_FAILED;
  67. bind_callback_ = callback;
  68. state_.SetPendingTransition(TCPSocketState::BIND);
  69. Call<PpapiPluginMsg_TCPSocket_BindReply>(
  70. BROWSER, PpapiHostMsg_TCPSocket_Bind(*addr),
  71. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgBindReply,
  72. base::Unretained(this)),
  73. callback);
  74. return PP_OK_COMPLETIONPENDING;
  75. }
  76. int32_t TCPSocketResourceBase::ConnectImpl(
  77. const char* host,
  78. uint16_t port,
  79. scoped_refptr<TrackedCallback> callback) {
  80. if (!host)
  81. return PP_ERROR_BADARGUMENT;
  82. if (state_.IsPending(TCPSocketState::CONNECT))
  83. return PP_ERROR_INPROGRESS;
  84. if (!state_.IsValidTransition(TCPSocketState::CONNECT))
  85. return PP_ERROR_FAILED;
  86. connect_callback_ = callback;
  87. state_.SetPendingTransition(TCPSocketState::CONNECT);
  88. Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
  89. BROWSER, PpapiHostMsg_TCPSocket_Connect(host, port),
  90. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgConnectReply,
  91. base::Unretained(this)),
  92. callback);
  93. return PP_OK_COMPLETIONPENDING;
  94. }
  95. int32_t TCPSocketResourceBase::ConnectWithNetAddressImpl(
  96. const PP_NetAddress_Private* addr,
  97. scoped_refptr<TrackedCallback> callback) {
  98. if (!addr)
  99. return PP_ERROR_BADARGUMENT;
  100. if (state_.IsPending(TCPSocketState::CONNECT))
  101. return PP_ERROR_INPROGRESS;
  102. if (!state_.IsValidTransition(TCPSocketState::CONNECT))
  103. return PP_ERROR_FAILED;
  104. connect_callback_ = callback;
  105. state_.SetPendingTransition(TCPSocketState::CONNECT);
  106. Call<PpapiPluginMsg_TCPSocket_ConnectReply>(
  107. BROWSER, PpapiHostMsg_TCPSocket_ConnectWithNetAddress(*addr),
  108. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgConnectReply,
  109. base::Unretained(this)),
  110. callback);
  111. return PP_OK_COMPLETIONPENDING;
  112. }
  113. PP_Bool TCPSocketResourceBase::GetLocalAddressImpl(
  114. PP_NetAddress_Private* local_addr) {
  115. if (!state_.IsBound() || !local_addr)
  116. return PP_FALSE;
  117. *local_addr = local_addr_;
  118. return PP_TRUE;
  119. }
  120. PP_Bool TCPSocketResourceBase::GetRemoteAddressImpl(
  121. PP_NetAddress_Private* remote_addr) {
  122. if (!state_.IsConnected() || !remote_addr)
  123. return PP_FALSE;
  124. *remote_addr = remote_addr_;
  125. return PP_TRUE;
  126. }
  127. int32_t TCPSocketResourceBase::SSLHandshakeImpl(
  128. const char* server_name,
  129. uint16_t server_port,
  130. scoped_refptr<TrackedCallback> callback) {
  131. if (!server_name)
  132. return PP_ERROR_BADARGUMENT;
  133. if (state_.IsPending(TCPSocketState::SSL_CONNECT) ||
  134. TrackedCallback::IsPending(read_callback_) ||
  135. TrackedCallback::IsPending(write_callback_)) {
  136. return PP_ERROR_INPROGRESS;
  137. }
  138. if (!state_.IsValidTransition(TCPSocketState::SSL_CONNECT))
  139. return PP_ERROR_FAILED;
  140. ssl_handshake_callback_ = callback;
  141. state_.SetPendingTransition(TCPSocketState::SSL_CONNECT);
  142. Call<PpapiPluginMsg_TCPSocket_SSLHandshakeReply>(
  143. BROWSER,
  144. PpapiHostMsg_TCPSocket_SSLHandshake(server_name, server_port,
  145. trusted_certificates_,
  146. untrusted_certificates_),
  147. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply,
  148. base::Unretained(this)),
  149. callback);
  150. return PP_OK_COMPLETIONPENDING;
  151. }
  152. PP_Resource TCPSocketResourceBase::GetServerCertificateImpl() {
  153. if (!server_certificate_.get())
  154. return 0;
  155. return server_certificate_->GetReference();
  156. }
  157. PP_Bool TCPSocketResourceBase::AddChainBuildingCertificateImpl(
  158. PP_Resource certificate,
  159. PP_Bool trusted) {
  160. // TODO(raymes): This is exposed in the private PPB_TCPSocket_Private
  161. // interface for Flash but isn't currently implemented due to security
  162. // implications. It is exposed so that it can be hooked up on the Flash side
  163. // and if we decide to implement it we can do so without modifying the Flash
  164. // codebase.
  165. NOTIMPLEMENTED();
  166. return PP_FALSE;
  167. }
  168. int32_t TCPSocketResourceBase::ReadImpl(
  169. char* buffer,
  170. int32_t bytes_to_read,
  171. scoped_refptr<TrackedCallback> callback) {
  172. if (!buffer || bytes_to_read <= 0)
  173. return PP_ERROR_BADARGUMENT;
  174. if (!state_.IsConnected())
  175. return PP_ERROR_FAILED;
  176. if (TrackedCallback::IsPending(read_callback_) ||
  177. state_.IsPending(TCPSocketState::SSL_CONNECT))
  178. return PP_ERROR_INPROGRESS;
  179. read_buffer_ = buffer;
  180. bytes_to_read_ =
  181. std::min(bytes_to_read,
  182. static_cast<int32_t>(TCPSocketResourceConstants::kMaxReadSize));
  183. read_callback_ = callback;
  184. Call<PpapiPluginMsg_TCPSocket_ReadReply>(
  185. BROWSER, PpapiHostMsg_TCPSocket_Read(bytes_to_read_),
  186. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgReadReply,
  187. base::Unretained(this)),
  188. callback);
  189. return PP_OK_COMPLETIONPENDING;
  190. }
  191. int32_t TCPSocketResourceBase::WriteImpl(
  192. const char* buffer,
  193. int32_t bytes_to_write,
  194. scoped_refptr<TrackedCallback> callback) {
  195. if (!buffer || bytes_to_write <= 0)
  196. return PP_ERROR_BADARGUMENT;
  197. if (!state_.IsConnected())
  198. return PP_ERROR_FAILED;
  199. if (TrackedCallback::IsPending(write_callback_) ||
  200. state_.IsPending(TCPSocketState::SSL_CONNECT))
  201. return PP_ERROR_INPROGRESS;
  202. if (bytes_to_write > TCPSocketResourceConstants::kMaxWriteSize)
  203. bytes_to_write = TCPSocketResourceConstants::kMaxWriteSize;
  204. write_callback_ = callback;
  205. Call<PpapiPluginMsg_TCPSocket_WriteReply>(
  206. BROWSER,
  207. PpapiHostMsg_TCPSocket_Write(std::string(buffer, bytes_to_write)),
  208. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgWriteReply,
  209. base::Unretained(this)),
  210. callback);
  211. return PP_OK_COMPLETIONPENDING;
  212. }
  213. int32_t TCPSocketResourceBase::ListenImpl(
  214. int32_t backlog,
  215. scoped_refptr<TrackedCallback> callback) {
  216. if (backlog <= 0)
  217. return PP_ERROR_BADARGUMENT;
  218. if (state_.IsPending(TCPSocketState::LISTEN))
  219. return PP_ERROR_INPROGRESS;
  220. if (!state_.IsValidTransition(TCPSocketState::LISTEN))
  221. return PP_ERROR_FAILED;
  222. listen_callback_ = callback;
  223. state_.SetPendingTransition(TCPSocketState::LISTEN);
  224. Call<PpapiPluginMsg_TCPSocket_ListenReply>(
  225. BROWSER, PpapiHostMsg_TCPSocket_Listen(backlog),
  226. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgListenReply,
  227. base::Unretained(this)),
  228. callback);
  229. return PP_OK_COMPLETIONPENDING;
  230. }
  231. int32_t TCPSocketResourceBase::AcceptImpl(
  232. PP_Resource* accepted_tcp_socket,
  233. scoped_refptr<TrackedCallback> callback) {
  234. if (!accepted_tcp_socket)
  235. return PP_ERROR_BADARGUMENT;
  236. if (TrackedCallback::IsPending(accept_callback_))
  237. return PP_ERROR_INPROGRESS;
  238. if (state_.state() != TCPSocketState::LISTENING)
  239. return PP_ERROR_FAILED;
  240. accept_callback_ = callback;
  241. accepted_tcp_socket_ = accepted_tcp_socket;
  242. Call<PpapiPluginMsg_TCPSocket_AcceptReply>(
  243. BROWSER, PpapiHostMsg_TCPSocket_Accept(),
  244. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgAcceptReply,
  245. base::Unretained(this)),
  246. callback);
  247. return PP_OK_COMPLETIONPENDING;
  248. }
  249. void TCPSocketResourceBase::CloseImpl() {
  250. if (state_.state() == TCPSocketState::CLOSED)
  251. return;
  252. state_.DoTransition(TCPSocketState::CLOSE, true);
  253. Post(BROWSER, PpapiHostMsg_TCPSocket_Close());
  254. PostAbortIfNecessary(&bind_callback_);
  255. PostAbortIfNecessary(&connect_callback_);
  256. PostAbortIfNecessary(&ssl_handshake_callback_);
  257. PostAbortIfNecessary(&read_callback_);
  258. PostAbortIfNecessary(&write_callback_);
  259. PostAbortIfNecessary(&listen_callback_);
  260. PostAbortIfNecessary(&accept_callback_);
  261. read_buffer_ = NULL;
  262. bytes_to_read_ = -1;
  263. server_certificate_.reset();
  264. accepted_tcp_socket_ = NULL;
  265. }
  266. int32_t TCPSocketResourceBase::SetOptionImpl(
  267. PP_TCPSocket_Option name,
  268. const PP_Var& value,
  269. bool check_connect_state,
  270. scoped_refptr<TrackedCallback> callback) {
  271. SocketOptionData option_data;
  272. switch (name) {
  273. case PP_TCPSOCKET_OPTION_NO_DELAY: {
  274. if (check_connect_state && !state_.IsConnected())
  275. return PP_ERROR_FAILED;
  276. if (value.type != PP_VARTYPE_BOOL)
  277. return PP_ERROR_BADARGUMENT;
  278. option_data.SetBool(PP_ToBool(value.value.as_bool));
  279. break;
  280. }
  281. case PP_TCPSOCKET_OPTION_SEND_BUFFER_SIZE:
  282. case PP_TCPSOCKET_OPTION_RECV_BUFFER_SIZE: {
  283. if (check_connect_state && !state_.IsConnected())
  284. return PP_ERROR_FAILED;
  285. if (value.type != PP_VARTYPE_INT32)
  286. return PP_ERROR_BADARGUMENT;
  287. option_data.SetInt32(value.value.as_int);
  288. break;
  289. }
  290. default: {
  291. NOTREACHED();
  292. return PP_ERROR_BADARGUMENT;
  293. }
  294. }
  295. set_option_callbacks_.push(callback);
  296. Call<PpapiPluginMsg_TCPSocket_SetOptionReply>(
  297. BROWSER, PpapiHostMsg_TCPSocket_SetOption(name, option_data),
  298. base::BindOnce(&TCPSocketResourceBase::OnPluginMsgSetOptionReply,
  299. base::Unretained(this)),
  300. callback);
  301. return PP_OK_COMPLETIONPENDING;
  302. }
  303. void TCPSocketResourceBase::PostAbortIfNecessary(
  304. scoped_refptr<TrackedCallback>* callback) {
  305. if (TrackedCallback::IsPending(*callback))
  306. (*callback)->PostAbort();
  307. }
  308. void TCPSocketResourceBase::OnPluginMsgBindReply(
  309. const ResourceMessageReplyParams& params,
  310. const PP_NetAddress_Private& local_addr) {
  311. // It is possible that CloseImpl() has been called. We don't want to update
  312. // class members in this case.
  313. if (!state_.IsPending(TCPSocketState::BIND))
  314. return;
  315. DCHECK(TrackedCallback::IsPending(bind_callback_));
  316. if (params.result() == PP_OK) {
  317. local_addr_ = local_addr;
  318. state_.CompletePendingTransition(true);
  319. } else {
  320. state_.CompletePendingTransition(false);
  321. }
  322. RunCallback(bind_callback_, params.result());
  323. }
  324. void TCPSocketResourceBase::OnPluginMsgConnectReply(
  325. const ResourceMessageReplyParams& params,
  326. const PP_NetAddress_Private& local_addr,
  327. const PP_NetAddress_Private& remote_addr) {
  328. // It is possible that CloseImpl() has been called. We don't want to update
  329. // class members in this case.
  330. if (!state_.IsPending(TCPSocketState::CONNECT))
  331. return;
  332. DCHECK(TrackedCallback::IsPending(connect_callback_));
  333. if (params.result() == PP_OK) {
  334. local_addr_ = local_addr;
  335. remote_addr_ = remote_addr;
  336. state_.CompletePendingTransition(true);
  337. } else {
  338. if (version_ == TCP_SOCKET_VERSION_1_1_OR_ABOVE) {
  339. state_.CompletePendingTransition(false);
  340. } else {
  341. // In order to maintain backward compatibility, allow to connect the
  342. // socket again.
  343. state_ = TCPSocketState(TCPSocketState::INITIAL);
  344. }
  345. }
  346. RunCallback(connect_callback_, params.result());
  347. }
  348. void TCPSocketResourceBase::OnPluginMsgSSLHandshakeReply(
  349. const ResourceMessageReplyParams& params,
  350. const PPB_X509Certificate_Fields& certificate_fields) {
  351. // It is possible that CloseImpl() has been called. We don't want to
  352. // update class members in this case.
  353. if (!state_.IsPending(TCPSocketState::SSL_CONNECT))
  354. return;
  355. DCHECK(TrackedCallback::IsPending(ssl_handshake_callback_));
  356. if (params.result() == PP_OK) {
  357. state_.CompletePendingTransition(true);
  358. server_certificate_ = new PPB_X509Certificate_Private_Shared(
  359. OBJECT_IS_PROXY,
  360. pp_instance(),
  361. certificate_fields);
  362. } else {
  363. state_.CompletePendingTransition(false);
  364. }
  365. RunCallback(ssl_handshake_callback_, params.result());
  366. }
  367. void TCPSocketResourceBase::OnPluginMsgReadReply(
  368. const ResourceMessageReplyParams& params,
  369. const std::string& data) {
  370. // It is possible that CloseImpl() has been called. We shouldn't access the
  371. // buffer in that case. The user may have released it.
  372. if (!state_.IsConnected() || !TrackedCallback::IsPending(read_callback_) ||
  373. !read_buffer_) {
  374. return;
  375. }
  376. const bool succeeded = params.result() == PP_OK;
  377. if (succeeded) {
  378. CHECK_LE(static_cast<int32_t>(data.size()), bytes_to_read_);
  379. if (!data.empty())
  380. memmove(read_buffer_, data.c_str(), data.size());
  381. }
  382. read_buffer_ = NULL;
  383. bytes_to_read_ = -1;
  384. RunCallback(read_callback_,
  385. succeeded ? static_cast<int32_t>(data.size()) : params.result());
  386. }
  387. void TCPSocketResourceBase::OnPluginMsgWriteReply(
  388. const ResourceMessageReplyParams& params) {
  389. if (!state_.IsConnected() || !TrackedCallback::IsPending(write_callback_))
  390. return;
  391. RunCallback(write_callback_, params.result());
  392. }
  393. void TCPSocketResourceBase::OnPluginMsgListenReply(
  394. const ResourceMessageReplyParams& params) {
  395. if (!state_.IsPending(TCPSocketState::LISTEN))
  396. return;
  397. DCHECK(TrackedCallback::IsPending(listen_callback_));
  398. state_.CompletePendingTransition(params.result() == PP_OK);
  399. RunCallback(listen_callback_, params.result());
  400. }
  401. void TCPSocketResourceBase::OnPluginMsgAcceptReply(
  402. const ResourceMessageReplyParams& params,
  403. int pending_host_id,
  404. const PP_NetAddress_Private& local_addr,
  405. const PP_NetAddress_Private& remote_addr) {
  406. // It is possible that CloseImpl() has been called. We shouldn't access the
  407. // output parameter in that case. The user may have released it.
  408. if (state_.state() != TCPSocketState::LISTENING ||
  409. !TrackedCallback::IsPending(accept_callback_) || !accepted_tcp_socket_) {
  410. return;
  411. }
  412. if (params.result() == PP_OK) {
  413. *accepted_tcp_socket_ = CreateAcceptedSocket(pending_host_id, local_addr,
  414. remote_addr);
  415. }
  416. accepted_tcp_socket_ = NULL;
  417. RunCallback(accept_callback_, params.result());
  418. }
  419. void TCPSocketResourceBase::OnPluginMsgSetOptionReply(
  420. const ResourceMessageReplyParams& params) {
  421. if (set_option_callbacks_.empty()) {
  422. NOTREACHED();
  423. return;
  424. }
  425. scoped_refptr<TrackedCallback> callback = set_option_callbacks_.front();
  426. set_option_callbacks_.pop();
  427. if (TrackedCallback::IsPending(callback))
  428. RunCallback(callback, params.result());
  429. }
  430. void TCPSocketResourceBase::RunCallback(scoped_refptr<TrackedCallback> callback,
  431. int32_t pp_result) {
  432. callback->Run(ConvertNetworkAPIErrorForCompatibility(
  433. pp_result, version_ == TCP_SOCKET_VERSION_PRIVATE));
  434. }
  435. } // namespace ppapi
  436. } // namespace proxy