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 "nacl_io/socket/socket_node.h" 6 7 #include "nacl_io/ossocket.h" 8 #ifdef PROVIDES_SOCKET_API 9 10 #include <errno.h> 11 #include <string.h> 12 13 #include "nacl_io/filesystem.h" 14 #include "nacl_io/kernel_handle.h" 15 #include "nacl_io/pepper_interface.h" 16 17 #include "ppapi/c/pp_resource.h" 18 #include "ppapi/c/ppb_net_address.h" 19 20 namespace nacl_io { 21 22 SocketNode::SocketNode(Filesystem* filesystem) 23 : StreamNode(filesystem), 24 socket_resource_(0), 25 local_addr_(0), 26 remote_addr_(0), 27 socket_flags_(0), 28 last_errno_(0), 29 keep_alive_(false) { 30 memset(&linger_, 0, sizeof(linger_)); 31 SetType(S_IFSOCK); 32 } 33 34 SocketNode::SocketNode(Filesystem* filesystem, PP_Resource socket) 35 : StreamNode(filesystem), 36 socket_resource_(socket), 37 local_addr_(0), 38 remote_addr_(0), 39 socket_flags_(0), 40 last_errno_(0), 41 keep_alive_(false) { 42 memset(&linger_, 0, sizeof(linger_)); 43 SetType(S_IFSOCK); 44 filesystem_->ppapi()->AddRefResource(socket_resource_); 45 } 46 47 void SocketNode::Destroy() { 48 if (socket_resource_) 49 filesystem_->ppapi()->ReleaseResource(socket_resource_); 50 if (local_addr_) 51 filesystem_->ppapi()->ReleaseResource(local_addr_); 52 if (remote_addr_) 53 filesystem_->ppapi()->ReleaseResource(remote_addr_); 54 55 socket_resource_ = 0; 56 local_addr_ = 0; 57 remote_addr_ = 0; 58 } 59 60 // Assume that |addr| and |out_addr| are non-NULL. 61 Error SocketNode::MMap(void* addr, 62 size_t length, 63 int prot, 64 int flags, 65 size_t offset, 66 void** out_addr) { 67 return EACCES; 68 } 69 70 // Normal read/write operations on a Socket are equivalent to 71 // send/recv with a flag value of 0. 72 Error SocketNode::Read(const HandleAttr& attr, 73 void* buf, 74 size_t count, 75 int* out_bytes) { 76 return Recv(attr, buf, count, 0, out_bytes); 77 } 78 79 Error SocketNode::Write(const HandleAttr& attr, 80 const void* buf, 81 size_t count, 82 int* out_bytes) { 83 return Send(attr, buf, count, 0, out_bytes); 84 } 85 86 NetAddressInterface* SocketNode::NetInterface() { 87 if (filesystem_->ppapi() == NULL) 88 return NULL; 89 90 return filesystem_->ppapi()->GetNetAddressInterface(); 91 } 92 93 TCPSocketInterface* SocketNode::TCPInterface() { 94 if (filesystem_->ppapi() == NULL) 95 return NULL; 96 97 return filesystem_->ppapi()->GetTCPSocketInterface(); 98 } 99 100 UDPSocketInterface* SocketNode::UDPInterface() { 101 if (filesystem_->ppapi() == NULL) 102 return NULL; 103 104 return filesystem_->ppapi()->GetUDPSocketInterface(); 105 } 106 107 PP_Resource SocketNode::SockAddrToResource(const struct sockaddr* addr, 108 socklen_t len) { 109 if (NULL == addr) 110 return 0; 111 112 if (AF_INET == addr->sa_family) { 113 PP_NetAddress_IPv4 addr4; 114 const sockaddr_in* sin = reinterpret_cast<const sockaddr_in*>(addr); 115 116 if (len != sizeof(sockaddr_in)) 117 return 0; 118 119 memset(&addr4, 0, sizeof(addr4)); 120 121 addr4.port = sin->sin_port; 122 memcpy(addr4.addr, &sin->sin_addr, sizeof(addr4.addr)); 123 return filesystem_->ppapi() 124 ->GetNetAddressInterface() 125 ->CreateFromIPv4Address(filesystem_->ppapi()->GetInstance(), &addr4); 126 } 127 128 if (AF_INET6 == addr->sa_family) { 129 PP_NetAddress_IPv6 addr6; 130 const sockaddr_in6* sin = reinterpret_cast<const sockaddr_in6*>(addr); 131 132 if (len != sizeof(sockaddr_in6)) 133 return 0; 134 135 memset(&addr6, 0, sizeof(addr6)); 136 137 addr6.port = sin->sin6_port; 138 memcpy(addr6.addr, &sin->sin6_addr, sizeof(addr6.addr)); 139 return filesystem_->ppapi() 140 ->GetNetAddressInterface() 141 ->CreateFromIPv6Address(filesystem_->ppapi()->GetInstance(), &addr6); 142 } 143 return 0; 144 } 145 146 socklen_t SocketNode::ResourceToSockAddr(PP_Resource addr, 147 socklen_t len, 148 struct sockaddr* out_addr) { 149 if (0 == addr) 150 return 0; 151 152 PP_NetAddress_IPv4 ipv4; 153 PP_NetAddress_IPv6 ipv6; 154 155 if (PP_TRUE == NetInterface()->DescribeAsIPv4Address(addr, &ipv4)) { 156 sockaddr_in addr4; 157 addr4.sin_family = AF_INET; 158 addr4.sin_port = ipv4.port; 159 memcpy(&addr4.sin_addr, ipv4.addr, sizeof(ipv4.addr)); 160 memcpy(out_addr, &addr4, 161 std::min(len, static_cast<socklen_t>(sizeof(addr4)))); 162 163 // Returns required size not copied size like getpeername/getsockname. 164 return sizeof(addr4); 165 } 166 167 if (PP_TRUE == NetInterface()->DescribeAsIPv6Address(addr, &ipv6)) { 168 sockaddr_in6 addr6; 169 addr6.sin6_family = AF_INET6; 170 addr6.sin6_port = ipv6.port; 171 memcpy(&addr6.sin6_addr, ipv6.addr, sizeof(ipv6.addr)); 172 memcpy(out_addr, &addr6, 173 std::min(len, static_cast<socklen_t>(sizeof(addr6)))); 174 175 // Returns required size not copied size like getpeername/getsockname. 176 return sizeof(addr6); 177 } 178 179 return 0; 180 } 181 182 bool SocketNode::IsEquivalentAddress(PP_Resource addr1, PP_Resource addr2) { 183 if (addr1 == addr2) 184 return true; 185 186 char data1[sizeof(sockaddr_in6)]; 187 char data2[sizeof(sockaddr_in6)]; 188 189 sockaddr* saddr1 = reinterpret_cast<sockaddr*>(data1); 190 sockaddr* saddr2 = reinterpret_cast<sockaddr*>(data2); 191 192 socklen_t len1 = ResourceToSockAddr(addr1, sizeof(data1), saddr1); 193 socklen_t len2 = ResourceToSockAddr(addr2, sizeof(data2), saddr2); 194 195 if (len1 != len2) 196 return false; 197 198 return memcmp(saddr1, saddr2, len1) == 0; 199 } 200 201 Error SocketNode::Accept(const HandleAttr& attr, 202 PP_Resource* new_sock, 203 struct sockaddr* addr, 204 socklen_t* len) { 205 return ENOSYS; 206 } 207 208 Error SocketNode::Connect(const HandleAttr& attr, 209 const struct sockaddr* addr, 210 socklen_t len) { 211 if (len < 1) 212 return EINVAL; 213 214 if (NULL == addr) 215 return EFAULT; 216 217 return EOPNOTSUPP; 218 } 219 220 Error SocketNode::Listen(int backlog) { 221 return EOPNOTSUPP; 222 } 223 224 Error SocketNode::GetSockOpt(int lvl, 225 int optname, 226 void* optval, 227 socklen_t* len) { 228 if (lvl != SOL_SOCKET) 229 return ENOPROTOOPT; 230 231 AUTO_LOCK(node_lock_); 232 233 int value = 0; 234 socklen_t value_len = 0; 235 void* value_ptr = NULL; 236 237 switch (optname) { 238 case SO_REUSEADDR: 239 // SO_REUSEADDR is effectively always on since we can't 240 // disable it with PPAPI sockets. 241 value = 1; 242 value_ptr = &value; 243 value_len = sizeof(value); 244 break; 245 case SO_LINGER: 246 value_ptr = &linger_; 247 value_len = sizeof(linger_); 248 break; 249 case SO_KEEPALIVE: 250 value = keep_alive_; 251 value_ptr = &value; 252 value_len = sizeof(value); 253 break; 254 case SO_ERROR: 255 value_ptr = &last_errno_; 256 value_len = sizeof(last_errno_); 257 last_errno_ = 0; 258 break; 259 default: 260 return ENOPROTOOPT; 261 } 262 263 int copy_bytes = std::min(value_len, *len); 264 memcpy(optval, value_ptr, copy_bytes); 265 *len = value_len; 266 return 0; 267 } 268 269 Error SocketNode::SetSockOpt(int lvl, 270 int optname, 271 const void* optval, 272 socklen_t len) { 273 size_t buflen = static_cast<size_t>(len); 274 275 if (lvl != SOL_SOCKET) 276 return ENOPROTOOPT; 277 278 AUTO_LOCK(node_lock_); 279 280 switch (optname) { 281 case SO_REUSEADDR: { 282 // SO_REUSEADDR is effectivly always on since we can't 283 // disable it with PPAPI sockets. Just return success 284 // here regardless. 285 if (buflen < sizeof(int)) 286 return EINVAL; 287 return 0; 288 } 289 case SO_LINGER: { 290 // Not supported by the PPAPI interface but we preserve 291 // the settings and pretend to support it. 292 if (buflen < sizeof(struct linger)) 293 return EINVAL; 294 struct linger new_linger = *static_cast<const linger*>(optval); 295 // Don't allow setting linger to be enabled until we 296 // implement the required synchronous shutdown()/close(). 297 // TODO(sbc): remove this after http://crbug.com/312401 298 // gets fixed. 299 if (new_linger.l_onoff != 0) 300 return EINVAL; 301 linger_ = new_linger; 302 return 0; 303 } 304 case SO_KEEPALIVE: { 305 // Not supported by the PPAPI interface but we preserve 306 // the flag and pretend to support it. 307 if (buflen < sizeof(int)) 308 return EINVAL; 309 int value = *static_cast<const int*>(optval); 310 keep_alive_ = value != 0; 311 return 0; 312 } 313 } 314 315 return ENOPROTOOPT; 316 } 317 318 Error SocketNode::Bind(const struct sockaddr* addr, socklen_t len) { 319 return EINVAL; 320 } 321 322 Error SocketNode::Recv(const HandleAttr& attr, 323 void* buf, 324 size_t len, 325 int flags, 326 int* out_len) { 327 return RecvFrom(attr, buf, len, flags, NULL, 0, out_len); 328 } 329 330 Error SocketNode::RecvFrom(const HandleAttr& attr, 331 void* buf, 332 size_t len, 333 int flags, 334 struct sockaddr* src_addr, 335 socklen_t* addrlen, 336 int* out_len) { 337 PP_Resource addr = 0; 338 Error err = RecvHelper(attr, buf, len, flags, &addr, out_len); 339 if (0 == err && 0 != addr) { 340 if (src_addr) 341 *addrlen = ResourceToSockAddr(addr, *addrlen, src_addr); 342 343 filesystem_->ppapi()->ReleaseResource(addr); 344 } 345 346 return err; 347 } 348 349 Error SocketNode::RecvHelper(const HandleAttr& attr, 350 void* buf, 351 size_t len, 352 int flags, 353 PP_Resource* addr, 354 int* out_len) { 355 if (0 == socket_resource_) 356 return EBADF; 357 358 int ms = read_timeout_; 359 if ((flags & MSG_DONTWAIT) || !attr.IsBlocking()) 360 ms = 0; 361 362 // TODO(noelallen) BUG=295177 363 // For UDP we should support filtering packets when using connect 364 EventListenerLock wait(GetEventEmitter()); 365 Error err = wait.WaitOnEvent(POLLIN, ms); 366 367 // Timeout is treated as a would block for sockets. 368 if (ETIMEDOUT == err) 369 return EWOULDBLOCK; 370 371 if (err) 372 return err; 373 374 err = Recv_Locked(buf, len, addr, out_len); 375 376 // We must have read from then inputbuffer, so Q up some receive work. 377 if ((err == 0) && *out_len) 378 QueueInput(); 379 return err; 380 } 381 382 Error SocketNode::Send(const HandleAttr& attr, 383 const void* buf, 384 size_t len, 385 int flags, 386 int* out_len) { 387 return SendHelper(attr, buf, len, flags, remote_addr_, out_len); 388 } 389 390 Error SocketNode::SendTo(const HandleAttr& attr, 391 const void* buf, 392 size_t len, 393 int flags, 394 const struct sockaddr* dest_addr, 395 socklen_t addrlen, 396 int* out_len) { 397 if ((NULL == dest_addr) && (0 == remote_addr_)) 398 return EDESTADDRREQ; 399 400 PP_Resource addr = SockAddrToResource(dest_addr, addrlen); 401 if (0 == addr) 402 return EINVAL; 403 404 Error err = SendHelper(attr, buf, len, flags, addr, out_len); 405 filesystem_->ppapi()->ReleaseResource(addr); 406 return err; 407 } 408 409 Error SocketNode::SendHelper(const HandleAttr& attr, 410 const void* buf, 411 size_t len, 412 int flags, 413 PP_Resource addr, 414 int* out_len) { 415 if (0 == socket_resource_) 416 return EBADF; 417 418 if (0 == addr) 419 return ENOTCONN; 420 421 int ms = write_timeout_; 422 if ((flags & MSG_DONTWAIT) || !attr.IsBlocking()) 423 ms = 0; 424 425 EventListenerLock wait(GetEventEmitter()); 426 Error err = wait.WaitOnEvent(POLLOUT, ms); 427 428 // Timeout is treated as a would block for sockets. 429 if (ETIMEDOUT == err) 430 return EWOULDBLOCK; 431 432 if (err) 433 return err; 434 435 err = Send_Locked(buf, len, addr, out_len); 436 437 // We must have added to the output buffer, so Q up some transmit work. 438 if ((err == 0) && *out_len) 439 QueueOutput(); 440 return err; 441 } 442 443 void SocketNode::SetError_Locked(int pp_error_num) { 444 SetStreamFlags(SSF_ERROR | SSF_CLOSED); 445 ClearStreamFlags(SSF_CAN_SEND | SSF_CAN_RECV); 446 last_errno_ = PPErrorToErrno(pp_error_num); 447 } 448 449 Error SocketNode::Shutdown(int how) { 450 return EOPNOTSUPP; 451 } 452 453 Error SocketNode::GetPeerName(struct sockaddr* addr, socklen_t* len) { 454 if (NULL == addr || NULL == len) 455 return EFAULT; 456 457 AUTO_LOCK(node_lock_); 458 if (remote_addr_ != 0) { 459 *len = ResourceToSockAddr(remote_addr_, *len, addr); 460 return 0; 461 } 462 463 return ENOTCONN; 464 } 465 466 Error SocketNode::GetSockName(struct sockaddr* addr, socklen_t* len) { 467 if (NULL == addr || NULL == len) 468 return EFAULT; 469 470 AUTO_LOCK(node_lock_); 471 if (local_addr_ == 0) { 472 // getsockname succeeds even if the socket is not bound. In this case, 473 // just return address 0, port 0. 474 memset(addr, 0, *len); 475 return 0; 476 } 477 478 *len = ResourceToSockAddr(local_addr_, *len, addr); 479 return 0; 480 } 481 482 } // namespace nacl_io 483 484 #endif // PROVIDES_SOCKET_API 485