View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2024 Christian Kohlschütter
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.newsclub.net.unix;
19  
20  import java.io.File;
21  import java.io.FileNotFoundException;
22  import java.io.IOException;
23  import java.net.InetAddress;
24  import java.net.SocketAddress;
25  import java.net.SocketException;
26  import java.net.URI;
27  import java.nio.ByteBuffer;
28  import java.util.Arrays;
29  import java.util.Collections;
30  import java.util.Objects;
31  import java.util.Set;
32  
33  /**
34   * An {@link AFSocketAddress} for unknown socket types.
35   *
36   * @author Christian Kohlschütter
37   */
38  public final class AFGenericSocketAddress extends AFSocketAddress {
39    private static final long serialVersionUID = 1L; // do not change!
40  
41    private static AFAddressFamily<AFGenericSocketAddress> family;
42    private static final String SELECTOR_PROVIDER_CLASS =
43        "org.newsclub.net.unix.generic.AFGenericSelectorProvider";
44  
45    private AFGenericSocketAddress(int port, final byte[] socketAddress, ByteBuffer nativeAddress)
46        throws SocketException {
47      super(port, socketAddress, nativeAddress, addressFamily());
48    }
49  
50    private static AFGenericSocketAddress newAFSocketAddress(int port, final byte[] socketAddress,
51        ByteBuffer nativeAddress) throws SocketException {
52      return newDeserializedAFSocketAddress(port, socketAddress, nativeAddress, addressFamily(),
53          AFGenericSocketAddress::new);
54    }
55  
56    /**
57     * Returns an {@link AFGenericSocketAddress} given a special {@link InetAddress} that encodes the
58     * byte sequence of an unknown-type socket address, like those returned by {@link #wrapAddress()}.
59     *
60     * @param address The "special" {@link InetAddress}.
61     * @param port The port (use 0 for "none").
62     * @return The {@link AFGenericSocketAddress} instance.
63     * @throws SocketException if the operation fails, for example when an unsupported address is
64     *           specified.
65     */
66    public static AFGenericSocketAddress unwrap(InetAddress address, int port)
67        throws SocketException {
68      return AFSocketAddress.unwrap(address, port, addressFamily());
69    }
70  
71    /**
72     * Returns an {@link AFGenericSocketAddress} given a special {@link InetAddress} hostname that
73     * encodes the byte sequence of an unknown-type socket address, like those returned by
74     * {@link #wrapAddress()}.
75     *
76     * @param hostname The "special" hostname, as provided by {@link InetAddress#getHostName()}.
77     * @param port The port (use 0 for "none").
78     * @return The {@link AFGenericSocketAddress} instance.
79     * @throws SocketException if the operation fails, for example when an unsupported address is
80     *           specified.
81     */
82    public static AFGenericSocketAddress unwrap(String hostname, int port) throws SocketException {
83      return AFSocketAddress.unwrap(hostname, port, addressFamily());
84    }
85  
86    /**
87     * Returns an {@link AFGenericSocketAddress} given a generic {@link SocketAddress}.
88     *
89     * @param address The address to unwrap.
90     * @return The {@link AFGenericSocketAddress} instance.
91     * @throws SocketException if the operation fails, for example when an unsupported address is
92     *           specified.
93     */
94    public static AFGenericSocketAddress unwrap(SocketAddress address) throws SocketException {
95      Objects.requireNonNull(address);
96      if (!isSupportedAddress(address)) {
97        throw new SocketException("Unsupported address");
98      }
99      return (AFGenericSocketAddress) address;
100   }
101 
102   @Override
103   public String toString() {
104     int port = getPort();
105 
106     return getClass().getName() + "[" + (port == 0 ? "" : "port=" + port + ";") + "bytes=" + Arrays
107         .toString(getBytes()) + "]";
108   }
109 
110   /**
111    * Returns the native representation of this generic address, which is most likely not portable.
112    * <p>
113    * The address contains the sa_family identifier as the first byte, and, on some platforms only,
114    * the address length, as the second byte.
115    *
116    * @return A new byte array containing the system-specific representation of that address.
117    */
118   public byte[] toBytes() {
119     byte[] bytes = getBytes();
120     return Arrays.copyOf(bytes, bytes.length);
121   }
122 
123   @Override
124   public boolean hasFilename() {
125     return false;
126   }
127 
128   @Override
129   public File getFile() throws FileNotFoundException {
130     throw new FileNotFoundException("no file");
131   }
132 
133   /**
134    * Checks if an {@link InetAddress} can be unwrapped to an {@link AFGenericSocketAddress}.
135    *
136    * @param addr The instance to check.
137    * @return {@code true} if so.
138    * @see #wrapAddress()
139    * @see #unwrap(InetAddress, int)
140    */
141   public static boolean isSupportedAddress(InetAddress addr) {
142     return AFSocketAddress.isSupportedAddress(addr, addressFamily());
143   }
144 
145   /**
146    * Checks if a {@link SocketAddress} can be unwrapped to an {@link AFGenericSocketAddress}.
147    *
148    * @param addr The instance to check.
149    * @return {@code true} if so.
150    * @see #unwrap(InetAddress, int)
151    */
152   public static boolean isSupportedAddress(SocketAddress addr) {
153     return (addr instanceof AFGenericSocketAddress);
154   }
155 
156   /**
157    * Returns the corresponding {@link AFAddressFamily}.
158    *
159    * @return The address family instance.
160    */
161   @SuppressWarnings("null")
162   public static synchronized AFAddressFamily<AFGenericSocketAddress> addressFamily() {
163     if (family == null) {
164       family = AFAddressFamily.registerAddressFamily("generic", //
165           AFGenericSocketAddress.class, new AFSocketAddressConfig<AFGenericSocketAddress>() {
166 
167             private final AFSocketAddressConstructor<AFGenericSocketAddress> addrConstr =
168                 isUseDeserializationForInit() ? AFGenericSocketAddress::newAFSocketAddress
169                     : AFGenericSocketAddress::new;
170 
171             @Override
172             protected AFGenericSocketAddress parseURI(URI u, int port) throws SocketException {
173               return AFGenericSocketAddress.of(u, port);
174             }
175 
176             @Override
177             protected AFSocketAddressConstructor<AFGenericSocketAddress> addressConstructor() {
178               return addrConstr;
179             }
180 
181             @Override
182             protected String selectorProviderClassname() {
183               return SELECTOR_PROVIDER_CLASS;
184             }
185 
186             @Override
187             protected Set<String> uriSchemes() {
188               return Collections.emptySet();
189             }
190           });
191       try {
192         Class.forName(SELECTOR_PROVIDER_CLASS);
193       } catch (ClassNotFoundException e) {
194         // ignore
195       }
196     }
197     return family;
198   }
199 
200   /**
201    * Returns an {@link AFGenericSocketAddress} for the given URI, if possible.
202    *
203    * @param uri The URI.
204    * @return The address.
205    * @throws SocketException if the operation fails.
206    */
207   @SuppressWarnings("PMD.ShortMethodName")
208   public static AFGenericSocketAddress of(URI uri) throws SocketException {
209     return of(uri, -1);
210   }
211 
212   /**
213    * Returns an {@link AFGenericSocketAddress} for the given URI, if possible.
214    *
215    * @param uri The URI.
216    * @param overridePort The port to forcibly use, or {@code -1} for "don't override".
217    * @return The address.
218    * @throws SocketException if the operation fails.
219    */
220   @SuppressWarnings({
221       "PMD.CognitiveComplexity", "PMD.CyclomaticComplexity", "PMD.ExcessiveMethodLength",
222       "PMD.NcssCount", "PMD.NPathComplexity", "PMD.ShortMethodName"})
223   public static AFGenericSocketAddress of(URI uri, int overridePort) throws SocketException {
224     throw new SocketException("Unsupported");
225   }
226 
227   @Override
228   @SuppressWarnings({"PMD.CognitiveComplexity", "PMD.CompareObjectsWithEquals"})
229   public URI toURI(String scheme, URI template) throws IOException {
230     return super.toURI(scheme, template);
231   }
232 }