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 java.net;
  27 
  28 import java.io.ObjectStreamException;
  29 import java.io.Serializable;
  30 import java.net.SocketAddress;
  31 import java.nio.file.FileSystem;
  32 import java.nio.file.FileSystems;
  33 import java.nio.file.InvalidPathException;
  34 import java.nio.file.Path;
  35 
  36 /**
  37  * A <a href="package-summary.html#unixdomain">Unix domain</a> socket address.
  38  * A Unix domain socket address encapsulates a file-system path that Unix domain sockets
  39  * bind or connect to.
  40  *
  41  * <p> An <a id="unnamed"></a><i>unnamed</i> {@code UnixDomainSocketAddress} has
  42  * an empty path. The local address of a Unix domain socket that is automatically
  43  * bound will be unnamed.
  44  *
  45  * <p> {@link Path} objects used to create instances of this class must be obtained
  46  * from the {@linkplain FileSystems#getDefault system-default} file system.
  47  *
  48  * @see java.nio.channels.SocketChannel
  49  * @see java.nio.channels.ServerSocketChannel
  50  * @since 16
  51  */
  52 public final class UnixDomainSocketAddress extends SocketAddress {
  53     @java.io.Serial
  54     static final long serialVersionUID = 92902496589351288L;
  55 
  56     private final transient Path path;
  57 
  58     /**
  59      * A serial proxy for all {@link UnixDomainSocketAddress} instances.
  60      * It captures the file path name and reconstructs using the public static
  61      * {@link #of(String) factory}.
  62      *
  63      * @serial include
  64      */
  65     private static final class Ser implements Serializable {
  66         @java.io.Serial
  67         static final long serialVersionUID = -7955684448513979814L;
  68 
  69         /**
  70          * The path name.
  71          * @serial
  72          */
  73         private final String pathname;
  74 
  75         Ser(String pathname) {
  76             this.pathname = pathname;
  77         }
  78 
  79         /**
  80          * Creates a {@link UnixDomainSocketAddress} instance, by an invocation
  81          * of the {@link #of(String) factory} method passing the path name.
  82          * @return a UnixDomainSocketAddress
  83          */
  84         @java.io.Serial
  85         private Object readResolve() {
  86             return UnixDomainSocketAddress.of(pathname);
  87         }
  88     }
  89 
  90     /**
  91      * Returns a
  92      * <a href="{@docRoot}/serialized-form.html#java.net.UnixDomainSocketAddress.Ser">
  93      * Ser</a> containing the path name of this instance.
  94      *
  95      * @return a {@link Ser}
  96      * representing the path name of this instance
  97      */
  98     @java.io.Serial
  99     private Object writeReplace() throws ObjectStreamException {
 100         return new Ser(path.toString());
 101     }
 102 
 103     /**
 104      * Throws InvalidObjectException, always.
 105      * @param s the stream
 106      * @throws java.io.InvalidObjectException always
 107      */
 108     @java.io.Serial
 109     private void readObject(java.io.ObjectInputStream s)
 110         throws java.io.InvalidObjectException
 111     {
 112         throw new java.io.InvalidObjectException("Proxy required");
 113     }
 114 
 115     /**
 116      * Throws InvalidObjectException, always.
 117      * @throws java.io.InvalidObjectException always
 118      */
 119     @java.io.Serial
 120     private void readObjectNoData()
 121         throws java.io.InvalidObjectException
 122     {
 123         throw new java.io.InvalidObjectException("Proxy required");
 124     }
 125 
 126     private UnixDomainSocketAddress(Path path) {
 127         FileSystem fs = path.getFileSystem();
 128         if (fs != FileSystems.getDefault()) {
 129             throw new IllegalArgumentException(); // fix message
 130         }
 131         if (fs.getClass().getModule() != Object.class.getModule()) {
 132             throw new IllegalArgumentException();  // fix message
 133         }
 134         this.path = path;
 135     }
 136 
 137     /**
 138      * Create a UnixDomainSocketAddress from the given path string.
 139      *
 140      * @param  pathname
 141      *         The path string, which can be empty
 142      *
 143      * @return A UnixDomainSocketAddress
 144      *
 145      * @throws InvalidPathException
 146      *         If the path cannot be converted to a Path
 147      */
 148     public static UnixDomainSocketAddress of(String pathname) {
 149         return of(Path.of(pathname));
 150     }
 151 
 152     /**
 153      * Create a UnixDomainSocketAddress for the given path.
 154      *
 155      * @param  path
 156      *         The path to the socket, which can be empty
 157      *
 158      * @return A UnixDomainSocketAddress
 159      *
 160      * @throws IllegalArgumentException
 161      *         If the path is not associated with the default file system
 162      */
 163     public static UnixDomainSocketAddress of(Path path) {
 164         return new UnixDomainSocketAddress(path);
 165     }
 166 
 167     /**
 168      * Return this address's path.
 169      *
 170      * @return this address's path
 171      */
 172     public Path getPath() {
 173         return path;
 174     }
 175 
 176     /**
 177      * Returns the hash code of this {@code UnixDomainSocketAddress}
 178      */
 179     @Override
 180     public int hashCode() {
 181         return path.hashCode();
 182     }
 183 
 184     /**
 185      * Compares this address with another object.
 186      *
 187      * @return true if the path fields are equal
 188      */
 189     @Override
 190     public boolean equals(Object o) {
 191         if (! (o instanceof UnixDomainSocketAddress))
 192             return false;
 193         UnixDomainSocketAddress that = (UnixDomainSocketAddress)o;
 194         return this.path.equals(that.path);
 195     }
 196 
 197     /**
 198      * Returns a string representation of this {@code UnixDomainSocketAddress}.
 199      *
 200      * @return this address's path which may be empty for an unnamed address
 201      */
 202     @Override
 203     public String toString() {
 204         return path.toString();
 205     }
 206 }