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.IOException;
21 import java.io.ObjectOutput;
22 import java.lang.reflect.Proxy;
23 import java.rmi.Remote;
24 import java.rmi.server.RMISocketFactory;
25 import java.rmi.server.RemoteObject;
26 import java.rmi.server.RemoteObjectInvocationHandler;
27
28 import org.newsclub.net.unix.AFUNIXSocketCredentials;
29
30 import com.kohlschutter.annotations.compiletime.SuppressFBWarnings;
31
32
33
34
35
36
37 public final class RemotePeerInfo {
38 private RMISocketFactory socketFactory;
39 String host;
40 int port;
41 private AFUNIXSocketCredentials peerCredentials;
42
43 RemotePeerInfo() {
44 }
45
46
47
48
49
50
51 public RMISocketFactory getSocketFactory() {
52 return socketFactory;
53 }
54
55
56
57
58
59
60 public String getHost() {
61 return host;
62 }
63
64
65
66
67
68
69 public int getPort() {
70 return port;
71 }
72
73
74
75
76
77
78 @SuppressFBWarnings("EI_EXPOSE_REP")
79 public AFUNIXSocketCredentials getPeerCredentials() {
80 return peerCredentials;
81 }
82
83
84
85
86
87
88
89
90 public static AFUNIXSocketCredentials remotePeerCredentials() {
91 return AFUNIXSocketCredentials.remotePeerCredentials();
92 }
93
94
95
96
97
98
99
100
101
102 public static AFUNIXSocketCredentials remotePeerCredentials(Remote obj) throws IOException {
103 return getConnectionInfo(obj).getPeerCredentials();
104 }
105
106
107
108
109
110
111
112
113
114
115
116
117 public static RemotePeerInfo getConnectionInfo(Remote obj) throws IOException {
118 try (RemotePeerInfo.ExtractingObjectOutput eoo = new RemotePeerInfo.ExtractingObjectOutput()) {
119 RemoteObjectInvocationHandler roih = (RemoteObjectInvocationHandler) Proxy
120 .getInvocationHandler(RemoteObject.toStub(obj));
121
122 roih.getRef().writeExternal(eoo);
123 if (!eoo.validate()) {
124 throw new IOException("Unexpected data format for " + obj.getClass());
125 }
126
127 RemotePeerInfo data = eoo.data;
128 if ((data.socketFactory) instanceof AFUNIXRMISocketFactory) {
129 AFUNIXRMISocketFactory sf = ((AFUNIXRMISocketFactory) (data.socketFactory));
130 data.peerCredentials = sf.peerCredentialsFor(data);
131
132 if (data.peerCredentials == null) {
133 if (sf.isLocalServer(data.port)) {
134 data.peerCredentials = AFUNIXSocketCredentials.SAME_PROCESS;
135 }
136 }
137 } else {
138 data.peerCredentials = null;
139 }
140
141 return data;
142 }
143 }
144
145
146
147
148
149
150
151
152
153
154 static final class ExtractingObjectOutput implements ObjectOutput {
155 private int callId = 0;
156 private boolean done = false;
157 private boolean invalid = false;
158 private int format = -1;
159
160 final RemotePeerInfo data = new RemotePeerInfo();
161
162 public ExtractingObjectOutput() {
163 }
164
165 private void setInvalid() {
166 invalid = done = true;
167 }
168
169 private void call(int id, Object v) {
170 switch (id) {
171 case 1:
172 if (v instanceof Integer) {
173
174 switch ((int) v) {
175 case 0:
176
177 format = 0;
178 return;
179 case 1:
180
181 format = 1;
182 return;
183 default:
184 }
185 }
186 break;
187 case 2:
188 if (v instanceof String) {
189 this.data.host = (String) v;
190 return;
191 }
192 break;
193 case 3:
194 if (format == 0) {
195 done = true;
196 }
197 if (v instanceof Integer) {
198 this.data.port = (int) v;
199 if (this.data.port <= 0) {
200 setInvalid();
201 }
202 return;
203 }
204 break;
205 case 4:
206 if (v instanceof RMISocketFactory && format == 1) {
207 this.data.socketFactory = (RMISocketFactory) v;
208 return;
209 }
210 break;
211 default:
212
213 done = true;
214 return;
215 }
216
217
218 setInvalid();
219 }
220
221 @Override
222 public void writeBoolean(boolean v) {
223 if (done) {
224 return;
225 }
226 call(++callId, v);
227 }
228
229 @Override
230 public void writeByte(int v) {
231 if (done) {
232 return;
233 }
234 call(++callId, v);
235 }
236
237 @Override
238 public void writeShort(int v) {
239 if (done) {
240 return;
241 }
242 call(++callId, v);
243 }
244
245 @Override
246 public void writeChar(int v) {
247 if (done) {
248 return;
249 }
250 call(++callId, v);
251 }
252
253 @Override
254 public void writeInt(int v) {
255 if (done) {
256 return;
257 }
258 call(++callId, v);
259 }
260
261 @Override
262 public void writeLong(long v) {
263 if (done) {
264 return;
265 }
266 call(++callId, v);
267 }
268
269 @Override
270 public void writeFloat(float v) {
271 if (done) {
272 return;
273 }
274 call(++callId, v);
275 }
276
277 @Override
278 public void writeDouble(double v) {
279 if (done) {
280 return;
281 }
282 call(++callId, v);
283 }
284
285 @Override
286 public void writeBytes(String s) {
287 if (done) {
288 return;
289 }
290 call(++callId, s);
291 }
292
293 @Override
294 public void writeChars(String s) {
295 if (done) {
296 return;
297 }
298 call(++callId, s);
299 }
300
301 @Override
302 public void writeUTF(String s) {
303 if (done) {
304 return;
305 }
306 call(++callId, s);
307 }
308
309 @Override
310 public void writeObject(Object obj) {
311 if (done) {
312 return;
313 }
314 call(++callId, obj);
315 }
316
317 @Override
318 public void write(int b) {
319 if (done) {
320 return;
321 }
322 call(++callId, b);
323 }
324
325 @Override
326 public void write(byte[] b) {
327 if (done) {
328 return;
329 }
330 call(++callId, b);
331 }
332
333 @Override
334 public void write(byte[] b, int off, int len) {
335 if (done) {
336 return;
337 }
338 setInvalid();
339
340
341
342 }
343
344 @Override
345 public void flush() {
346 }
347
348 public boolean validate() {
349 this.done = true;
350 if (callId < 3) {
351 setInvalid();
352 }
353 return !invalid;
354 }
355
356 @Override
357 public void close() {
358 }
359 }
360
361 @Override
362 public String toString() {
363 return getClass().getName() + "[" + host + ":" + port + ";socketFactory=" + socketFactory
364 + ";peerCredentials=" + peerCredentials + "]";
365 }
366 }