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