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