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.
5 #include "xwalk/sysapps/raw_socket/udp_socket_object.h"
9 #include "base/logging.h"
10 #include "net/base/net_errors.h"
11 #include "xwalk/sysapps/raw_socket/udp_socket.h"
13 using namespace xwalk::jsapi::udp_socket; // NOLINT
14 using namespace xwalk::jsapi::raw_socket; // NOLINT
18 const unsigned kBufferSize = 4096;
25 UDPSocketObject::UDPSocketObject()
26 : has_write_pending_(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)));
49 UDPSocketObject::~UDPSocketObject() {}
51 void UDPSocketObject::DoRead() {
52 if (!socket_->is_connected())
57 int ret = socket_->RecvFrom(read_buffer_.get(),
60 base::Bind(&UDPSocketObject::OnRead,
61 base::Unretained(this)));
67 void UDPSocketObject::OnInit(scoped_ptr<XWalkExtensionFunctionInfo> info) {
68 scoped_ptr<Init::Params> params(Init::Params::Create(*info->arguments()));
70 LOG(WARNING) << "Malformed parameters passed to " << info->name();
71 setReadyState(READY_STATE_CLOSED);
72 DispatchEvent("error");
76 socket_.reset(new net::UDPSocket(net::DatagramSocket::DEFAULT_BIND,
77 net::RandIntCallback(),
79 net::NetLog::Source()));
81 if (!params->options) {
82 OnConnectionOpen(net::OK);
86 if (!params->options->local_address.empty()) {
87 net::IPAddressNumber ip_number;
88 if (!net::ParseIPLiteralToNumber(params->options->local_address,
90 LOG(WARNING) << "Invalid IP address " << params->options->local_address;
91 setReadyState(READY_STATE_CLOSED);
92 DispatchEvent("error");
96 if (params->options->address_reuse)
97 socket_->AllowAddressReuse();
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");
108 OnConnectionOpen(net::OK);
112 if (params->options->remote_address.empty() ||
113 !params->options->remote_port) {
114 OnConnectionOpen(net::OK);
118 net::HostResolver::RequestInfo request_info(net::HostPortPair(
119 params->options->remote_address, params->options->remote_port));
121 int ret = single_resolver_->Resolve(
123 net::DEFAULT_PRIORITY,
125 base::Bind(&UDPSocketObject::OnConnectionOpen,
126 base::Unretained(this)),
129 if (ret != net::ERR_IO_PENDING)
130 OnConnectionOpen(ret);
133 void UDPSocketObject::OnClose(scoped_ptr<XWalkExtensionFunctionInfo> info) {
137 void UDPSocketObject::OnSuspend(scoped_ptr<XWalkExtensionFunctionInfo> info) {
138 is_suspended_ = true;
141 void UDPSocketObject::OnResume(scoped_ptr<XWalkExtensionFunctionInfo> info) {
142 is_suspended_ = false;
145 void UDPSocketObject::OnJoinMulticast(
146 scoped_ptr<XWalkExtensionFunctionInfo> info) {
149 void UDPSocketObject::OnLeaveMulticast(
150 scoped_ptr<XWalkExtensionFunctionInfo> info) {
153 void UDPSocketObject::OnSendString(
154 scoped_ptr<XWalkExtensionFunctionInfo> info) {
155 if (!socket_ || has_write_pending_)
158 scoped_ptr<SendDOMString::Params>
159 params(SendDOMString::Params::Create(*info->arguments()));
161 LOG(WARNING) << "Malformed parameters passed to " << info->name();
165 if (params->data.size() > kBufferSize) {
166 LOG(WARNING) << "Write data bigger than the write buffer.";
170 write_buffer_size_ = params->data.size();
171 memcpy(write_buffer_->data(), params->data.data(), write_buffer_size_);
173 if (!params->remote_address || !*params->remote_port) {
178 net::HostResolver::RequestInfo request_info(net::HostPortPair(
179 *params->remote_address, *params->remote_port));
181 int ret = single_resolver_->Resolve(
183 net::DEFAULT_PRIORITY,
185 base::Bind(&UDPSocketObject::OnSend,
186 base::Unretained(this)),
189 if (ret != net::ERR_IO_PENDING)
192 has_write_pending_ = true;
195 void UDPSocketObject::OnRead(int status) {
196 // No data means the other side has
197 // disconnected the socket.
199 setReadyState(READY_STATE_CLOSED);
200 DispatchEvent("close");
204 scoped_ptr<base::Value> data(base::BinaryValue::CreateWithCopiedBuffer(
205 static_cast<char*>(read_buffer_->data()), status));
207 UDPMessageEvent event;
208 event.data = std::string(read_buffer_->data(), status);
209 event.remote_port = from_.port();
210 event.remote_address = from_.ToStringWithoutPort();
212 scoped_ptr<base::ListValue> eventData(new base::ListValue);
213 eventData->Append(event.ToValue().release());
216 DispatchEvent("message", eventData.Pass());
221 void UDPSocketObject::OnWrite(int status) {
222 has_write_pending_ = false;
223 DispatchEvent("drain");
226 void UDPSocketObject::OnConnectionOpen(int status) {
227 if (status != net::OK) {
228 setReadyState(READY_STATE_CLOSED);
229 DispatchEvent("error");
233 setReadyState(READY_STATE_OPEN);
234 DispatchEvent("open");
237 void UDPSocketObject::OnSend(int status) {
238 if (status != net::OK || addresses_.empty()) {
239 setReadyState(READY_STATE_CLOSED);
240 DispatchEvent("error");
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");
254 int ret = socket_->SendTo(
258 base::Bind(&UDPSocketObject::OnWrite, base::Unretained(this)));
260 if (ret == net::ERR_IO_PENDING) {
261 has_write_pending_ = true;
262 } else if (ret == write_buffer_size_) {
263 has_write_pending_ = false;
266 setReadyState(READY_STATE_CLOSED);
267 DispatchEvent("close");
271 if (!is_reading_ && socket_->is_connected())
275 } // namespace sysapps