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 17package android.system; 18 19import java.net.SocketAddress; 20import java.nio.charset.StandardCharsets; 21import java.util.Arrays; 22 23/** 24 * A UNIX-domain (AF_UNIX / AF_LOCAL) socket address. 25 * 26 * @hide 27 */ 28public final class UnixSocketAddress extends SocketAddress { 29 30 private static final int NAMED_PATH_LENGTH = OsConstants.UNIX_PATH_MAX; 31 private static final byte[] UNNAMED_PATH = new byte[0]; 32 33 // See unix(7): Three types of UnixSocketAddress: 34 // 1) pathname: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] != 0. 35 // 2) unnamed: sun_path = []. 36 // 3) abstract: 0 < sun_path.length <= NAMED_PATH_LENGTH, sun_path[0] == 0. 37 private byte[] sun_path; 38 39 /** This constructor is also used from JNI. */ 40 private UnixSocketAddress(byte[] sun_path) { 41 if (sun_path == null) { 42 throw new IllegalArgumentException("sun_path must not be null"); 43 } 44 if (sun_path.length > NAMED_PATH_LENGTH) { 45 throw new IllegalArgumentException("sun_path exceeds the maximum length"); 46 } 47 48 if (sun_path.length == 0) { 49 this.sun_path = UNNAMED_PATH; 50 } else { 51 this.sun_path = new byte[sun_path.length]; 52 System.arraycopy(sun_path, 0, this.sun_path, 0, sun_path.length); 53 } 54 } 55 56 /** 57 * Creates a named, abstract AF_UNIX socket address. 58 */ 59 public static UnixSocketAddress createAbstract(String name) { 60 byte[] nameBytes = name.getBytes(StandardCharsets.UTF_8); 61 // Abstract sockets have a path that starts with (byte) 0. 62 byte[] path = new byte[nameBytes.length + 1]; 63 System.arraycopy(nameBytes, 0, path, 1, nameBytes.length); 64 return new UnixSocketAddress(path); 65 } 66 67 /** 68 * Creates a named, filesystem AF_UNIX socket address. 69 */ 70 public static UnixSocketAddress createFileSystem(String pathName) { 71 byte[] pathNameBytes = pathName.getBytes(StandardCharsets.UTF_8); 72 // File system sockets have a path that ends with (byte) 0. 73 byte[] path = new byte[pathNameBytes.length + 1]; 74 System.arraycopy(pathNameBytes, 0, path, 0, pathNameBytes.length); 75 return new UnixSocketAddress(path); 76 } 77 78 /** 79 * Creates an unnamed, filesystem AF_UNIX socket address. 80 */ 81 public static UnixSocketAddress createUnnamed() { 82 return new UnixSocketAddress(UNNAMED_PATH); 83 } 84 85 /** Used for testing. */ 86 public byte[] getSunPath() { 87 if (sun_path.length == 0) { 88 return sun_path; 89 } 90 byte[] sunPathCopy = new byte[sun_path.length]; 91 System.arraycopy(sun_path, 0, sunPathCopy, 0, sun_path.length); 92 return sunPathCopy; 93 } 94 95 @Override 96 public boolean equals(Object o) { 97 if (this == o) { 98 return true; 99 } 100 if (o == null || getClass() != o.getClass()) { 101 return false; 102 } 103 104 UnixSocketAddress that = (UnixSocketAddress) o; 105 return Arrays.equals(sun_path, that.sun_path); 106 } 107 108 @Override 109 public int hashCode() { 110 return Arrays.hashCode(sun_path); 111 } 112 113 @Override 114 public String toString() { 115 return "UnixSocketAddress[" + 116 "sun_path=" + Arrays.toString(sun_path) + 117 ']'; 118 } 119} 120