1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import dalvik.system.CloseGuard; 21import java.io.FileDescriptor; 22import java.io.IOException; 23import java.io.InputStream; 24import java.io.OutputStream; 25import java.net.ConnectException; 26import java.net.InetAddress; 27import java.net.InetSocketAddress; 28import java.net.Proxy; 29import java.net.SocketAddress; 30import java.net.SocketException; 31import java.net.SocketImpl; 32import java.net.SocketTimeoutException; 33import java.net.UnknownHostException; 34import java.nio.ByteOrder; 35import java.util.Arrays; 36import libcore.io.ErrnoException; 37import libcore.io.IoBridge; 38import libcore.io.Libcore; 39import libcore.io.Memory; 40import libcore.io.Streams; 41import static libcore.io.OsConstants.*; 42 43/** 44 * @hide used in java.nio. 45 */ 46public class PlainSocketImpl extends SocketImpl { 47 48 // For SOCKS support. A SOCKS bind() uses the last 49 // host connected to in its request. 50 private static InetAddress lastConnectedAddress; 51 52 private static int lastConnectedPort; 53 54 private boolean streaming = true; 55 56 private boolean shutdownInput; 57 58 private Proxy proxy; 59 60 private final CloseGuard guard = CloseGuard.get(); 61 62 public PlainSocketImpl(FileDescriptor fd) { 63 this.fd = fd; 64 if (fd.valid()) { 65 guard.open("close"); 66 } 67 } 68 69 public PlainSocketImpl(Proxy proxy) { 70 this(new FileDescriptor()); 71 this.proxy = proxy; 72 } 73 74 public PlainSocketImpl() { 75 this(new FileDescriptor()); 76 } 77 78 public PlainSocketImpl(FileDescriptor fd, int localport, InetAddress addr, int port) { 79 this.fd = fd; 80 this.localport = localport; 81 this.address = addr; 82 this.port = port; 83 if (fd.valid()) { 84 guard.open("close"); 85 } 86 } 87 88 @Override 89 protected void accept(SocketImpl newImpl) throws IOException { 90 if (usingSocks()) { 91 ((PlainSocketImpl) newImpl).socksBind(); 92 ((PlainSocketImpl) newImpl).socksAccept(); 93 return; 94 } 95 96 try { 97 InetSocketAddress peerAddress = new InetSocketAddress(); 98 FileDescriptor clientFd = Libcore.os.accept(fd, peerAddress); 99 100 // TODO: we can't just set newImpl.fd to clientFd because a nio SocketChannel may 101 // be sharing the FileDescriptor. http://b//4452981. 102 newImpl.fd.setInt$(clientFd.getInt$()); 103 104 newImpl.address = peerAddress.getAddress(); 105 newImpl.port = peerAddress.getPort(); 106 } catch (ErrnoException errnoException) { 107 if (errnoException.errno == EAGAIN) { 108 throw new SocketTimeoutException(errnoException); 109 } 110 throw errnoException.rethrowAsSocketException(); 111 } 112 113 // Reset the client's inherited read timeout to the Java-specified default of 0. 114 newImpl.setOption(SocketOptions.SO_TIMEOUT, Integer.valueOf(0)); 115 116 newImpl.localport = IoBridge.getSocketLocalPort(newImpl.fd); 117 } 118 119 private boolean usingSocks() { 120 return proxy != null && proxy.type() == Proxy.Type.SOCKS; 121 } 122 123 public void initLocalPort(int localPort) { 124 this.localport = localPort; 125 } 126 127 public void initRemoteAddressAndPort(InetAddress remoteAddress, int remotePort) { 128 this.address = remoteAddress; 129 this.port = remotePort; 130 } 131 132 private void checkNotClosed() throws IOException { 133 if (!fd.valid()) { 134 throw new SocketException("Socket is closed"); 135 } 136 } 137 138 @Override 139 protected synchronized int available() throws IOException { 140 checkNotClosed(); 141 // we need to check if the input has been shutdown. If so 142 // we should return that there is no data to be read 143 if (shutdownInput) { 144 return 0; 145 } 146 return IoBridge.available(fd); 147 } 148 149 @Override protected void bind(InetAddress address, int port) throws IOException { 150 IoBridge.bind(fd, address, port); 151 this.address = address; 152 if (port != 0) { 153 this.localport = port; 154 } else { 155 this.localport = IoBridge.getSocketLocalPort(fd); 156 } 157 } 158 159 @Override 160 protected synchronized void close() throws IOException { 161 guard.close(); 162 IoBridge.closeSocket(fd); 163 } 164 165 @Override 166 protected void connect(String aHost, int aPort) throws IOException { 167 connect(InetAddress.getByName(aHost), aPort); 168 } 169 170 @Override 171 protected void connect(InetAddress anAddr, int aPort) throws IOException { 172 connect(anAddr, aPort, 0); 173 } 174 175 /** 176 * Connects this socket to the specified remote host address/port. 177 * 178 * @param anAddr 179 * the remote host address to connect to 180 * @param aPort 181 * the remote port to connect to 182 * @param timeout 183 * a timeout where supported. 0 means no timeout 184 * @throws IOException 185 * if an error occurs while connecting 186 */ 187 private void connect(InetAddress anAddr, int aPort, int timeout) throws IOException { 188 InetAddress normalAddr = anAddr.isAnyLocalAddress() ? InetAddress.getLocalHost() : anAddr; 189 if (streaming && usingSocks()) { 190 socksConnect(anAddr, aPort, 0); 191 } else { 192 IoBridge.connect(fd, normalAddr, aPort, timeout); 193 } 194 super.address = normalAddr; 195 super.port = aPort; 196 } 197 198 @Override 199 protected void create(boolean streaming) throws IOException { 200 this.streaming = streaming; 201 this.fd = IoBridge.socket(streaming); 202 } 203 204 @Override protected void finalize() throws Throwable { 205 try { 206 if (guard != null) { 207 guard.warnIfOpen(); 208 } 209 close(); 210 } finally { 211 super.finalize(); 212 } 213 } 214 215 @Override protected synchronized InputStream getInputStream() throws IOException { 216 checkNotClosed(); 217 return new PlainSocketInputStream(this); 218 } 219 220 private static class PlainSocketInputStream extends InputStream { 221 private final PlainSocketImpl socketImpl; 222 223 public PlainSocketInputStream(PlainSocketImpl socketImpl) { 224 this.socketImpl = socketImpl; 225 } 226 227 @Override public int available() throws IOException { 228 return socketImpl.available(); 229 } 230 231 @Override public void close() throws IOException { 232 socketImpl.close(); 233 } 234 235 @Override public int read() throws IOException { 236 return Streams.readSingleByte(this); 237 } 238 239 @Override public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException { 240 return socketImpl.read(buffer, byteOffset, byteCount); 241 } 242 } 243 244 @Override public Object getOption(int option) throws SocketException { 245 return IoBridge.getSocketOption(fd, option); 246 } 247 248 @Override protected synchronized OutputStream getOutputStream() throws IOException { 249 checkNotClosed(); 250 return new PlainSocketOutputStream(this); 251 } 252 253 private static class PlainSocketOutputStream extends OutputStream { 254 private final PlainSocketImpl socketImpl; 255 256 public PlainSocketOutputStream(PlainSocketImpl socketImpl) { 257 this.socketImpl = socketImpl; 258 } 259 260 @Override public void close() throws IOException { 261 socketImpl.close(); 262 } 263 264 @Override public void write(int oneByte) throws IOException { 265 Streams.writeSingleByte(this, oneByte); 266 } 267 268 @Override public void write(byte[] buffer, int offset, int byteCount) throws IOException { 269 socketImpl.write(buffer, offset, byteCount); 270 } 271 } 272 273 @Override 274 protected void listen(int backlog) throws IOException { 275 if (usingSocks()) { 276 // Do nothing for a SOCKS connection. The listen occurs on the 277 // server during the bind. 278 return; 279 } 280 try { 281 Libcore.os.listen(fd, backlog); 282 } catch (ErrnoException errnoException) { 283 throw errnoException.rethrowAsSocketException(); 284 } 285 } 286 287 @Override 288 public void setOption(int option, Object value) throws SocketException { 289 IoBridge.setSocketOption(fd, option, value); 290 } 291 292 /** 293 * Gets the SOCKS proxy server port. 294 */ 295 private int socksGetServerPort() { 296 // get socks server port from proxy. It is unnecessary to check 297 // "socksProxyPort" property, since proxy setting should only be 298 // determined by ProxySelector. 299 InetSocketAddress addr = (InetSocketAddress) proxy.address(); 300 return addr.getPort(); 301 } 302 303 /** 304 * Gets the InetAddress of the SOCKS proxy server. 305 */ 306 private InetAddress socksGetServerAddress() throws UnknownHostException { 307 String proxyName; 308 // get socks server address from proxy. It is unnecessary to check 309 // "socksProxyHost" property, since all proxy setting should be 310 // determined by ProxySelector. 311 InetSocketAddress addr = (InetSocketAddress) proxy.address(); 312 proxyName = addr.getHostName(); 313 if (proxyName == null) { 314 proxyName = addr.getAddress().getHostAddress(); 315 } 316 return InetAddress.getByName(proxyName); 317 } 318 319 /** 320 * Connect using a SOCKS server. 321 */ 322 private void socksConnect(InetAddress applicationServerAddress, int applicationServerPort, int timeout) throws IOException { 323 try { 324 IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort(), timeout); 325 } catch (Exception e) { 326 throw new SocketException("SOCKS connection failed", e); 327 } 328 329 socksRequestConnection(applicationServerAddress, applicationServerPort); 330 331 lastConnectedAddress = applicationServerAddress; 332 lastConnectedPort = applicationServerPort; 333 } 334 335 /** 336 * Request a SOCKS connection to the application server given. If the 337 * request fails to complete successfully, an exception is thrown. 338 */ 339 private void socksRequestConnection(InetAddress applicationServerAddress, 340 int applicationServerPort) throws IOException { 341 socksSendRequest(Socks4Message.COMMAND_CONNECT, 342 applicationServerAddress, applicationServerPort); 343 Socks4Message reply = socksReadReply(); 344 if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { 345 throw new IOException(reply.getErrorString(reply.getCommandOrResult())); 346 } 347 } 348 349 /** 350 * Perform an accept for a SOCKS bind. 351 */ 352 public void socksAccept() throws IOException { 353 Socks4Message reply = socksReadReply(); 354 if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { 355 throw new IOException(reply.getErrorString(reply.getCommandOrResult())); 356 } 357 } 358 359 /** 360 * Shutdown the input portion of the socket. 361 */ 362 @Override 363 protected void shutdownInput() throws IOException { 364 shutdownInput = true; 365 try { 366 Libcore.os.shutdown(fd, SHUT_RD); 367 } catch (ErrnoException errnoException) { 368 throw errnoException.rethrowAsSocketException(); 369 } 370 } 371 372 /** 373 * Shutdown the output portion of the socket. 374 */ 375 @Override 376 protected void shutdownOutput() throws IOException { 377 try { 378 Libcore.os.shutdown(fd, SHUT_WR); 379 } catch (ErrnoException errnoException) { 380 throw errnoException.rethrowAsSocketException(); 381 } 382 } 383 384 /** 385 * Bind using a SOCKS server. 386 */ 387 private void socksBind() throws IOException { 388 try { 389 IoBridge.connect(fd, socksGetServerAddress(), socksGetServerPort()); 390 } catch (Exception e) { 391 throw new IOException("Unable to connect to SOCKS server", e); 392 } 393 394 // There must be a connection to an application host for the bind to work. 395 if (lastConnectedAddress == null) { 396 throw new SocketException("Invalid SOCKS client"); 397 } 398 399 // Use the last connected address and port in the bind request. 400 socksSendRequest(Socks4Message.COMMAND_BIND, lastConnectedAddress, 401 lastConnectedPort); 402 Socks4Message reply = socksReadReply(); 403 404 if (reply.getCommandOrResult() != Socks4Message.RETURN_SUCCESS) { 405 throw new IOException(reply.getErrorString(reply.getCommandOrResult())); 406 } 407 408 // A peculiarity of socks 4 - if the address returned is 0, use the 409 // original socks server address. 410 if (reply.getIP() == 0) { 411 address = socksGetServerAddress(); 412 } else { 413 // IPv6 support not yet required as 414 // currently the Socks4Message.getIP() only returns int, 415 // so only works with IPv4 4byte addresses 416 byte[] replyBytes = new byte[4]; 417 Memory.pokeInt(replyBytes, 0, reply.getIP(), ByteOrder.BIG_ENDIAN); 418 address = InetAddress.getByAddress(replyBytes); 419 } 420 localport = reply.getPort(); 421 } 422 423 /** 424 * Send a SOCKS V4 request. 425 */ 426 private void socksSendRequest(int command, InetAddress address, int port) throws IOException { 427 Socks4Message request = new Socks4Message(); 428 request.setCommandOrResult(command); 429 request.setPort(port); 430 request.setIP(address.getAddress()); 431 request.setUserId("default"); 432 433 getOutputStream().write(request.getBytes(), 0, request.getLength()); 434 } 435 436 /** 437 * Read a SOCKS V4 reply. 438 */ 439 private Socks4Message socksReadReply() throws IOException { 440 Socks4Message reply = new Socks4Message(); 441 int bytesRead = 0; 442 while (bytesRead < Socks4Message.REPLY_LENGTH) { 443 int count = getInputStream().read(reply.getBytes(), bytesRead, 444 Socks4Message.REPLY_LENGTH - bytesRead); 445 if (count == -1) { 446 break; 447 } 448 bytesRead += count; 449 } 450 if (Socks4Message.REPLY_LENGTH != bytesRead) { 451 throw new SocketException("Malformed reply from SOCKS server"); 452 } 453 return reply; 454 } 455 456 @Override 457 protected void connect(SocketAddress remoteAddr, int timeout) throws IOException { 458 InetSocketAddress inetAddr = (InetSocketAddress) remoteAddr; 459 connect(inetAddr.getAddress(), inetAddr.getPort(), timeout); 460 } 461 462 @Override 463 protected boolean supportsUrgentData() { 464 return true; 465 } 466 467 @Override 468 protected void sendUrgentData(int value) throws IOException { 469 try { 470 byte[] buffer = new byte[] { (byte) value }; 471 Libcore.os.sendto(fd, buffer, 0, 1, MSG_OOB, null, 0); 472 } catch (ErrnoException errnoException) { 473 throw errnoException.rethrowAsSocketException(); 474 } 475 } 476 477 /** 478 * For PlainSocketInputStream. 479 */ 480 private int read(byte[] buffer, int offset, int byteCount) throws IOException { 481 if (byteCount == 0) { 482 return 0; 483 } 484 Arrays.checkOffsetAndCount(buffer.length, offset, byteCount); 485 if (shutdownInput) { 486 return -1; 487 } 488 int readCount = IoBridge.recvfrom(true, fd, buffer, offset, byteCount, 0, null, false); 489 // Return of zero bytes for a blocking socket means a timeout occurred 490 if (readCount == 0) { 491 throw new SocketTimeoutException(); 492 } 493 // Return of -1 indicates the peer was closed 494 if (readCount == -1) { 495 shutdownInput = true; 496 } 497 return readCount; 498 } 499 500 /** 501 * For PlainSocketOutputStream. 502 */ 503 private void write(byte[] buffer, int offset, int byteCount) throws IOException { 504 Arrays.checkOffsetAndCount(buffer.length, offset, byteCount); 505 if (streaming) { 506 while (byteCount > 0) { 507 int bytesWritten = IoBridge.sendto(fd, buffer, offset, byteCount, 0, null, 0); 508 byteCount -= bytesWritten; 509 offset += bytesWritten; 510 } 511 } else { 512 // Unlike writes to a streaming socket, writes to a datagram 513 // socket are all-or-nothing, so we don't need a loop here. 514 // http://code.google.com/p/android/issues/detail?id=15304 515 IoBridge.sendto(fd, buffer, offset, byteCount, 0, address, port); 516 } 517 } 518} 519