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