OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 The Chromium OS 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 <string.h> |
| 6 #ifdef __GLIBC__ |
| 7 #include <arpa/inet.h> |
| 8 #include <netinet/in.h> |
| 9 #include <sys/types.h> |
| 10 #include <sys/socket.h> |
| 11 #else |
| 12 #include <nacl-mounts/net/newlib_compat.h> |
| 13 #endif |
| 14 #include <irt.h> |
| 15 #include <nacl-mounts/net/SocketSubSystem.h> |
| 16 #include <nacl-mounts/net/TcpServerSocket.h> |
| 17 #include <nacl-mounts/net/TcpSocket.h> |
| 18 #include <nacl-mounts/ppapi/cpp/private/net_address_private.h> |
| 19 #include <nacl-mounts/util/DebugPrint.h> |
| 20 #include <nacl-mounts/util/PthreadHelpers.h> |
| 21 #include "ppapi/cpp/file_ref.h" |
| 22 #include <signal.h> |
| 23 |
| 24 SocketSubSystem::SocketSubSystem(pp::Instance* instance) |
| 25 : pp_instance_(instance) |
| 26 , factory_(this) |
| 27 , host_resolver_(NULL) { |
| 28 AddHostAddress("localhost", 0x7F000001); |
| 29 } |
| 30 |
| 31 uint32_t SocketSubSystem::AddHostAddress(const char* name, uint32_t addr) { |
| 32 return addr; |
| 33 } |
| 34 |
| 35 addrinfo* SocketSubSystem::CreateAddrInfo(const PP_NetAddress_Private& netaddr, |
| 36 const addrinfo* hints, |
| 37 const char* name) { |
| 38 addrinfo* ai = new addrinfo(); |
| 39 sockaddr_in6* addr = new sockaddr_in6(); |
| 40 |
| 41 ai->ai_addr = reinterpret_cast<sockaddr*>(addr); |
| 42 ai->ai_addrlen = sizeof(*addr); |
| 43 |
| 44 PP_NetAddressFamily_Private family = |
| 45 pp::NetAddressPrivate::GetFamily(netaddr); |
| 46 if (family == PP_NETADDRESSFAMILY_IPV4) |
| 47 ai->ai_addr->sa_family = ai->ai_family = AF_INET; |
| 48 else if (family == PP_NETADDRESSFAMILY_IPV6) |
| 49 ai->ai_addr->sa_family = ai->ai_family = AF_INET6; |
| 50 |
| 51 ai->ai_canonname = strdup(name); |
| 52 addr->sin6_port = pp::NetAddressPrivate::GetPort(netaddr); |
| 53 if (family == PP_NETADDRESSFAMILY_IPV6) { |
| 54 pp::NetAddressPrivate::GetAddress( |
| 55 netaddr, &addr->sin6_addr, sizeof(in6_addr)); |
| 56 } else { |
| 57 pp::NetAddressPrivate::GetAddress( |
| 58 netaddr, &(reinterpret_cast<sockaddr_in*>(addr))->sin_addr, |
| 59 sizeof(in_addr)); |
| 60 } |
| 61 |
| 62 if (hints && hints->ai_socktype) |
| 63 ai->ai_socktype = hints->ai_socktype; |
| 64 else |
| 65 ai->ai_socktype = SOCK_STREAM; |
| 66 |
| 67 if (hints && hints->ai_protocol) |
| 68 ai->ai_protocol = hints->ai_protocol; |
| 69 |
| 70 return ai; |
| 71 } |
| 72 |
| 73 int SocketSubSystem::getaddrinfo(const char* hostname, const char* servname, |
| 74 const addrinfo* hints, addrinfo** res) { |
| 75 SimpleAutoLock lock(mutex()); |
| 76 GetAddrInfoParams params; |
| 77 params.hostname = hostname; |
| 78 params.servname = servname; |
| 79 params.hints = hints; |
| 80 params.res = res; |
| 81 int32_t result = PP_OK_COMPLETIONPENDING; |
| 82 pp::Module::Get()->core()->CallOnMainThread(0, factory_.NewCallback( |
| 83 &SocketSubSystem::Resolve, ¶ms, &result)); |
| 84 while (result == PP_OK_COMPLETIONPENDING) |
| 85 cond().wait(mutex()); |
| 86 return result == PP_OK ? 0 : EAI_FAIL; |
| 87 } |
| 88 |
| 89 void SocketSubSystem::Resolve(int32_t result, GetAddrInfoParams* params, |
| 90 int32_t* pres) { |
| 91 SimpleAutoLock lock(mutex()); |
| 92 const char* hostname = params->hostname; |
| 93 const char* servname = params->servname; |
| 94 const addrinfo* hints = params->hints; |
| 95 addrinfo** res = params->res; |
| 96 |
| 97 if (hints && hints->ai_family != AF_UNSPEC && |
| 98 hints->ai_family != AF_INET && |
| 99 hints->ai_family != AF_INET6) { |
| 100 *pres = PP_ERROR_FAILED; |
| 101 cond().broadcast(); |
| 102 dbgprintf("SSS::Resolve failed: incorrect ai_family\n"); |
| 103 return; |
| 104 } |
| 105 |
| 106 uint32_t port = 0; |
| 107 if (servname != NULL) { |
| 108 char* cp; |
| 109 port = strtol(servname, &cp, 10); |
| 110 if (port > 0 && port <= 65535 && *cp == '\0') { |
| 111 port = htons(port); |
| 112 } else { |
| 113 dbgprintf("Bad port number %s\n", servname); |
| 114 port = 0; |
| 115 } |
| 116 } |
| 117 |
| 118 bool is_ipv6 = hints ? hints->ai_family == AF_INET6 : false; |
| 119 in6_addr in = {}; |
| 120 bool is_numeric = hostname && |
| 121 inet_pton(is_ipv6 ? AF_INET6 : AF_INET, hostname, &in); |
| 122 |
| 123 if (is_numeric) { |
| 124 PP_NetAddress_Private addr = {}; |
| 125 if (is_ipv6) { |
| 126 // TODO(dpolukhin): handle scope_id |
| 127 if (!pp::NetAddressPrivate::CreateFromIPv6Address( |
| 128 in.s6_addr, 0, port, &addr)) { |
| 129 dbgprintf("NetAddressPrivate::CreateFromIPv6Address failed!\n"); |
| 130 *pres = PP_ERROR_FAILED; |
| 131 cond().broadcast(); |
| 132 return; |
| 133 } |
| 134 } else { |
| 135 if (!pp::NetAddressPrivate::CreateFromIPv4Address( |
| 136 in.s6_addr, port, &addr)) { |
| 137 dbgprintf("NetAddressPrivate::CreateFromIPv4Address failed!\n"); |
| 138 *pres = PP_ERROR_FAILED; |
| 139 cond().broadcast(); |
| 140 return; |
| 141 } |
| 142 } |
| 143 *res = CreateAddrInfo(addr, hints, ""); |
| 144 *pres = PP_OK; |
| 145 cond().broadcast(); |
| 146 return; |
| 147 } |
| 148 |
| 149 if (hints && hints->ai_flags & AI_PASSIVE) { |
| 150 // Numeric case we considered above so the only remaining case is any. |
| 151 PP_NetAddress_Private addr = {}; |
| 152 if (!pp::NetAddressPrivate::GetAnyAddress(is_ipv6, &addr)) { |
| 153 dbgprintf("NetAddressPrivate::GetAnyAddress failed!\n"); |
| 154 *pres = PP_ERROR_FAILED; |
| 155 cond().broadcast(); |
| 156 return; |
| 157 } |
| 158 *res = CreateAddrInfo(addr, hints, ""); |
| 159 *pres = PP_OK; |
| 160 cond().broadcast(); |
| 161 return; |
| 162 } |
| 163 |
| 164 if (!hostname) { |
| 165 PP_NetAddress_Private localhost = {}; |
| 166 if (is_ipv6) { |
| 167 uint8_t localhost_ip[16] = {}; |
| 168 localhost_ip[15] = 1; |
| 169 // TODO(dpolukhin): handle scope_id |
| 170 if (!pp::NetAddressPrivate::CreateFromIPv6Address( |
| 171 localhost_ip, 0, port, &localhost)) { |
| 172 dbgprintf("NetAddressPrivate::CreateFromIPv6Address failed!\n"); |
| 173 *pres = PP_ERROR_FAILED; |
| 174 cond().broadcast(); |
| 175 return; |
| 176 } |
| 177 } else { |
| 178 uint8_t localhost_ip[4] = { 127, 0, 0, 1 }; |
| 179 if (!pp::NetAddressPrivate::CreateFromIPv4Address( |
| 180 localhost_ip, port, &localhost)) { |
| 181 dbgprintf("NetAddressPrivate::CreateFromIPv4Address failed!\n"); |
| 182 *pres = PP_ERROR_FAILED; |
| 183 cond().broadcast(); |
| 184 return; |
| 185 } |
| 186 } |
| 187 *res = CreateAddrInfo(localhost, hints, ""); |
| 188 *pres = PP_OK; |
| 189 cond().broadcast(); |
| 190 return; |
| 191 } |
| 192 |
| 193 if (hints && hints->ai_flags & AI_NUMERICHOST) { |
| 194 dbgprintf("SSS::Resolve failed (AI_NUMERICHOST)\n"); |
| 195 *pres = PP_ERROR_FAILED; |
| 196 cond().broadcast(); |
| 197 return; |
| 198 } |
| 199 |
| 200 // In case of JS socket don't use local host resolver. |
| 201 if (pp::HostResolverPrivate::IsAvailable()) { |
| 202 PP_HostResolver_Private_Hint hint = { PP_NETADDRESSFAMILY_UNSPECIFIED, 0 }; |
| 203 if (hints) { |
| 204 if (hints->ai_family == AF_INET) |
| 205 hint.family = PP_NETADDRESSFAMILY_IPV4; |
| 206 else if (hints->ai_family == AF_INET6) |
| 207 hint.family = PP_NETADDRESSFAMILY_IPV6; |
| 208 if (hints->ai_flags & AI_CANONNAME) |
| 209 hint.flags = PP_HOST_RESOLVER_FLAGS_CANONNAME; |
| 210 } |
| 211 |
| 212 assert(host_resolver_ == NULL); |
| 213 host_resolver_ = new pp::HostResolverPrivate(instance()); |
| 214 *pres = host_resolver_->Resolve(hostname, port, hint, |
| 215 factory_.NewCallback(&SocketSubSystem::OnResolve, params, pres)); |
| 216 if (*pres != PP_OK_COMPLETIONPENDING) { |
| 217 delete host_resolver_; |
| 218 host_resolver_ = NULL; |
| 219 cond().broadcast(); |
| 220 } |
| 221 } else { |
| 222 dbgprintf("NetAddress resolver not available\n"); |
| 223 *res = NULL; |
| 224 *pres = PP_ERROR_FAILED; |
| 225 cond().broadcast(); |
| 226 return; |
| 227 } |
| 228 } |
| 229 |
| 230 void SocketSubSystem::OnResolve(int32_t result, GetAddrInfoParams* params, |
| 231 int32_t* pres) { |
| 232 SimpleAutoLock lock(mutex()); |
| 233 assert(host_resolver_); |
| 234 const addrinfo* hints = params->hints; |
| 235 addrinfo** res = params->res; |
| 236 std::string host_name = host_resolver_->GetCanonicalName().AsString(); |
| 237 if (result == PP_OK) { |
| 238 size_t size = host_resolver_->GetSize(); |
| 239 for (size_t i = 0; i < size; i++) { |
| 240 PP_NetAddress_Private address = {}; |
| 241 if (host_resolver_->GetNetAddress(i, &address)) { |
| 242 *res = CreateAddrInfo(address, hints, host_name.c_str()); |
| 243 res = &(*res)->ai_next; |
| 244 } |
| 245 } |
| 246 } else { |
| 247 result = PP_ERROR_FAILED; |
| 248 } |
| 249 delete host_resolver_; |
| 250 host_resolver_ = NULL; |
| 251 *pres = result; |
| 252 cond().broadcast(); |
| 253 } |
| 254 |
| 255 void SocketSubSystem::freeaddrinfo(addrinfo* ai) { |
| 256 while (ai != NULL) { |
| 257 addrinfo* next = ai->ai_next; |
| 258 free(ai->ai_canonname); |
| 259 delete ai->ai_addr; |
| 260 delete ai; |
| 261 ai = next; |
| 262 } |
| 263 } |
| 264 |
| 265 int SocketSubSystem::getnameinfo(const sockaddr *sa, socklen_t salen, |
| 266 char* host, size_t hostlen, |
| 267 char* serv, size_t servlen, int flags) { |
| 268 if (sa->sa_family != AF_INET && sa->sa_family != AF_INET6) |
| 269 return EAI_FAMILY; |
| 270 |
| 271 if (serv) { |
| 272 snprintf(serv, servlen, "%d", |
| 273 ntohs((reinterpret_cast<const sockaddr_in*>(sa))->sin_port)); |
| 274 } |
| 275 if (host) { |
| 276 if (sa->sa_family == AF_INET6) { |
| 277 inet_ntop(AF_INET6, |
| 278 &(reinterpret_cast<const sockaddr_in6*>(sa))->sin6_addr, |
| 279 host, hostlen); |
| 280 } |
| 281 } else { |
| 282 inet_ntop(AF_INET, &(reinterpret_cast<sockaddr_in*>(sa))->sin_addr, |
| 283 host, hostlen); |
| 284 } |
| 285 |
| 286 return 0; |
| 287 } |
| 288 |
| 289 bool SocketSubSystem::GetHostPort(const sockaddr* serv_addr, socklen_t addrlen, |
| 290 std::string* hostname, uint16_t* port) { |
| 291 if (serv_addr->sa_family == AF_INET) { |
| 292 const sockaddr_in* sin4 = reinterpret_cast<const sockaddr_in*>(serv_addr); |
| 293 *port = ntohs(sin4->sin_port); |
| 294 char buf[NI_MAXHOST]; |
| 295 inet_ntop(AF_INET, &sin4->sin_addr, buf, sizeof(buf)); |
| 296 *hostname = buf; |
| 297 } else { |
| 298 const sockaddr_in6* sin6 = reinterpret_cast<const sockaddr_in6*>(serv_addr); |
| 299 *port = ntohs(sin6->sin6_port); |
| 300 char buf[NI_MAXHOST]; |
| 301 inet_ntop(AF_INET6, &sin6->sin6_addr, buf, sizeof(buf)); |
| 302 *hostname = buf; |
| 303 } |
| 304 return true; |
| 305 } |
| 306 |
| 307 int SocketSubSystem::connect(Socket** stream, const sockaddr* serv_addr, |
| 308 socklen_t addrlen) { |
| 309 uint16_t port; |
| 310 std::string hostname; |
| 311 if (!GetHostPort(serv_addr, addrlen, &hostname, &port)) { |
| 312 errno = EAFNOSUPPORT; |
| 313 return -1; |
| 314 } |
| 315 |
| 316 TCPSocket* socket = new TCPSocket(this, O_RDWR); |
| 317 if (!socket->connect(hostname.c_str(), port)) { |
| 318 errno = ECONNREFUSED; |
| 319 socket->release(); |
| 320 return -1; |
| 321 } |
| 322 *stream = socket; |
| 323 |
| 324 return 0; |
| 325 } |
| 326 |
| 327 int SocketSubSystem::bind(Socket** stream, const sockaddr* addr, |
| 328 socklen_t addrlen) { |
| 329 *stream = (new TCPServerSocket(this, 0, addr, addrlen)); |
| 330 return 0; |
| 331 } |
| 332 |
| 333 uint32_t SocketSubSystem::gethostbyname(const char* name) { |
| 334 addrinfo* ai; |
| 335 addrinfo hints; |
| 336 hints.ai_family = AF_INET; |
| 337 hints.ai_flags = 0; |
| 338 if (!getaddrinfo(name, "80", &hints, &ai)) { |
| 339 uint32_t ip = ((struct sockaddr_in*)ai->ai_addr)->sin_addr.s_addr; |
| 340 return ip; |
| 341 } else { |
| 342 dbgprintf("getaddrinfo returned AI_FAIL\n"); |
| 343 return NULL; |
| 344 } |
| 345 } |
| 346 |
| 347 SocketSubSystem::~SocketSubSystem() { |
| 348 } |
| 349 |
| 350 int SocketSubSystem::shutdown(Socket* stream, int how) { |
| 351 if (stream) { |
| 352 // Actually shutdown should be something more complicated by for now |
| 353 // it works. Method close can be called multiple time. |
| 354 stream->close(); |
| 355 return 0; |
| 356 } else { |
| 357 errno = EBADF; |
| 358 return -1; |
| 359 } |
| 360 } |
| 361 |
| 362 int SocketSubSystem::close(Socket* stream) { |
| 363 if (stream) { |
| 364 stream->close(); |
| 365 stream->release(); |
| 366 } |
| 367 return 0; |
| 368 } |
| 369 |
| 370 int SocketSubSystem::read(Socket* stream, char* buf, size_t count, |
| 371 size_t* nread) { |
| 372 if (stream) |
| 373 return stream->read(buf, count, nread); |
| 374 else |
| 375 return EBADF; |
| 376 } |
| 377 |
| 378 int SocketSubSystem::write(Socket* stream, const char* buf, size_t count, |
| 379 size_t* nwrote) { |
| 380 if (stream) |
| 381 return stream->write(buf, count, nwrote); |
| 382 else |
| 383 return EBADF; |
| 384 } |
| 385 |
| 386 int SocketSubSystem::seek(Socket* stream, nacl_abi_off_t offset, int whence, |
| 387 nacl_abi_off_t* new_offset) { |
| 388 if (stream) |
| 389 return stream->seek(offset, whence, new_offset); |
| 390 else |
| 391 return EBADF; |
| 392 } |
| 393 |
| 394 int SocketSubSystem::fstat(Socket* stream, nacl_abi_stat* out) { |
| 395 if (stream) |
| 396 return stream->fstat(out); |
| 397 else |
| 398 return EBADF; |
| 399 } |
| 400 |
| 401 int SocketSubSystem::fcntl(Socket* stream, int cmd, va_list ap) { |
| 402 if (stream) { |
| 403 return stream->fcntl(cmd, ap); |
| 404 } else { |
| 405 errno = EBADF; |
| 406 return -1; |
| 407 } |
| 408 } |
| 409 |
| 410 int SocketSubSystem::ioctl(Socket* stream, int request, va_list ap) { |
| 411 if (stream) { |
| 412 return stream->ioctl(request, ap); |
| 413 } else { |
| 414 errno = EBADF; |
| 415 return -1; |
| 416 } |
| 417 } |
| 418 |
| 419 int SocketSubSystem::listen(Socket* stream, int backlog) { |
| 420 if (stream) { |
| 421 if (static_cast<TCPServerSocket*>(stream)->listen(backlog)) { |
| 422 return 0; |
| 423 } else { |
| 424 errno = EACCES; |
| 425 return -1; |
| 426 } |
| 427 } else { |
| 428 errno = EBADF; |
| 429 return -1; |
| 430 } |
| 431 } |
| 432 |
| 433 Socket* SocketSubSystem::accept(Socket* stream, struct sockaddr *addr, |
| 434 socklen_t* addrlen) { |
| 435 if (stream) { |
| 436 PP_Resource resource = static_cast<TCPServerSocket*>(stream)->accept(); |
| 437 if (resource) { |
| 438 TCPSocket* socket = new TCPSocket(this, O_RDWR); |
| 439 if (socket->acceptFrom(resource)) { |
| 440 return socket; |
| 441 } else { |
| 442 socket->release(); |
| 443 } |
| 444 } |
| 445 errno = EINVAL; |
| 446 return 0; |
| 447 } else { |
| 448 errno = EBADF; |
| 449 return 0; |
| 450 } |
| 451 } |
| 452 |
OLD | NEW |