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
5#include "ppapi/proxy/tcp_server_socket_private_resource.h"
6
7#include "ppapi/proxy/plugin_dispatcher.h"
8#include "ppapi/proxy/ppapi_messages.h"
9#include "ppapi/proxy/ppb_tcp_socket_private_proxy.h"
10
11namespace ppapi {
12namespace proxy {
13
14TCPServerSocketPrivateResource::TCPServerSocketPrivateResource(
15    Connection connection,
16    PP_Instance instance)
17    : PluginResource(connection, instance),
18      state_(STATE_BEFORE_LISTENING),
19      local_addr_(),
20      plugin_dispatcher_id_(0) {
21  SendCreate(BROWSER, PpapiHostMsg_TCPServerSocket_CreatePrivate());
22
23  PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
24  if (dispatcher)
25    plugin_dispatcher_id_ = dispatcher->plugin_dispatcher_id();
26  else
27    NOTREACHED();
28}
29
30TCPServerSocketPrivateResource::~TCPServerSocketPrivateResource() {
31}
32
33thunk::PPB_TCPServerSocket_Private_API*
34TCPServerSocketPrivateResource::AsPPB_TCPServerSocket_Private_API() {
35  return this;
36}
37
38int32_t TCPServerSocketPrivateResource::Listen(
39    const PP_NetAddress_Private* addr,
40    int32_t backlog,
41    scoped_refptr<TrackedCallback> callback) {
42  if (!addr)
43    return PP_ERROR_BADARGUMENT;
44  if (state_ != STATE_BEFORE_LISTENING)
45    return PP_ERROR_FAILED;
46  if (TrackedCallback::IsPending(listen_callback_))
47    return PP_ERROR_INPROGRESS;
48
49  listen_callback_ = callback;
50
51  // Send the request, the browser will call us back via ListenACK
52  Call<PpapiPluginMsg_TCPServerSocket_ListenReply>(
53      BROWSER,
54      PpapiHostMsg_TCPServerSocket_Listen(*addr, backlog),
55      base::Bind(&TCPServerSocketPrivateResource::OnPluginMsgListenReply,
56                 base::Unretained(this)));
57  return PP_OK_COMPLETIONPENDING;
58}
59
60int32_t TCPServerSocketPrivateResource::Accept(
61    PP_Resource* tcp_socket,
62    scoped_refptr<TrackedCallback> callback) {
63  if (!tcp_socket)
64    return PP_ERROR_BADARGUMENT;
65  if (state_ != STATE_LISTENING)
66    return PP_ERROR_FAILED;
67  if (TrackedCallback::IsPending(accept_callback_))
68    return PP_ERROR_INPROGRESS;
69
70  accept_callback_ = callback;
71
72  Call<PpapiPluginMsg_TCPServerSocket_AcceptReply>(
73      BROWSER,
74      PpapiHostMsg_TCPServerSocket_Accept(plugin_dispatcher_id_),
75      base::Bind(&TCPServerSocketPrivateResource::OnPluginMsgAcceptReply,
76                 base::Unretained(this), tcp_socket));
77  return PP_OK_COMPLETIONPENDING;
78}
79
80int32_t TCPServerSocketPrivateResource::GetLocalAddress(
81    PP_NetAddress_Private* addr) {
82  if (!addr)
83    return PP_ERROR_BADARGUMENT;
84  if (state_ != STATE_LISTENING)
85    return PP_ERROR_FAILED;
86  *addr = local_addr_;
87  return PP_OK;
88}
89
90void TCPServerSocketPrivateResource::StopListening() {
91  if (state_ == STATE_CLOSED)
92    return;
93  state_ = STATE_CLOSED;
94  Post(BROWSER, PpapiHostMsg_TCPServerSocket_StopListening());
95  if (TrackedCallback::IsPending(listen_callback_))
96    listen_callback_->PostAbort();
97  if (TrackedCallback::IsPending(accept_callback_))
98    accept_callback_->PostAbort();
99}
100
101void TCPServerSocketPrivateResource::OnPluginMsgListenReply(
102    const ResourceMessageReplyParams& params,
103    const PP_NetAddress_Private& local_addr) {
104  if (state_ != STATE_BEFORE_LISTENING ||
105      !TrackedCallback::IsPending(listen_callback_)) {
106    return;
107  }
108  if (params.result() == PP_OK) {
109    local_addr_ = local_addr;
110    state_ = STATE_LISTENING;
111  }
112  listen_callback_->Run(params.result());
113}
114
115void TCPServerSocketPrivateResource::OnPluginMsgAcceptReply(
116    PP_Resource* tcp_socket,
117    const ResourceMessageReplyParams& params,
118    uint32 accepted_socket_id,
119    const PP_NetAddress_Private& local_addr,
120    const PP_NetAddress_Private& remote_addr) {
121  DCHECK(tcp_socket);
122  if (state_ != STATE_LISTENING ||
123      !TrackedCallback::IsPending(accept_callback_)) {
124    return;
125  }
126  if (params.result() == PP_OK) {
127    *tcp_socket =
128        PPB_TCPSocket_Private_Proxy::CreateProxyResourceForConnectedSocket(
129            pp_instance(),
130            accepted_socket_id,
131            local_addr,
132            remote_addr);
133  }
134  accept_callback_->Run(params.result());
135}
136
137}  // namespace proxy
138}  // namespace ppapi
139