1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.newsclub.net.unix;
19
20 import java.io.Closeable;
21 import java.io.FileDescriptor;
22 import java.io.IOException;
23 import java.net.SocketException;
24 import java.nio.ByteBuffer;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30
31 final class AncillaryDataSupport implements Closeable {
32 private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
33 private static final FileDescriptor[] NO_FILE_DESCRIPTORS = new FileDescriptor[0];
34
35 private static final int MIN_ANCBUF_LEN = NativeUnixSocket.isLoaded() ? NativeUnixSocket
36 .ancillaryBufMinLen() : 0;
37
38 private final Map<FileDescriptor, Integer> openReceivedFileDescriptors = Collections
39 .synchronizedMap(new HashMap<>());
40
41 private final List<FileDescriptor[]> receivedFileDescriptors = Collections.synchronizedList(
42 new ArrayList<>());
43
44
45 private ByteBuffer ancillaryReceiveBuffer = EMPTY_BUFFER;
46
47
48 int[] pendingFileDescriptors = null;
49
50 private int[] tipcErrorInfo = null;
51
52 private int[] tipcDestName = null;
53
54
55 void setTipcErrorInfo(int errorCode, int dataLength) {
56 if (errorCode == 0 && dataLength == 0) {
57 tipcErrorInfo = null;
58 } else {
59 tipcErrorInfo = new int[] {errorCode, dataLength};
60 }
61 }
62
63 int[] getTIPCErrorInfo() {
64 int[] info = tipcErrorInfo;
65 tipcErrorInfo = null;
66 return info;
67 }
68
69 void setTipcDestName(int a, int b, int c) {
70 if (a == 0 && b == 0 && c == 0) {
71 this.tipcDestName = null;
72 } else {
73 this.tipcDestName = new int[] {a, b, c};
74 }
75 }
76
77 int[] getTIPCDestName() {
78 int[] addr = tipcDestName;
79 tipcDestName = null;
80 return addr;
81 }
82
83 int getAncillaryReceiveBufferSize() {
84 return ancillaryReceiveBuffer.capacity();
85 }
86
87 void setAncillaryReceiveBufferSize(int size) {
88 if (size == ancillaryReceiveBuffer.capacity()) {
89 return;
90 } else if (size <= 0) {
91 this.ancillaryReceiveBuffer = EMPTY_BUFFER;
92 } else {
93 setAncillaryReceiveBufferSize0(Math.max(256, Math.min(MIN_ANCBUF_LEN, size)));
94 }
95 }
96
97 void setAncillaryReceiveBufferSize0(int size) {
98 this.ancillaryReceiveBuffer = ByteBuffer.allocateDirect(size);
99 }
100
101 public void ensureAncillaryReceiveBufferSize(int minSize) {
102 if (minSize <= 0) {
103 return;
104 }
105 if (ancillaryReceiveBuffer.capacity() < minSize) {
106 setAncillaryReceiveBufferSize(minSize);
107 }
108 }
109
110
111 void receiveFileDescriptors(int[] fds) throws IOException {
112 if (fds == null || fds.length == 0) {
113 return;
114 }
115 final int fdsLength = fds.length;
116 FileDescriptor[] descriptors = new FileDescriptor[fdsLength];
117 for (int i = 0; i < fdsLength; i++) {
118 final FileDescriptor fdesc = new FileDescriptor();
119 NativeUnixSocket.initFD(fdesc, fds[i]);
120 descriptors[i] = fdesc;
121
122 openReceivedFileDescriptors.put(fdesc, fds[i]);
123
124 final Closeable cleanup = new Closeable() {
125
126 @Override
127 public void close() throws IOException {
128 openReceivedFileDescriptors.remove(fdesc);
129 }
130 };
131
132 try {
133 NativeUnixSocket.attachCloseable(fdesc, cleanup);
134 } catch (SocketException e) {
135
136 }
137 }
138
139 this.receivedFileDescriptors.add(descriptors);
140 }
141
142 void clearReceivedFileDescriptors() {
143 receivedFileDescriptors.clear();
144 }
145
146 FileDescriptor[] getReceivedFileDescriptors() {
147 if (receivedFileDescriptors.isEmpty()) {
148 return NO_FILE_DESCRIPTORS;
149 }
150 List<FileDescriptor[]> copy = new ArrayList<>(receivedFileDescriptors);
151 if (copy.isEmpty()) {
152 return NO_FILE_DESCRIPTORS;
153 }
154 receivedFileDescriptors.removeAll(copy);
155 int count = 0;
156 for (FileDescriptor[] fds : copy) {
157 count += fds.length;
158 }
159 if (count == 0) {
160 return NO_FILE_DESCRIPTORS;
161 }
162 FileDescriptor[] oneArray = new FileDescriptor[count];
163 int offset = 0;
164 for (FileDescriptor[] fds : copy) {
165 System.arraycopy(fds, 0, oneArray, offset, fds.length);
166 offset += fds.length;
167 }
168 return oneArray;
169 }
170
171 void setOutboundFileDescriptors(int[] fds) {
172 this.pendingFileDescriptors = (fds == null || fds.length == 0) ? null : fds;
173 }
174
175 boolean hasOutboundFileDescriptors() {
176 return this.pendingFileDescriptors != null;
177 }
178
179 void setOutboundFileDescriptors(FileDescriptor... fdescs) throws IOException {
180 final int[] fds;
181 if (fdescs == null || fdescs.length == 0) {
182 fds = null;
183 } else {
184 final int numFdescs = fdescs.length;
185 fds = new int[numFdescs];
186 for (int i = 0; i < numFdescs; i++) {
187 FileDescriptor fdesc = fdescs[i];
188 fds[i] = NativeUnixSocket.getFD(fdesc);
189 }
190 }
191 this.setOutboundFileDescriptors(fds);
192 }
193
194 @Override
195 public void close() {
196 synchronized (openReceivedFileDescriptors) {
197 for (FileDescriptor desc : openReceivedFileDescriptors.keySet()) {
198 if (desc.valid()) {
199 try {
200 NativeUnixSocket.close(desc);
201 } catch (Exception e) {
202
203 }
204 }
205 }
206 }
207 }
208 }