1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  
18  package org.newsclub.net.unix.rmi;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.io.ObjectInput;
23  import java.io.ObjectOutput;
24  import java.rmi.server.RMIClientSocketFactory;
25  import java.rmi.server.RMIServerSocketFactory;
26  import java.rmi.server.RMISocketFactory;
27  import java.util.HashMap;
28  import java.util.Map;
29  import java.util.Objects;
30  
31  import org.newsclub.net.unix.AFSocket;
32  import org.newsclub.net.unix.AFSocketAddress;
33  import org.newsclub.net.unix.AFUNIXSocket;
34  import org.newsclub.net.unix.AFUNIXSocketAddress;
35  import org.newsclub.net.unix.AFUNIXSocketCredentials;
36  import org.newsclub.net.unix.HostAndPort;
37  
38  import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
39  
40  
41  
42  
43  
44  
45  public class AFUNIXRMISocketFactory extends AFRMISocketFactory {
46    private static final long serialVersionUID = 1L;
47  
48    static final String DEFAULT_SOCKET_FILE_PREFIX = "";
49    static final String DEFAULT_SOCKET_FILE_SUFFIX = ".rmi";
50  
51    private File socketDir;
52    private String socketPrefix;
53    private String socketSuffix;
54  
55    private final transient Map<HostAndPort, AFUNIXSocketCredentials> credentials = new HashMap<>();
56  
57    
58  
59  
60  
61  
62    public AFUNIXRMISocketFactory() {
63      super();
64    }
65  
66    
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78    @SuppressFBWarnings("EI_EXPOSE_REP2")
79    public AFUNIXRMISocketFactory(final AFNaming naming, final File socketDir,
80        final RMIClientSocketFactory defaultClientFactory,
81        final RMIServerSocketFactory defaultServerFactory, final String socketPrefix,
82        final String socketSuffix) {
83      super(naming, defaultClientFactory, defaultServerFactory);
84      Objects.requireNonNull(socketDir);
85      this.socketDir = socketDir;
86      this.socketPrefix = socketPrefix == null ? DEFAULT_SOCKET_FILE_PREFIX : socketPrefix;
87      this.socketSuffix = socketSuffix == null ? DEFAULT_SOCKET_FILE_SUFFIX : socketSuffix;
88    }
89  
90    
91  
92  
93  
94  
95  
96  
97  
98    public AFUNIXRMISocketFactory(AFNaming naming, File socketDir,
99        RMIClientSocketFactory defaultClientFactory, RMIServerSocketFactory defaultServerFactory) {
100     this(naming, socketDir, defaultClientFactory, defaultServerFactory, null, null);
101   }
102 
103   
104 
105 
106 
107 
108 
109   public AFUNIXRMISocketFactory(AFNaming naming, File socketDir) {
110     this(naming, socketDir, DefaultRMIClientSocketFactory.getInstance(),
111         DefaultRMIServerSocketFactory.getInstance());
112   }
113 
114   @Override
115   protected AFNaming readNamingInstance(ObjectInput in) throws IOException {
116     socketDir = new File(in.readUTF());
117     int port = in.readInt();
118     return AFUNIXNaming.getInstance(socketDir, port);
119   }
120 
121   @Override
122   protected void writeNamingInstance(ObjectOutput out, AFNaming naming) throws IOException {
123     out.writeUTF(socketDir.getAbsolutePath());
124     out.writeInt(naming.getRegistryPort());
125   }
126 
127   @Override
128   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
129     super.readExternal(in);
130 
131     socketPrefix = in.readUTF();
132     socketSuffix = in.readUTF();
133   }
134 
135   @Override
136   public void writeExternal(ObjectOutput out) throws IOException {
137     super.writeExternal(out);
138 
139     out.writeUTF(socketPrefix);
140     out.writeUTF(socketSuffix);
141   }
142 
143   @Override
144   public int hashCode() {
145     return socketDir == null ? System.identityHashCode(this) : socketDir.hashCode();
146   }
147 
148   @Override
149   public boolean equals(Object other) {
150     if (!(other instanceof AFUNIXRMISocketFactory)) {
151       return false;
152     }
153     AFUNIXRMISocketFactory sf = (AFUNIXRMISocketFactory) other;
154     if (socketDir == null) {
155       return sf == this;
156     } else {
157       return socketDir.equals(sf.socketDir);
158     }
159   }
160 
161   
162 
163 
164 
165 
166   public File getSocketDir() {
167     return socketDir;
168   }
169 
170   File getFile(int port) {
171     if (isPlainFileSocket()) {
172       return getSocketDir();
173     } else {
174       Objects.requireNonNull(socketDir);
175       return new File(socketDir, socketPrefix + port + socketSuffix);
176     }
177   }
178 
179   boolean hasSocketFile(int port) {
180     return getFile(port).exists();
181   }
182 
183   private boolean isPlainFileSocket() {
184     return (getNaming().getRegistryPort() == RMIPorts.PLAIN_FILE_SOCKET);
185   }
186 
187   @Override
188   protected AFUNIXSocketAddress newSocketAddress(int port) throws IOException {
189     return AFUNIXSocketAddress.of(getFile(port), port);
190   }
191 
192   @Override
193   protected final AFSocket<?> newConnectedSocket(AFSocketAddress addr) throws IOException {
194     final AFUNIXSocket socket = ((AFUNIXSocketAddress) addr).newConnectedSocket();
195     AFUNIXSocketCredentials creds = socket.getPeerCredentials();
196 
197     final HostAndPort hap = new HostAndPort(addr.getHostString(), addr.getPort());
198     synchronized (credentials) {
199       if (credentials.put(hap, creds) != null) {
200         
201       }
202     }
203     socket.addCloseable(() -> {
204       synchronized (credentials) {
205         credentials.remove(hap);
206       }
207     });
208     return socket;
209   }
210 
211   @Override
212   public String toString() {
213     return super.toString() + 
214         "[path=" + socketDir + 
215         (isPlainFileSocket() ? "" : 
216             ";prefix=" + socketPrefix + ";suffix=" + socketSuffix) + "]";
217   }
218 
219   @Override
220   public void close() throws IOException {
221     synchronized (credentials) {
222       credentials.clear();
223     }
224     super.close();
225   }
226 
227   AFUNIXSocketCredentials peerCredentialsFor(RemotePeerInfo data) {
228     synchronized (credentials) {
229       return credentials.get(new HostAndPort(data.host, data.port));
230     }
231   }
232 
233   @Override
234   boolean hasRegisteredPort(int port) {
235     return hasSocketFile(port);
236   }
237 }