0
# File Descriptor Operations
1
2
Advanced Unix Domain Socket features including file descriptor passing, peer credentials, and ancillary message handling for sophisticated inter-process communication scenarios.
3
4
## Core Imports
5
6
```java
7
import java.io.*;
8
import java.net.*;
9
import org.newsclub.net.unix.AFUNIXSocket;
10
import org.newsclub.net.unix.AFUNIXSocketChannel;
11
import org.newsclub.net.unix.AFUNIXSocketCredentials;
12
import org.newsclub.net.unix.AFUNIXSocketExtensions;
13
import org.newsclub.net.unix.AFSocketCapability;
14
import org.newsclub.net.unix.FileDescriptorAccess;
15
```
16
17
## Capabilities
18
19
### AFUNIXSocketExtensions
20
21
Interface defining advanced Unix Domain Socket extensions beyond the standard Socket API, including file descriptor passing and credential access.
22
23
```java { .api }
24
/**
25
* Advanced Unix Domain Socket extensions interface
26
*/
27
public interface AFUNIXSocketExtensions {
28
29
/**
30
* Gets file descriptors received via ancillary messages
31
* File descriptors are received automatically with regular data
32
* @return Array of received file descriptors, never null
33
* @throws IOException if retrieval fails
34
*/
35
FileDescriptor[] getReceivedFileDescriptors() throws IOException;
36
37
/**
38
* Clears the queue of received file descriptors
39
* Should be called after processing received file descriptors
40
*/
41
void clearReceivedFileDescriptors();
42
43
/**
44
* Sets file descriptors to be sent via ancillary messages
45
* File descriptors will be sent with the next write operation
46
* @param fds File descriptors to send (can be empty to clear)
47
* @throws IOException if setting fails
48
*/
49
void setOutboundFileDescriptors(FileDescriptor... fds) throws IOException;
50
51
/**
52
* Checks if outbound file descriptors are pending
53
* @return true if file descriptors are queued for sending
54
*/
55
boolean hasOutboundFileDescriptors();
56
57
/**
58
* Gets credentials of the peer process
59
* @return Peer credentials information
60
* @throws IOException if retrieval fails or not supported
61
*/
62
AFUNIXSocketCredentials getPeerCredentials() throws IOException;
63
}
64
```
65
66
**Usage Examples:**
67
68
```java
69
import java.io.*;
70
import java.nio.charset.StandardCharsets;
71
import org.newsclub.net.unix.*;
72
73
// Server: Receiving file descriptors
74
File serverSocket = new File("/tmp/fd-server.sock");
75
try (AFUNIXServerSocket server = AFUNIXServerSocket.bindOn(AFUNIXSocketAddress.of(serverSocket))) {
76
System.out.println("Server waiting for connections...");
77
78
try (AFUNIXSocket clientSocket = server.accept()) {
79
System.out.println("Client connected");
80
81
// Read regular data and file descriptors
82
InputStream is = clientSocket.getInputStream();
83
byte[] buffer = new byte[1024];
84
int bytesRead = is.read(buffer);
85
String message = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
86
System.out.println("Received message: " + message);
87
88
// Check for received file descriptors
89
FileDescriptor[] receivedFds = clientSocket.getReceivedFileDescriptors();
90
System.out.println("Received " + receivedFds.length + " file descriptors");
91
92
for (int i = 0; i < receivedFds.length; i++) {
93
// Use the received file descriptor
94
try (FileInputStream fis = new FileInputStream(receivedFds[i])) {
95
byte[] fileBuffer = new byte[1024];
96
int fileBytes = fis.read(fileBuffer);
97
String fileContent = new String(fileBuffer, 0, fileBytes, StandardCharsets.UTF_8);
98
System.out.println("Content from FD " + i + ": " + fileContent);
99
}
100
}
101
102
// Clear received file descriptors after processing
103
clientSocket.clearReceivedFileDescriptors();
104
105
// Get peer credentials
106
AFUNIXSocketCredentials peerCreds = clientSocket.getPeerCredentials();
107
System.out.println("Peer process ID: " + peerCreds.getPid());
108
System.out.println("Peer user ID: " + peerCreds.getUid());
109
System.out.println("Peer group ID: " + peerCreds.getGid());
110
}
111
}
112
113
// Client: Sending file descriptors
114
File clientSocket = new File("/tmp/fd-client.sock");
115
try (AFUNIXSocket socket = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(serverSocket))) {
116
117
// Create a temporary file to send
118
File tempFile = File.createTempFile("test", ".txt");
119
try (FileWriter writer = new FileWriter(tempFile)) {
120
writer.write("Hello from shared file!");
121
}
122
123
// Open file descriptor to send
124
FileInputStream fileInput = new FileInputStream(tempFile);
125
FileDescriptor fd = fileInput.getFD();
126
127
// Set file descriptor to be sent
128
socket.setOutboundFileDescriptors(fd);
129
130
// Send regular data (file descriptor will be sent automatically)
131
OutputStream os = socket.getOutputStream();
132
os.write("Sending file descriptor".getBytes(StandardCharsets.UTF_8));
133
os.flush();
134
135
System.out.println("File descriptor sent with message");
136
137
// Clean up
138
fileInput.close();
139
tempFile.delete();
140
}
141
```
142
143
### AFUNIXSocketCredentials
144
145
Container for Unix Domain Socket peer credentials, providing access to peer process information for authentication and authorization.
146
147
```java { .api }
148
/**
149
* Unix Domain Socket peer credentials
150
*/
151
public final class AFUNIXSocketCredentials {
152
153
/**
154
* Gets the process ID of the peer
155
* @return Process ID (PID)
156
*/
157
public long getPid();
158
159
/**
160
* Gets the user ID of the peer process
161
* @return User ID (UID)
162
*/
163
public long getUid();
164
165
/**
166
* Gets the primary group ID of the peer process
167
* @return Primary group ID (GID)
168
*/
169
public long getGid();
170
171
/**
172
* Gets all group IDs of the peer process
173
* @return Array of all group IDs
174
*/
175
public long[] getGids();
176
177
/**
178
* Gets the UUID of the peer process (if available)
179
* @return Process UUID or null
180
*/
181
public String getUUID();
182
183
/**
184
* Creates credentials for the current process
185
* @return Current process credentials
186
*/
187
public static AFUNIXSocketCredentials current();
188
189
/**
190
* Gets remote peer credentials from RMI context
191
* Used in RMI scenarios to identify the calling process
192
* @return Remote peer credentials or null
193
*/
194
public static AFUNIXSocketCredentials remotePeerCredentials();
195
196
/**
197
* String representation of credentials
198
* @return Human-readable credential information
199
*/
200
public String toString();
201
}
202
```
203
204
**Usage Examples:**
205
206
```java
207
import org.newsclub.net.unix.*;
208
209
// Authentication server using peer credentials
210
File authServerSocket = new File("/tmp/auth-server.sock");
211
try (AFUNIXServerSocket server = AFUNIXServerSocket.bindOn(AFUNIXSocketAddress.of(authServerSocket))) {
212
213
while (true) {
214
try (AFUNIXSocket client = server.accept()) {
215
// Get peer credentials for authentication
216
AFUNIXSocketCredentials peerCreds = client.getPeerCredentials();
217
218
System.out.println("Connection from:");
219
System.out.println(" PID: " + peerCreds.getPid());
220
System.out.println(" UID: " + peerCreds.getUid());
221
System.out.println(" GID: " + peerCreds.getGid());
222
223
// Simple authorization check
224
if (peerCreds.getUid() == 0) {
225
System.out.println("Root user detected - full access granted");
226
client.getOutputStream().write("ADMIN_ACCESS".getBytes());
227
} else if (peerCreds.getUid() == getCurrentUserId()) {
228
System.out.println("Same user - standard access granted");
229
client.getOutputStream().write("USER_ACCESS".getBytes());
230
} else {
231
System.out.println("Different user - access denied");
232
client.getOutputStream().write("ACCESS_DENIED".getBytes());
233
}
234
235
client.getOutputStream().flush();
236
}
237
}
238
}
239
240
// Check group memberships
241
AFUNIXSocketCredentials currentCreds = AFUNIXSocketCredentials.current();
242
long[] groups = currentCreds.getGids();
243
System.out.println("Current process belongs to " + groups.length + " groups:");
244
for (long gid : groups) {
245
System.out.println(" GID: " + gid);
246
}
247
```
248
249
### FileDescriptorAccess
250
251
Utility class for advanced file descriptor operations and access to native file descriptor values.
252
253
```java { .api }
254
/**
255
* Utility class for file descriptor access and operations
256
*/
257
public final class FileDescriptorAccess {
258
259
/**
260
* Gets the native file descriptor value from a FileDescriptor
261
* @param fd The FileDescriptor instance
262
* @return Native file descriptor number
263
* @throws IOException if access fails
264
*/
265
public static int getFileDescriptor(FileDescriptor fd) throws IOException;
266
267
/**
268
* Gets the file descriptor from an AFSocket
269
* @param socket The socket instance
270
* @return Socket's file descriptor
271
* @throws IOException if access fails
272
*/
273
public static FileDescriptor getFileDescriptor(AFSocket socket) throws IOException;
274
275
/**
276
* Checks if a file descriptor is valid
277
* @param fd The FileDescriptor to check
278
* @return true if the file descriptor is valid
279
*/
280
public static boolean isValid(FileDescriptor fd);
281
282
/**
283
* Creates a FileDescriptor from a native file descriptor number
284
* @param fdNum Native file descriptor number
285
* @return FileDescriptor instance
286
* @throws IOException if creation fails
287
*/
288
public static FileDescriptor fromNative(int fdNum) throws IOException;
289
}
290
```
291
292
**Usage Examples:**
293
294
```java
295
import org.newsclub.net.unix.*;
296
297
// File descriptor introspection
298
try (AFUNIXSocket socket = AFUNIXSocket.newInstance()) {
299
socket.connect(AFUNIXSocketAddress.of(new File("/tmp/test.sock")));
300
301
// Get the socket's file descriptor
302
FileDescriptor socketFd = FileDescriptorAccess.getFileDescriptor(socket);
303
int nativeFd = FileDescriptorAccess.getFileDescriptor(socketFd);
304
305
System.out.println("Socket file descriptor: " + nativeFd);
306
System.out.println("File descriptor valid: " + FileDescriptorAccess.isValid(socketFd));
307
308
// Create file descriptor for stdout
309
FileDescriptor stdoutFd = FileDescriptorAccess.fromNative(1);
310
socket.setOutboundFileDescriptors(stdoutFd);
311
312
// Send message with stdout file descriptor
313
socket.getOutputStream().write("Check your terminal!".getBytes());
314
socket.getOutputStream().flush();
315
}
316
```
317
318
### Capability Detection
319
320
Check for file descriptor and credential support before using advanced features:
321
322
```java { .api }
323
/**
324
* Capability constants for file descriptor features
325
*/
326
public enum AFSocketCapability {
327
/** File descriptor passing support */
328
CAPABILITY_FILE_DESCRIPTORS,
329
330
/** Peer credential support */
331
CAPABILITY_PEER_CREDENTIALS,
332
333
/** Ancillary message support */
334
CAPABILITY_ANCILLARY_MESSAGES
335
}
336
```
337
338
**Feature Detection Examples:**
339
340
```java
341
import org.newsclub.net.unix.*;
342
343
public class FeatureDetection {
344
public static void main(String[] args) {
345
System.out.println("Advanced Unix Socket Features:");
346
347
if (AFSocketCapability.CAPABILITY_FILE_DESCRIPTORS.isSupported()) {
348
System.out.println("✓ File descriptor passing available");
349
demonstrateFileDescriptorPassing();
350
} else {
351
System.out.println("✗ File descriptor passing not supported");
352
}
353
354
if (AFSocketCapability.CAPABILITY_PEER_CREDENTIALS.isSupported()) {
355
System.out.println("✓ Peer credentials available");
356
demonstratePeerCredentials();
357
} else {
358
System.out.println("✗ Peer credentials not supported");
359
}
360
361
if (AFSocketCapability.CAPABILITY_ANCILLARY_MESSAGES.isSupported()) {
362
System.out.println("✓ Ancillary messages available");
363
} else {
364
System.out.println("✗ Ancillary messages not supported");
365
}
366
}
367
368
private static void demonstrateFileDescriptorPassing() {
369
// File descriptor passing implementation
370
System.out.println(" → File descriptor passing is fully functional");
371
}
372
373
private static void demonstratePeerCredentials() {
374
// Peer credentials implementation
375
AFUNIXSocketCredentials current = AFUNIXSocketCredentials.current();
376
System.out.println(" → Current process PID: " + current.getPid());
377
System.out.println(" → Current process UID: " + current.getUid());
378
}
379
}
380
```
381
382
### Security Considerations
383
384
When using file descriptor passing and peer credentials:
385
386
1. **Validate Received File Descriptors**: Always validate file descriptors before use
387
2. **Check Permissions**: Verify peer credentials for authorization
388
3. **Resource Management**: Properly close received file descriptors
389
4. **Error Handling**: Handle cases where features are not supported
390
5. **Capability Testing**: Always test capabilities before using advanced features
391
392
```java
393
// Safe file descriptor handling
394
FileDescriptor[] receivedFds = socket.getReceivedFileDescriptors();
395
for (FileDescriptor fd : receivedFds) {
396
if (FileDescriptorAccess.isValid(fd)) {
397
try {
398
// Use the file descriptor
399
processFileDescriptor(fd);
400
} finally {
401
// Ensure proper cleanup
402
try {
403
// Close if it's a file we opened
404
if (fd != FileDescriptor.in && fd != FileDescriptor.out && fd != FileDescriptor.err) {
405
// Close safely
406
}
407
} catch (Exception e) {
408
// Log but don't fail
409
}
410
}
411
}
412
}
413
socket.clearReceivedFileDescriptors();
414
```