1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.system;
18 
19 import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
20 
21 import android.annotation.SystemApi;
22 
23 import java.net.SocketAddress;
24 import java.nio.charset.StandardCharsets;
25 import java.util.Arrays;
26 
27 /**
28  * A UNIX-domain (AF_UNIX / AF_LOCAL) socket address.
29  *
30  * See <a href="https://man7.org/linux/man-pages/man7/unix.7.html">unix(7)</a>.
31  *
32  * @see OsConstants#AF_UNIX
33  *
34  * @hide
35  */
36 @SystemApi(client = MODULE_LIBRARIES)
37 public final class UnixSocketAddress extends SocketAddress {
38 
39     private static final int NAMED_PATH_LENGTH = OsConstants.UNIX_PATH_MAX;
40     private static final byte[] UNNAMED_PATH = new byte[0];
41 
42     // See unix(7): Three types of UnixSocketAddress:
43     // 1) pathname: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] != 0.
44     // 2) unnamed: sun_path = [].
45     // 3) abstract: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] == 0.
46     // Note that the array referenced by this field can be modified from JNI (libcore_io_Linux.cpp).
47     private final byte[] sun_path;
48 
49     /** This constructor is also used from JNI. */
UnixSocketAddress(byte[] sun_path)50     private UnixSocketAddress(byte[] sun_path) {
51         if (sun_path == null) {
52             throw new IllegalArgumentException("sun_path must not be null");
53         }
54         if (sun_path.length > NAMED_PATH_LENGTH) {
55             throw new IllegalArgumentException("sun_path exceeds the maximum length");
56         }
57 
58         if (sun_path.length == 0) {
59             this.sun_path = UNNAMED_PATH;
60         } else {
61             this.sun_path = new byte[sun_path.length];
62             System.arraycopy(sun_path, 0, this.sun_path, 0, sun_path.length);
63         }
64     }
65 
66     /**
67      * Creates a named, abstract AF_UNIX socket address.
68      *
69      * @throws NullPointerException if {@code name} is null
70      * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
71      *
72      * @hide
73      */
createAbstract(String name)74     public static UnixSocketAddress createAbstract(String name) {
75         byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
76         // Abstract sockets have a path that starts with (byte) 0.
77         byte[] path = new byte[nameBytes.length + 1];
78         System.arraycopy(nameBytes, 0, path, 1, nameBytes.length);
79         return new UnixSocketAddress(path);
80     }
81 
82     /**
83      * Creates a named, filesystem {@link OsConstants#AF_UNIX} socket address.
84      *
85      * See <a href="https://man7.org/linux/man-pages/man7/unix.7.html">unix(7)</a>.
86      *
87      * @param pathname filename for named unix socket
88      * @throws NullPointerException if {@code name} is {@code null}
89      * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
90      *
91      * @hide
92      */
93     @SystemApi(client = MODULE_LIBRARIES)
createFileSystem(String pathName)94     public static UnixSocketAddress createFileSystem(String pathName) {
95         byte[] pathNameBytes = pathName.getBytes(StandardCharsets.UTF_8);
96         // File system sockets have a path that ends with (byte) 0.
97         byte[] path = new byte[pathNameBytes.length + 1];
98         System.arraycopy(pathNameBytes, 0, path, 0, pathNameBytes.length);
99         return new UnixSocketAddress(path);
100     }
101 
102     /**
103      * Creates an unnamed, filesystem AF_UNIX socket address.
104      *
105      * @hide
106      */
createUnnamed()107     public static UnixSocketAddress createUnnamed() {
108         return new UnixSocketAddress(UNNAMED_PATH);
109     }
110 
111     /**
112      * Used for testing.
113      *
114      * @hide
115      */
getSunPath()116     public byte[] getSunPath() {
117         if (sun_path.length == 0) {
118             return sun_path;
119         }
120         byte[] sunPathCopy = new byte[sun_path.length];
121         System.arraycopy(sun_path, 0, sunPathCopy, 0, sun_path.length);
122         return sunPathCopy;
123     }
124 
125     /**
126      * @hide
127      */
128     @Override
equals(Object o)129     public boolean equals(Object o) {
130         if (this == o) {
131             return true;
132         }
133         if (o == null || getClass() != o.getClass()) {
134             return false;
135         }
136 
137         UnixSocketAddress that = (UnixSocketAddress) o;
138         return Arrays.equals(sun_path, that.sun_path);
139     }
140 
141     /**
142      * @hide
143      */
144     @Override
hashCode()145     public int hashCode() {
146         return Arrays.hashCode(sun_path);
147     }
148 
149     /**
150      * @hide
151      */
152     @Override
toString()153     public String toString() {
154         return "UnixSocketAddress[" +
155                 "sun_path=" + Arrays.toString(sun_path) +
156                 ']';
157     }
158 }
159