c974e654c32fe16d0b4af389409c40cad76f7b95
[platform/framework/web/crosswalk.git] / src / xwalk / sysapps / raw_socket / udp_socket_object.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/sysapps/raw_socket/udp_socket_object.h"
6
7 #include <string.h>
8
9 #include "base/logging.h"
10 #include "net/base/net_errors.h"
11 #include "xwalk/sysapps/raw_socket/udp_socket.h"
12
13 using namespace xwalk::jsapi::udp_socket; // NOLINT
14 using namespace xwalk::jsapi::raw_socket; // NOLINT
15
16 namespace {
17
18 const unsigned kBufferSize = 4096;
19
20 }  // namespace
21
22 namespace xwalk {
23 namespace sysapps {
24
25 UDPSocketObject::UDPSocketObject()
26     : has_write_pending_(false),
27       is_suspended_(false),
28       is_reading_(false),
29       read_buffer_(new net::IOBuffer(kBufferSize)),
30       write_buffer_(new net::IOBuffer(kBufferSize)),
31       resolver_(net::HostResolver::CreateDefaultResolver(NULL)),
32       single_resolver_(new net::SingleRequestHostResolver(resolver_.get())) {
33   handler_.Register("init",
34       base::Bind(&UDPSocketObject::OnInit, base::Unretained(this)));
35   handler_.Register("_close",
36       base::Bind(&UDPSocketObject::OnClose, base::Unretained(this)));
37   handler_.Register("suspend",
38       base::Bind(&UDPSocketObject::OnSuspend, base::Unretained(this)));
39   handler_.Register("resume",
40       base::Bind(&UDPSocketObject::OnResume, base::Unretained(this)));
41   handler_.Register("joinMulticast",
42       base::Bind(&UDPSocketObject::OnJoinMulticast, base::Unretained(this)));
43   handler_.Register("leaveMulticast",
44       base::Bind(&UDPSocketObject::OnLeaveMulticast, base::Unretained(this)));
45   handler_.Register("_sendString",
46       base::Bind(&UDPSocketObject::OnSendString, base::Unretained(this)));
47 }
48
49 UDPSocketObject::~UDPSocketObject() {}
50
51 void UDPSocketObject::DoRead() {
52   if (!socket_->is_connected())
53     return;
54
55   is_reading_ = true;
56
57   int ret = socket_->RecvFrom(read_buffer_.get(),
58                               kBufferSize,
59                               &from_,
60                               base::Bind(&UDPSocketObject::OnRead,
61                                          base::Unretained(this)));
62
63   if (ret > 0)
64     OnRead(ret);
65 }
66
67 void UDPSocketObject::OnInit(scoped_ptr<XWalkExtensionFunctionInfo> info) {
68   scoped_ptr<Init::Params> params(Init::Params::Create(*info->arguments()));
69   if (!params) {
70     LOG(WARNING) << "Malformed parameters passed to " << info->name();
71     setReadyState(READY_STATE_CLOSED);
72     DispatchEvent("error");
73     return;
74   }
75
76   socket_.reset(new net::UDPSocket(net::DatagramSocket::DEFAULT_BIND,
77                                    net::RandIntCallback(),
78                                    NULL,
79                                    net::NetLog::Source()));
80
81   if (!params->options) {
82     OnConnectionOpen(net::OK);
83     return;
84   }
85
86   if (!params->options->local_address.empty()) {
87     net::IPAddressNumber ip_number;
88     if (!net::ParseIPLiteralToNumber(params->options->local_address,
89                                      &ip_number)) {
90       LOG(WARNING) << "Invalid IP address " << params->options->local_address;
91       setReadyState(READY_STATE_CLOSED);
92       DispatchEvent("error");
93       return;
94     }
95
96     if (params->options->address_reuse)
97       socket_->AllowAddressReuse();
98
99     net::IPEndPoint end_point(ip_number, params->options->local_port);
100     if (socket_->Bind(end_point) != net::OK) {
101       LOG(WARNING) << "Can't bind to " << end_point.ToString();
102       setReadyState(READY_STATE_CLOSED);
103       DispatchEvent("error");
104       return;
105     }
106
107     DoRead();
108     OnConnectionOpen(net::OK);
109     return;
110   }
111
112   if (params->options->remote_address.empty() ||
113       !params->options->remote_port) {
114     OnConnectionOpen(net::OK);
115     return;
116   }
117
118   net::HostResolver::RequestInfo request_info(net::HostPortPair(
119       params->options->remote_address, params->options->remote_port));
120
121   int ret = single_resolver_->Resolve(
122       request_info,
123       net::DEFAULT_PRIORITY,
124       &addresses_,
125       base::Bind(&UDPSocketObject::OnConnectionOpen,
126                  base::Unretained(this)),
127       net::BoundNetLog());
128
129   if (ret != net::ERR_IO_PENDING)
130     OnConnectionOpen(ret);
131 }
132
133 void UDPSocketObject::OnClose(scoped_ptr<XWalkExtensionFunctionInfo> info) {
134   socket_.reset();
135 }
136
137 void UDPSocketObject::OnSuspend(scoped_ptr<XWalkExtensionFunctionInfo> info) {
138   is_suspended_ = true;
139 }
140
141 void UDPSocketObject::OnResume(scoped_ptr<XWalkExtensionFunctionInfo> info) {
142   is_suspended_ = false;
143 }
144
145 void UDPSocketObject::OnJoinMulticast(
146     scoped_ptr<XWalkExtensionFunctionInfo> info) {
147 }
148
149 void UDPSocketObject::OnLeaveMulticast(
150     scoped_ptr<XWalkExtensionFunctionInfo> info) {
151 }
152
153 void UDPSocketObject::OnSendString(
154     scoped_ptr<XWalkExtensionFunctionInfo> info) {
155   if (!socket_ || has_write_pending_)
156     return;
157
158   scoped_ptr<SendDOMString::Params>
159       params(SendDOMString::Params::Create(*info->arguments()));
160   if (!params) {
161     LOG(WARNING) << "Malformed parameters passed to " << info->name();
162     return;
163   }
164
165   if (params->data.size() > kBufferSize) {
166     LOG(WARNING) << "Write data bigger than the write buffer.";
167     return;
168   }
169
170   write_buffer_size_ = params->data.size();
171   memcpy(write_buffer_->data(), params->data.data(), write_buffer_size_);
172
173   if (!params->remote_address || !*params->remote_port) {
174     OnSend(net::OK);
175     return;
176   }
177
178   net::HostResolver::RequestInfo request_info(net::HostPortPair(
179       *params->remote_address, *params->remote_port));
180
181   int ret = single_resolver_->Resolve(
182       request_info,
183       net::DEFAULT_PRIORITY,
184       &addresses_,
185       base::Bind(&UDPSocketObject::OnSend,
186                  base::Unretained(this)),
187       net::BoundNetLog());
188
189   if (ret != net::ERR_IO_PENDING)
190     OnSend(ret);
191   else
192     has_write_pending_ = true;
193 }
194
195 void UDPSocketObject::OnRead(int status) {
196   // No data means the other side has
197   // disconnected the socket.
198   if (status == 0) {
199     setReadyState(READY_STATE_CLOSED);
200     DispatchEvent("close");
201     return;
202   }
203
204   scoped_ptr<base::Value> data(base::BinaryValue::CreateWithCopiedBuffer(
205       static_cast<char*>(read_buffer_->data()), status));
206
207   UDPMessageEvent event;
208   event.data = std::string(read_buffer_->data(), status);
209   event.remote_port = from_.port();
210   event.remote_address = from_.ToStringWithoutPort();
211
212   scoped_ptr<base::ListValue> eventData(new base::ListValue);
213   eventData->Append(event.ToValue().release());
214
215   if (!is_suspended_)
216     DispatchEvent("message", eventData.Pass());
217
218   DoRead();
219 }
220
221 void UDPSocketObject::OnWrite(int status) {
222   has_write_pending_ = false;
223   DispatchEvent("drain");
224 }
225
226 void UDPSocketObject::OnConnectionOpen(int status) {
227   if (status != net::OK) {
228     setReadyState(READY_STATE_CLOSED);
229     DispatchEvent("error");
230     return;
231   }
232
233   setReadyState(READY_STATE_OPEN);
234   DispatchEvent("open");
235 }
236
237 void UDPSocketObject::OnSend(int status) {
238   if (status != net::OK || addresses_.empty()) {
239     setReadyState(READY_STATE_CLOSED);
240     DispatchEvent("error");
241     return;
242   }
243
244   if (!socket_->is_connected()) {
245     // If we are waiting for reads and the socket is not connect,
246     // it means the connection was closed.
247     if (is_reading_ || socket_->Connect(addresses_[0]) != net::OK) {
248       setReadyState(READY_STATE_CLOSED);
249       DispatchEvent("error");
250       return;
251     }
252   }
253
254   int ret = socket_->SendTo(
255       write_buffer_.get(),
256       write_buffer_size_,
257       addresses_[0],
258       base::Bind(&UDPSocketObject::OnWrite, base::Unretained(this)));
259
260   if (ret == net::ERR_IO_PENDING) {
261     has_write_pending_ = true;
262   } else if (ret == write_buffer_size_) {
263     has_write_pending_ = false;
264   } else {
265     socket_->Close();
266     setReadyState(READY_STATE_CLOSED);
267     DispatchEvent("close");
268     return;
269   }
270
271   if (!is_reading_ && socket_->is_connected())
272     DoRead();
273 }
274
275 }  // namespace sysapps
276 }  // namespace xwalk