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 @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
38 public final class UnixSocketAddress extends SocketAddress {
39 
40     private static final int NAMED_PATH_LENGTH = OsConstants.UNIX_PATH_MAX;
41     private static final byte[] UNNAMED_PATH = new byte[0];
42 
43     // See unix(7): Three types of UnixSocketAddress:
44     // 1) pathname: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] != 0.
45     // 2) unnamed: sun_path = [].
46     // 3) abstract: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] == 0.
47     // Note that the array referenced by this field can be modified from JNI (libcore_io_Linux.cpp).
48     private final byte[] sun_path;
49 
50     /** This constructor is also used from JNI. */
UnixSocketAddress(byte[] sun_path)51     private UnixSocketAddress(byte[] sun_path) {
52         if (sun_path == null) {
53             throw new IllegalArgumentException("sun_path must not be null");
54         }
55         if (sun_path.length > NAMED_PATH_LENGTH) {
56             throw new IllegalArgumentException("sun_path exceeds the maximum length");
57         }
58 
59         if (sun_path.length == 0) {
60             this.sun_path = UNNAMED_PATH;
61         } else {
62             this.sun_path = new byte[sun_path.length];
63             System.arraycopy(sun_path, 0, this.sun_path, 0, sun_path.length);
64         }
65     }
66 
67     /**
68      * Creates a named, abstract AF_UNIX socket address.
69      *
70      * @throws NullPointerException if {@code name} is null
71      * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
72      *
73      * @hide
74      */
createAbstract(String name)75     public static UnixSocketAddress createAbstract(String name) {
76         byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8);
77         // Abstract sockets have a path that starts with (byte) 0.
78         byte[] path = new byte[nameBytes.length + 1];
79         System.arraycopy(nameBytes, 0, path, 1, nameBytes.length);
80         return new UnixSocketAddress(path);
81     }
82 
83     /**
84      * Creates a named, filesystem {@link OsConstants#AF_UNIX} socket address.
85      *
86      * See <a href="https://man7.org/linux/man-pages/man7/unix.7.html">unix(7)</a>.
87      *
88      * @param pathname filename for named unix socket
89      * @throws NullPointerException if {@code name} is {@code null}
90      * @throws IllegalArgumentException if {@code name} is invalid, e.g. too long
91      *
92      * @hide
93      */
94     @SystemApi(client = MODULE_LIBRARIES)
95     @libcore.api.CorePlatformApi(status = libcore.api.CorePlatformApi.Status.STABLE)
createFileSystem(String pathName)96     public static UnixSocketAddress createFileSystem(String pathName) {
97         byte[] pathNameBytes = pathName.getBytes(StandardCharsets.UTF_8);
98         // File system sockets have a path that ends with (byte) 0.
99         byte[] path = new byte[pathNameBytes.length + 1];
100         System.arraycopy(pathNameBytes, 0, path, 0, pathNameBytes.length);
101         return new UnixSocketAddress(path);
102     }
103 
104     /**
105      * Creates an unnamed, filesystem AF_UNIX socket address.
106      *
107      * @hide
108      */
createUnnamed()109     public static UnixSocketAddress createUnnamed() {
110         return new UnixSocketAddress(UNNAMED_PATH);
111     }
112 
113     /**
114      * Used for testing.
115      *
116      * @hide
117      */
getSunPath()118     public byte[] getSunPath() {
119         if (sun_path.length == 0) {
120             return sun_path;
121         }
122         byte[] sunPathCopy = new byte[sun_path.length];
123         System.arraycopy(sun_path, 0, sunPathCopy, 0, sun_path.length);
124         return sunPathCopy;
125     }
126 
127     /**
128      * @hide
129      */
130     @Override
equals(Object o)131     public boolean equals(Object o) {
132         if (this == o) {
133             return true;
134         }
135         if (o == null || getClass() != o.getClass()) {
136             return false;
137         }
138 
139         UnixSocketAddress that = (UnixSocketAddress) o;
140         return Arrays.equals(sun_path, that.sun_path);
141     }
142 
143     /**
144      * @hide
145      */
146     @Override
hashCode()147     public int hashCode() {
148         return Arrays.hashCode(sun_path);
149     }
150 
151     /**
152      * @hide
153      */
154     @Override
toString()155     public String toString() {
156         return "UnixSocketAddress[" +
157                 "sun_path=" + Arrays.toString(sun_path) +
158                 ']';
159     }
160 }
161