1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.nio.ByteBuffer; 31 import java.nio.channels.AsynchronousCloseException; 32 import java.nio.channels.ByteChannel; 33 import java.nio.channels.ClosedChannelException; 34 import java.nio.channels.NotYetConnectedException; 35 import java.nio.channels.spi.AbstractInterruptibleChannel; 36 import java.util.Objects; 37 import java.util.concurrent.locks.ReentrantLock; 38 39 import static java.util.concurrent.TimeUnit.NANOSECONDS; 40 41 class UnixDomainSocketChannelImpl 42 extends AbstractInterruptibleChannel 43 implements ByteChannel 44 { 45 // Used to make native read and write calls 46 private static final NativeDispatcher nd = new SocketDispatcher(); 47 48 // Our file descriptor object 49 private final FileDescriptor fd; 50 // Lock held by current reading or connecting thread 51 private final ReentrantLock readLock = new ReentrantLock(); 52 53 // Lock held by current writing or connecting thread 54 private final ReentrantLock writeLock = new ReentrantLock(); 55 56 // Lock for managing close state 57 private final Object stateLock = new Object(); 58 59 // Channel state 60 private static final int ST_INUSE = 0; 61 private static final int ST_CLOSING = 1; 62 private static final int ST_CLOSED = 2; 63 private int state; 64 65 // IDs of native threads doing reads and writes, for signalling 66 private long readerThread; 67 private long writerThread; 68 69 UnixDomainSocketChannelImpl(FileDescriptor fd) 70 throws IOException 71 { 72 this.fd = fd; 73 } 74 75 /** 76 * Checks that the channel is open. 77 * 78 * @throws ClosedChannelException if channel is closed (or closing) 79 */ 80 private void ensureOpen() throws ClosedChannelException { 81 if (!isOpen()) 82 throw new ClosedChannelException(); 83 } 84 85 /** 86 * Closes the socket if there are no I/O operations in progress 87 */ 88 private boolean tryClose() throws IOException { 89 assert Thread.holdsLock(stateLock) && state == ST_CLOSING; 90 if (readerThread == 0 && writerThread == 0) { 91 state = ST_CLOSED; 92 nd.close(fd); 93 return true; 94 } else { 95 return false; 96 } 97 } 98 99 /** 100 * Complete closure of pre-closed socket (release the file descriptor) 101 */ 102 private void tryFinishClose() { 103 try { 104 tryClose(); 105 } catch (IOException ignore) { } 106 } 107 108 /** 109 * Marks the beginning of a read operation 110 * 111 * @throws ClosedChannelException if the channel is closed 112 * @throws NotYetConnectedException if the channel is not yet connected 113 */ 114 private void beginRead() throws ClosedChannelException { 115 // set hook for Thread.interrupt 116 begin(); 117 synchronized (stateLock) { 118 ensureOpen(); 119 readerThread = NativeThread.current(); 120 } 121 } 122 123 /** 124 * Marks the end of a read operation that may have blocked. 125 * 126 * @throws AsynchronousCloseException if the channel was closed due to this 127 * thread being interrupted on a blocking read operation. 128 */ 129 private void endRead(boolean completed) 130 throws AsynchronousCloseException 131 { 132 synchronized (stateLock) { 133 readerThread = 0; 134 if (state == ST_CLOSING) { 135 tryFinishClose(); 136 } 137 } 138 end(completed); 139 } 140 141 @Override 142 public int read(ByteBuffer buf) throws IOException { 143 Objects.requireNonNull(buf); 144 145 readLock.lock(); 146 try { 147 int n = 0; 148 try { 149 beginRead(); 150 n = IOUtil.read(fd, buf, -1, nd); 151 while (IOStatus.okayToRetry(n) && isOpen()) { 152 park(Net.POLLIN, 0L); 153 n = IOUtil.read(fd, buf, -1, nd); 154 } 155 } finally { 156 endRead(n > 0); 157 } 158 return n; 159 } finally { 160 readLock.unlock(); 161 } 162 } 163 164 /** 165 * Marks the beginning of a write operation that might block. 166 * 167 * @throws ClosedChannelException if the channel is closed 168 * @throws NotYetConnectedException if the channel is not yet connected 169 */ 170 private void beginWrite() throws ClosedChannelException { 171 begin(); 172 synchronized (stateLock) { 173 // set hook for Thread.interrupt 174 ensureOpen(); 175 writerThread = NativeThread.current(); 176 } 177 } 178 179 /** 180 * Marks the end of a write operation that may have blocked. 181 * 182 * @throws AsynchronousCloseException if the channel was closed due to this 183 * thread being interrupted on a blocking write operation. 184 */ 185 private void endWrite(boolean completed) 186 throws AsynchronousCloseException 187 { 188 synchronized (stateLock) { 189 writerThread = 0; 190 if (state == ST_CLOSING) { 191 tryFinishClose(); 192 } 193 } 194 end(completed); 195 } 196 197 void park(int event, long nanos) throws IOException { 198 long millis; 199 if (nanos <= 0) { 200 millis = -1; 201 } else { 202 millis = NANOSECONDS.toMillis(nanos); 203 } 204 Net.poll(fd, event, millis); 205 } 206 207 @Override 208 public int write(ByteBuffer buf) throws IOException { 209 Objects.requireNonNull(buf); 210 211 writeLock.lock(); 212 try { 213 int n = 0; 214 try { 215 beginWrite(); 216 n = IOUtil.write(fd, buf, -1, nd); 217 while (IOStatus.okayToRetry(n) && isOpen()) { 218 park(Net.POLLOUT, 0L); 219 n = IOUtil.write(fd, buf, -1, nd); 220 } 221 } finally { 222 endWrite(n > 0); 223 } 224 return n; 225 } finally { 226 writeLock.unlock(); 227 } 228 } 229 230 /** 231 * Closes this channel 232 * 233 * If there is an I/O operation in progress then the socket is pre-closed 234 * and the I/O threads signalled, in which case the final close is deferred 235 * until all I/O operations complete. 236 */ 237 @Override 238 protected void implCloseChannel() throws IOException { 239 synchronized (stateLock) { 240 assert state == ST_INUSE; 241 state = ST_CLOSING; 242 if (!tryClose()) { 243 long reader = readerThread; 244 long writer = writerThread; 245 if (reader != 0 || writer != 0) { 246 nd.preClose(fd); 247 if (reader != 0) 248 NativeThread.signal(reader); 249 if (writer != 0) 250 NativeThread.signal(writer); 251 } 252 } 253 } 254 } 255 256 @Override 257 public String toString() { 258 StringBuilder sb = new StringBuilder(); 259 sb.append(this.getClass().getSuperclass().getName()); 260 sb.append('['); 261 if (!isOpen()) 262 sb.append("closed"); 263 sb.append(']'); 264 return sb.toString(); 265 } 266 } | 1 /* 2 * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.nio.ch; 27 28 import java.io.FileDescriptor; 29 import java.io.IOException; 30 import java.io.UncheckedIOException; 31 import java.net.NetPermission; 32 import java.net.ProtocolFamily; 33 import java.net.Socket; 34 import java.net.SocketAddress; 35 import java.net.SocketException; 36 import java.net.SocketOption; 37 import java.net.SocketTimeoutException; 38 import java.net.StandardProtocolFamily; 39 import java.net.StandardSocketOptions; 40 import java.net.UnixDomainSocketAddress; 41 import java.nio.ByteBuffer; 42 import java.nio.channels.AlreadyBoundException; 43 import java.nio.channels.AlreadyConnectedException; 44 import java.nio.channels.AsynchronousCloseException; 45 import java.nio.channels.ClosedChannelException; 46 import java.nio.channels.ConnectionPendingException; 47 import java.nio.channels.IllegalBlockingModeException; 48 import java.nio.channels.NoConnectionPendingException; 49 import java.nio.channels.NotYetConnectedException; 50 import java.nio.channels.SelectionKey; 51 import java.nio.channels.SocketChannel; 52 import java.nio.channels.spi.SelectorProvider; 53 import java.nio.file.InvalidPathException; 54 import java.nio.file.Path; 55 import java.security.AccessController; 56 import java.security.PrivilegedAction; 57 import java.util.Collections; 58 import java.util.HashSet; 59 import java.util.Objects; 60 import java.util.Set; 61 import java.util.concurrent.locks.ReentrantLock; 62 63 import sun.net.ConnectionResetException; 64 import sun.net.NetHooks; 65 import sun.net.ext.ExtendedSocketOptions; 66 import sun.net.util.SocketExceptions; 67 68 /** 69 * An implementation of SocketChannels 70 */ 71 72 public class UnixDomainSocketChannelImpl extends SocketChannelImpl 73 { 74 UnixDomainSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) 75 throws IOException 76 { 77 super(sp, fd, bound); 78 } 79 80 // Constructor for sockets obtained from server sockets 81 // 82 UnixDomainSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, SocketAddress isa) 83 throws IOException 84 { 85 super(sp, fd, isa); 86 } 87 88 @Override 89 SocketAddress implLocalAddress(FileDescriptor fd) throws IOException { 90 return UnixDomainNet.localAddress(fd); 91 } 92 93 @Override 94 SocketAddress getRevealedLocalAddress(SocketAddress address) { 95 UnixDomainSocketAddress uaddr = (UnixDomainSocketAddress)address; 96 return UnixDomainNet.getRevealedLocalAddress(uaddr); 97 } 98 99 @SuppressWarnings("unchecked") 100 @Override 101 <T> T implGetOption(SocketOption<T> name) throws IOException { 102 return (T) Net.getSocketOption(getFD(), name); 103 } 104 105 @Override 106 <T> void implSetOption(SocketOption<T> name, T value) throws IOException { 107 Net.setSocketOption(getFD(), name, value); 108 } 109 110 private static class DefaultOptionsHolder { 111 static final Set<SocketOption<?>> defaultOptions = defaultOptions(); 112 113 private static Set<SocketOption<?>> defaultOptions() { 114 HashSet<SocketOption<?>> set = new HashSet<>(); 115 set.add(StandardSocketOptions.SO_SNDBUF); 116 set.add(StandardSocketOptions.SO_RCVBUF); 117 set.add(StandardSocketOptions.SO_LINGER); 118 set.addAll(ExtendedSocketOptions.unixSocketOptions()); 119 return Collections.unmodifiableSet(set); 120 } 121 } 122 123 @Override 124 public final Set<SocketOption<?>> supportedOptions() { 125 return DefaultOptionsHolder.defaultOptions; 126 } 127 128 @Override 129 SocketAddress implBind(SocketAddress local) throws IOException { 130 UnixDomainNet.checkCapability(); 131 UnixDomainSocketAddress usa = UnixDomainNet.checkAddress(local); 132 Path path = usa == null ? null : usa.getPath(); 133 UnixDomainNet.bind(getFD(), path); 134 if (usa == null || path.toString().equals("")) { 135 return UnixDomainNet.UNNAMED; 136 } else { 137 return UnixDomainNet.localAddress(getFD()); 138 } 139 } 140 141 @Override 142 public Socket socket() { 143 throw new UnsupportedOperationException("socket not supported"); 144 } 145 146 /** 147 * Checks the permissions required for connect 148 */ 149 @Override 150 SocketAddress checkRemote(SocketAddress sa) throws IOException { 151 Objects.requireNonNull(sa); 152 UnixDomainNet.checkCapability(); 153 UnixDomainSocketAddress usa = UnixDomainNet.checkAddress(sa); 154 return usa; 155 } 156 157 @Override 158 int implConnect(FileDescriptor fd, SocketAddress sa) throws IOException { 159 UnixDomainSocketAddress usa = (UnixDomainSocketAddress)sa; 160 return UnixDomainNet.connect(fd, usa.getPath()); 161 } 162 163 String getRevealedLocalAddressAsString(SocketAddress sa) { 164 UnixDomainSocketAddress usa = (UnixDomainSocketAddress)sa; 165 return UnixDomainNet.getRevealedLocalAddressAsString(usa); 166 } 167 168 /** 169 * Read/write need to be overridden for JFR 170 */ 171 @Override 172 public int read(ByteBuffer buf) throws IOException { 173 return super.read(buf); 174 } 175 176 @Override 177 public int write(ByteBuffer buf) throws IOException { 178 return super.write(buf); 179 } 180 181 @Override 182 public long write(ByteBuffer[] srcs, int offset, int length) 183 throws IOException 184 { 185 return super.write(srcs, offset, length); 186 } 187 188 @Override 189 public long read(ByteBuffer[] dsts, int offset, int length) 190 throws IOException 191 { 192 return super.read(dsts, offset, length); 193 } 194 } |