View Javadoc
1   /*
2    * junixsocket
3    *
4    * Copyright 2009-2026 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.darwin.system;
19  
20  import java.io.FileDescriptor;
21  import java.io.IOException;
22  import java.net.Socket;
23  import java.net.SocketException;
24  
25  import org.newsclub.net.unix.AFSYSTEMSocketAddress;
26  import org.newsclub.net.unix.AFSYSTEMSocketImplExtensions;
27  import org.newsclub.net.unix.AFSocket;
28  import org.newsclub.net.unix.AFSocketCapability;
29  import org.newsclub.net.unix.AFSocketFactory;
30  
31  import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
32  
33  /**
34   * Implementation of an {@code AF_SYSTEM} socket.
35   *
36   * @author Christian Kohlschütter
37   */
38  public final class AFSYSTEMSocket extends AFSocket<AFSYSTEMSocketAddress> implements
39      AFSYSTEMSocketExtensions {
40    private static AFSYSTEMSocketImplExtensions staticExtensions = null;
41  
42    AFSYSTEMSocket(FileDescriptor fdObj, AFSocketFactory<AFSYSTEMSocketAddress> factory)
43        throws SocketException {
44      super(new AFSYSTEMSocketImpl(fdObj), factory);
45    }
46  
47    @SuppressWarnings("unused")
48    private static synchronized AFSYSTEMSocketImplExtensions getStaticImplExtensions()
49        throws IOException {
50      if (staticExtensions == null) {
51        try (AFSYSTEMSocket socket = new AFSYSTEMSocket(null, null)) {
52          staticExtensions = (AFSYSTEMSocketImplExtensions) socket.getImplExtensions();
53        }
54      }
55      return staticExtensions;
56    }
57  
58    /**
59     * Returns <code>true</code> iff {@link AFSYSTEMSocket}s (sockets of type "AF_SYSTEM") are
60     * supported by the current Java VM and the kernel.
61     *
62     * To support {@link AFSYSTEMSocket}s, a custom JNI library must be loaded that is supplied with
63     * <em>junixsocket</em>, and the system must support AF_SYSTEM sockets.
64     *
65     * This call is equivalent to checking {@link AFSocket#isSupported()} and
66     * {@link AFSocket#supports(AFSocketCapability)} with
67     * {@link AFSocketCapability#CAPABILITY_DARWIN}.
68     *
69     * @return {@code true} iff supported.
70     */
71    @SuppressFBWarnings("HSM_HIDING_METHOD")
72    public static boolean isSupported() {
73      return AFSocket.isSupported() && AFSocket.supports(AFSocketCapability.CAPABILITY_DARWIN);
74    }
75  
76    @Override
77    protected AFSYSTEMSocketChannel newChannel() {
78      return new AFSYSTEMSocketChannel(this);
79    }
80  
81    /**
82     * Creates a new, unbound {@link AFSocket}.
83     *
84     * This "default" implementation is a bit "lenient" with respect to the specification.
85     *
86     * In particular, we ignore calls to {@link Socket#getTcpNoDelay()} and
87     * {@link Socket#setTcpNoDelay(boolean)}.
88     *
89     * @return A new, unbound socket.
90     * @throws IOException if the operation fails.
91     */
92    public static AFSYSTEMSocket newInstance() throws IOException {
93      return (AFSYSTEMSocket) AFSocket.newInstance(AFSYSTEMSocket::new, (AFSYSTEMSocketFactory) null);
94    }
95  
96    static AFSYSTEMSocket newInstance(AFSYSTEMSocketFactory factory) throws SocketException {
97      return (AFSYSTEMSocket) AFSocket.newInstance(AFSYSTEMSocket::new, factory);
98    }
99  
100   /**
101    * Creates a new, unbound, "strict" {@link AFSocket}.
102    *
103    * This call uses an implementation that tries to be closer to the specification than
104    * {@link #newInstance()}, at least for some cases.
105    *
106    * @return A new, unbound socket.
107    * @throws IOException if the operation fails.
108    */
109   public static AFSYSTEMSocket newStrictInstance() throws IOException {
110     return (AFSYSTEMSocket) AFSocket.newInstance(AFSYSTEMSocket::new, (AFSYSTEMSocketFactory) null);
111   }
112 
113   /**
114    * Creates a new {@link AFSocket} and connects it to the given {@link AFSYSTEMSocketAddress}.
115    *
116    * @param addr The address to connect to.
117    * @return A new, connected socket.
118    * @throws IOException if the operation fails.
119    */
120   public static AFSYSTEMSocket connectTo(AFSYSTEMSocketAddress addr) throws IOException {
121     return (AFSYSTEMSocket) AFSocket.connectTo(AFSYSTEMSocket::new, addr);
122   }
123 
124   @Override
125   public AFSYSTEMSocketChannel getChannel() {
126     return (AFSYSTEMSocketChannel) super.getChannel();
127   }
128 
129   /**
130    * Very basic self-test function.
131    *
132    * Prints "supported" and "capabilities" status to System.out.
133    *
134    * @param args ignored.
135    */
136   public static void main(String[] args) {
137     System.out.print(AFSYSTEMSocket.class.getName() + ".isSupported(): ");
138     System.out.flush();
139     System.out.println(AFSYSTEMSocket.isSupported());
140   }
141 }