0
# Exception Handling
1
2
Comprehensive exception hierarchy providing detailed error information for robust socket error handling and debugging in Unix Domain Socket operations.
3
4
## Capabilities
5
6
### AFException
7
8
Base exception class for all AF socket-related errors, extending IOException to integrate with standard Java I/O exception handling.
9
10
```java { .api }
11
/**
12
* Base exception class for AF socket operations
13
*/
14
public class AFException extends IOException {
15
16
/**
17
* Creates a new AFException with the specified message
18
* @param message The error message
19
*/
20
public AFException(String message);
21
22
/**
23
* Creates a new AFException with message and cause
24
* @param message The error message
25
* @param cause The underlying cause
26
*/
27
public AFException(String message, Throwable cause);
28
29
/**
30
* Creates a new AFException with the specified cause
31
* @param cause The underlying cause
32
*/
33
public AFException(Throwable cause);
34
35
// Error information
36
public String getMessage();
37
public Throwable getCause();
38
public String getLocalizedMessage();
39
40
// Stack trace information
41
public StackTraceElement[] getStackTrace();
42
public void printStackTrace();
43
public void printStackTrace(PrintStream s);
44
public void printStackTrace(PrintWriter s);
45
}
46
```
47
48
**Usage Examples:**
49
50
```java
51
import org.newsclub.net.unix.*;
52
53
try {
54
AFUNIXSocket socket = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of("/nonexistent/path.sock"));
55
} catch (AFException e) {
56
System.err.println("AF Socket error: " + e.getMessage());
57
58
// Check for specific causes
59
Throwable cause = e.getCause();
60
if (cause instanceof FileNotFoundException) {
61
System.err.println("Socket file not found");
62
} else if (cause instanceof SecurityException) {
63
System.err.println("Permission denied");
64
}
65
66
// Log full stack trace for debugging
67
e.printStackTrace();
68
}
69
```
70
71
### Socket State Exceptions
72
73
Exceptions related to socket state and lifecycle management.
74
75
```java { .api }
76
/**
77
* Exception thrown when operating on closed sockets
78
*/
79
public class SocketClosedException extends SocketException {
80
public SocketClosedException();
81
public SocketClosedException(String msg);
82
public SocketClosedException(String msg, Throwable cause);
83
}
84
85
/**
86
* Exception thrown when socket address is unavailable
87
*/
88
public class AddressUnavailableSocketException extends SocketException {
89
public AddressUnavailableSocketException();
90
public AddressUnavailableSocketException(String msg);
91
public AddressUnavailableSocketException(String msg, Throwable cause);
92
}
93
94
/**
95
* Exception thrown when connection is refused
96
*/
97
public class ConnectionRefusedSocketException extends SocketException {
98
public ConnectionRefusedSocketException();
99
public ConnectionRefusedSocketException(String msg);
100
public ConnectionRefusedSocketException(String msg, Throwable cause);
101
}
102
```
103
104
**Usage Examples:**
105
106
```java
107
// Socket state validation
108
public void performSocketOperation(AFUNIXSocket socket) throws IOException {
109
try {
110
if (socket.isClosed()) {
111
throw new SocketClosedException("Socket is already closed");
112
}
113
114
// Perform operation
115
OutputStream os = socket.getOutputStream();
116
os.write("data".getBytes());
117
118
} catch (SocketClosedException e) {
119
System.err.println("Cannot operate on closed socket: " + e.getMessage());
120
throw e;
121
}
122
}
123
124
// Address availability check
125
public AFUNIXServerSocket createServer(File socketFile) throws IOException {
126
try {
127
AFUNIXSocketAddress address = AFUNIXSocketAddress.of(socketFile);
128
AFUNIXServerSocket server = AFUNIXServerSocket.newInstance();
129
server.bind(address);
130
return server;
131
132
} catch (AddressUnavailableSocketException e) {
133
System.err.println("Socket address unavailable: " + socketFile);
134
135
// Try to clean up and retry
136
if (socketFile.exists() && socketFile.delete()) {
137
System.out.println("Cleaned up stale socket file, retrying...");
138
return createServer(socketFile);
139
}
140
throw e;
141
}
142
}
143
144
// Connection handling
145
public void connectWithRetry(AFUNIXSocketAddress address, int maxRetries) throws IOException {
146
int attempts = 0;
147
148
while (attempts < maxRetries) {
149
try {
150
AFUNIXSocket socket = AFUNIXSocket.connectTo(address);
151
System.out.println("Connected successfully");
152
return;
153
154
} catch (ConnectionRefusedSocketException e) {
155
attempts++;
156
System.err.println("Connection refused, attempt " + attempts + "/" + maxRetries);
157
158
if (attempts >= maxRetries) {
159
throw new IOException("Failed to connect after " + maxRetries + " attempts", e);
160
}
161
162
try {
163
Thread.sleep(1000 * attempts); // Exponential backoff
164
} catch (InterruptedException ie) {
165
Thread.currentThread().interrupt();
166
throw new IOException("Connection interrupted", ie);
167
}
168
}
169
}
170
}
171
```
172
173
### Communication Exceptions
174
175
Exceptions related to data transmission and socket communication errors.
176
177
```java { .api }
178
/**
179
* Exception thrown when pipe is broken during communication
180
*/
181
public class BrokenPipeSocketException extends SocketException {
182
public BrokenPipeSocketException();
183
public BrokenPipeSocketException(String msg);
184
public BrokenPipeSocketException(String msg, Throwable cause);
185
}
186
187
/**
188
* Exception thrown when connection is reset by peer
189
*/
190
public class ConnectionResetSocketException extends SocketException {
191
public ConnectionResetSocketException();
192
public ConnectionResetSocketException(String msg);
193
public ConnectionResetSocketException(String msg, Throwable cause);
194
}
195
196
/**
197
* Exception thrown when socket times out
198
*/
199
public class SocketTimeoutException extends InterruptedIOException {
200
public SocketTimeoutException();
201
public SocketTimeoutException(String msg);
202
public SocketTimeoutException(String msg, Throwable cause);
203
}
204
```
205
206
**Usage Examples:**
207
208
```java
209
// Robust data transmission
210
public void sendDataWithErrorHandling(AFUNIXSocket socket, byte[] data) throws IOException {
211
try {
212
OutputStream os = socket.getOutputStream();
213
os.write(data);
214
os.flush();
215
216
} catch (BrokenPipeSocketException e) {
217
System.err.println("Broken pipe - peer closed connection: " + e.getMessage());
218
219
// Clean up resources
220
try {
221
socket.close();
222
} catch (IOException closeEx) {
223
e.addSuppressed(closeEx);
224
}
225
throw e;
226
227
} catch (ConnectionResetSocketException e) {
228
System.err.println("Connection reset by peer: " + e.getMessage());
229
230
// Log connection reset and clean up
231
logConnectionReset(socket, e);
232
throw e;
233
}
234
}
235
236
// Timeout handling
237
public String readWithTimeout(AFUNIXSocket socket, int timeoutMs) throws IOException {
238
try {
239
socket.setSoTimeout(timeoutMs);
240
241
InputStream is = socket.getInputStream();
242
byte[] buffer = new byte[1024];
243
int bytesRead = is.read(buffer);
244
245
if (bytesRead > 0) {
246
return new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
247
}
248
return null;
249
250
} catch (SocketTimeoutException e) {
251
System.err.println("Read timeout after " + timeoutMs + "ms: " + e.getMessage());
252
253
// Decide whether to retry or fail
254
if (shouldRetryAfterTimeout(socket)) {
255
return readWithTimeout(socket, timeoutMs * 2); // Double timeout and retry
256
}
257
throw e;
258
259
} finally {
260
// Reset timeout
261
socket.setSoTimeout(0);
262
}
263
}
264
265
private boolean shouldRetryAfterTimeout(AFUNIXSocket socket) {
266
return socket.isConnected() && !socket.isClosed();
267
}
268
269
private void logConnectionReset(AFUNIXSocket socket, ConnectionResetSocketException e) {
270
try {
271
AFUNIXSocketAddress localAddr = (AFUNIXSocketAddress) socket.getLocalSocketAddress();
272
AFUNIXSocketAddress remoteAddr = (AFUNIXSocketAddress) socket.getRemoteSocketAddress();
273
274
System.err.println("Connection reset - Local: " + localAddr + ", Remote: " + remoteAddr);
275
} catch (Exception ex) {
276
System.err.println("Connection reset - Unable to get socket addresses");
277
}
278
}
279
```
280
281
### System and Platform Exceptions
282
283
Exceptions related to system-level errors and platform-specific issues.
284
285
```java { .api }
286
/**
287
* Exception thrown when device or resource is not found
288
*/
289
public class NoSuchDeviceSocketException extends SocketException {
290
public NoSuchDeviceSocketException();
291
public NoSuchDeviceSocketException(String msg);
292
public NoSuchDeviceSocketException(String msg, Throwable cause);
293
}
294
295
/**
296
* Exception thrown when operation is not supported
297
*/
298
public class OperationNotSupportedSocketException extends SocketException {
299
public OperationNotSupportedSocketException();
300
public OperationNotSupportedSocketException(String msg);
301
public OperationNotSupportedSocketException(String msg, Throwable cause);
302
}
303
304
/**
305
* Exception thrown when invalid argument is provided
306
*/
307
public class InvalidArgumentSocketException extends SocketException {
308
public InvalidArgumentSocketException();
309
public InvalidArgumentSocketException(String msg);
310
public InvalidArgumentSocketException(String msg, Throwable cause);
311
}
312
```
313
314
**Usage Examples:**
315
316
```java
317
// Platform capability checking
318
public void performPlatformSpecificOperation(AFUNIXSocket socket) throws IOException {
319
try {
320
// Attempt platform-specific operation (e.g., peer credentials)
321
PeerCredentials credentials = socket.getPeerCredentials();
322
System.out.println("Peer PID: " + credentials.getPid());
323
324
} catch (OperationNotSupportedSocketException e) {
325
System.err.println("Peer credentials not supported on this platform: " + e.getMessage());
326
327
// Fall back to alternative approach
328
performAlternativeAuthentication(socket);
329
330
} catch (NoSuchDeviceSocketException e) {
331
System.err.println("Required device not available: " + e.getMessage());
332
throw new IOException("Platform requirements not met", e);
333
}
334
}
335
336
// Argument validation
337
public void configureSocket(AFUNIXSocket socket, Map<String, Object> options) throws IOException {
338
try {
339
for (Map.Entry<String, Object> option : options.entrySet()) {
340
applySocketOption(socket, option.getKey(), option.getValue());
341
}
342
343
} catch (InvalidArgumentSocketException e) {
344
System.err.println("Invalid socket configuration: " + e.getMessage());
345
346
// Log configuration details for debugging
347
System.err.println("Configuration options: " + options);
348
throw new IllegalArgumentException("Socket configuration failed", e);
349
}
350
}
351
352
private void applySocketOption(AFUNIXSocket socket, String optionName, Object value) throws IOException {
353
switch (optionName.toLowerCase()) {
354
case "timeout":
355
if (!(value instanceof Integer)) {
356
throw new InvalidArgumentSocketException("Timeout must be an integer");
357
}
358
socket.setSoTimeout((Integer) value);
359
break;
360
361
case "keepalive":
362
if (!(value instanceof Boolean)) {
363
throw new InvalidArgumentSocketException("KeepAlive must be a boolean");
364
}
365
socket.setKeepAlive((Boolean) value);
366
break;
367
368
default:
369
throw new InvalidArgumentSocketException("Unknown socket option: " + optionName);
370
}
371
}
372
373
private void performAlternativeAuthentication(AFUNIXSocket socket) {
374
// Alternative authentication mechanism
375
System.out.println("Using alternative authentication method");
376
}
377
```
378
379
## Exception Handling Patterns
380
381
### Comprehensive Error Handling
382
383
```java
384
// Complete error handling pattern for socket operations
385
public class RobustSocketClient {
386
private static final int MAX_RETRIES = 3;
387
private static final int RETRY_DELAY_MS = 1000;
388
389
public void performRobustOperation(File socketFile, byte[] data) throws IOException {
390
AFUNIXSocketAddress address = AFUNIXSocketAddress.of(socketFile);
391
IOException lastException = null;
392
393
for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
394
try {
395
performSingleOperation(address, data);
396
return; // Success
397
398
} catch (AddressUnavailableSocketException e) {
399
System.err.println("Attempt " + attempt + ": Address unavailable - " + e.getMessage());
400
lastException = e;
401
402
if (attempt == MAX_RETRIES) {
403
throw new IOException("Socket server appears to be down", e);
404
}
405
406
} catch (ConnectionRefusedSocketException e) {
407
System.err.println("Attempt " + attempt + ": Connection refused - " + e.getMessage());
408
lastException = e;
409
410
if (attempt == MAX_RETRIES) {
411
throw new IOException("Server not accepting connections", e);
412
}
413
414
} catch (BrokenPipeSocketException | ConnectionResetSocketException e) {
415
System.err.println("Attempt " + attempt + ": Connection lost - " + e.getMessage());
416
lastException = e;
417
418
// Don't retry on connection loss
419
throw new IOException("Connection lost during operation", e);
420
421
} catch (SocketTimeoutException e) {
422
System.err.println("Attempt " + attempt + ": Operation timed out - " + e.getMessage());
423
lastException = e;
424
425
if (attempt == MAX_RETRIES) {
426
throw new IOException("Operation timed out after " + MAX_RETRIES + " attempts", e);
427
}
428
429
} catch (OperationNotSupportedSocketException e) {
430
// Don't retry unsupported operations
431
throw new IOException("Operation not supported on this platform", e);
432
433
} catch (AFException e) {
434
System.err.println("Attempt " + attempt + ": AF socket error - " + e.getMessage());
435
lastException = e;
436
437
if (attempt == MAX_RETRIES) {
438
throw new IOException("Socket operation failed", e);
439
}
440
}
441
442
if (attempt < MAX_RETRIES) {
443
try {
444
Thread.sleep(RETRY_DELAY_MS * attempt); // Progressive delay
445
} catch (InterruptedException ie) {
446
Thread.currentThread().interrupt();
447
throw new IOException("Operation interrupted", ie);
448
}
449
}
450
}
451
452
throw new IOException("All retry attempts failed", lastException);
453
}
454
455
private void performSingleOperation(AFUNIXSocketAddress address, byte[] data) throws IOException {
456
try (AFUNIXSocket socket = AFUNIXSocket.connectTo(address)) {
457
socket.setSoTimeout(5000); // 5 second timeout
458
459
// Send data
460
OutputStream os = socket.getOutputStream();
461
os.write(data);
462
os.flush();
463
464
// Read response
465
InputStream is = socket.getInputStream();
466
byte[] buffer = new byte[1024];
467
int bytesRead = is.read(buffer);
468
469
if (bytesRead > 0) {
470
String response = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
471
System.out.println("Received: " + response);
472
}
473
}
474
}
475
}
476
```
477
478
### Exception Classification and Recovery
479
480
```java
481
// Exception classification for different recovery strategies
482
public class ExceptionHandler {
483
484
public enum ErrorSeverity {
485
RECOVERABLE, // Can retry
486
TRANSIENT, // May recover after delay
487
PERMANENT, // Don't retry
488
FATAL // Should terminate
489
}
490
491
public static ErrorSeverity classifyException(Exception e) {
492
if (e instanceof SocketClosedException) {
493
return ErrorSeverity.PERMANENT;
494
} else if (e instanceof AddressUnavailableSocketException) {
495
return ErrorSeverity.TRANSIENT;
496
} else if (e instanceof ConnectionRefusedSocketException) {
497
return ErrorSeverity.TRANSIENT;
498
} else if (e instanceof BrokenPipeSocketException) {
499
return ErrorSeverity.PERMANENT;
500
} else if (e instanceof ConnectionResetSocketException) {
501
return ErrorSeverity.PERMANENT;
502
} else if (e instanceof SocketTimeoutException) {
503
return ErrorSeverity.RECOVERABLE;
504
} else if (e instanceof OperationNotSupportedSocketException) {
505
return ErrorSeverity.FATAL;
506
} else if (e instanceof InvalidArgumentSocketException) {
507
return ErrorSeverity.FATAL;
508
} else if (e instanceof AFException) {
509
return ErrorSeverity.TRANSIENT;
510
}
511
return ErrorSeverity.PERMANENT;
512
}
513
514
public static boolean shouldRetry(Exception e, int attemptCount, int maxAttempts) {
515
if (attemptCount >= maxAttempts) {
516
return false;
517
}
518
519
ErrorSeverity severity = classifyException(e);
520
return severity == ErrorSeverity.RECOVERABLE || severity == ErrorSeverity.TRANSIENT;
521
}
522
523
public static long getRetryDelay(Exception e, int attemptCount) {
524
ErrorSeverity severity = classifyException(e);
525
526
switch (severity) {
527
case RECOVERABLE:
528
return Math.min(1000L * (1L << attemptCount), 30000L); // Exponential backoff, max 30s
529
case TRANSIENT:
530
return Math.min(2000L * attemptCount, 10000L); // Linear backoff, max 10s
531
default:
532
return 0L;
533
}
534
}
535
}
536
```
537
538
### Logging and Monitoring
539
540
```java
541
// Exception logging for monitoring and debugging
542
public class SocketExceptionLogger {
543
private static final Logger logger = LoggerFactory.getLogger(SocketExceptionLogger.class);
544
545
public static void logException(Exception e, AFUNIXSocket socket, String operation) {
546
Map<String, Object> context = new HashMap<>();
547
context.put("operation", operation);
548
context.put("exception_type", e.getClass().getSimpleName());
549
context.put("exception_message", e.getMessage());
550
551
try {
552
if (socket != null) {
553
context.put("socket_closed", socket.isClosed());
554
context.put("socket_connected", socket.isConnected());
555
context.put("socket_bound", socket.isBound());
556
557
if (socket.getLocalSocketAddress() != null) {
558
context.put("local_address", socket.getLocalSocketAddress().toString());
559
}
560
if (socket.getRemoteSocketAddress() != null) {
561
context.put("remote_address", socket.getRemoteSocketAddress().toString());
562
}
563
}
564
} catch (Exception ex) {
565
context.put("socket_info_error", ex.getMessage());
566
}
567
568
ExceptionHandler.ErrorSeverity severity = ExceptionHandler.classifyException(e);
569
context.put("error_severity", severity.toString());
570
571
// Log based on severity
572
switch (severity) {
573
case FATAL:
574
logger.error("Fatal socket error: {}", context, e);
575
break;
576
case PERMANENT:
577
logger.warn("Permanent socket error: {}", context, e);
578
break;
579
case TRANSIENT:
580
logger.info("Transient socket error: {}", context);
581
break;
582
case RECOVERABLE:
583
logger.debug("Recoverable socket error: {}", context);
584
break;
585
}
586
}
587
}
588
```