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