1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.unix;
17
18 import io.netty5.buffer.BufferUtil;
19 import io.netty5.buffer.api.Buffer;
20 import io.netty5.buffer.api.BufferAllocator;
21 import io.netty5.buffer.api.DefaultBufferAllocators;
22 import io.netty5.util.Resource;
23
24 import java.io.IOException;
25 import java.nio.ByteBuffer;
26 import java.nio.channels.WritableByteChannel;
27
28 import static java.util.Objects.requireNonNull;
29
30 public abstract class SocketWritableByteChannel implements WritableByteChannel {
31 private final FileDescriptor fd;
32
33 protected SocketWritableByteChannel(FileDescriptor fd) {
34 this.fd = requireNonNull(fd, "fd");
35 }
36
37 @Override
38 public final int write(ByteBuffer src) throws IOException {
39 final int written;
40 int position = src.position();
41 int limit = src.limit();
42 if (src.isDirect()) {
43 written = fd.write(src, position, src.limit());
44 } else {
45 final int readableBytes = limit - position;
46 final BufferAllocator alloc = alloc();
47 Buffer buffer = null;
48 boolean dispose = true;
49 try {
50 if (alloc.isPooling() && alloc.getAllocationType().isDirect()) {
51 buffer = alloc.allocate(readableBytes);
52 } else {
53 buffer = BufferUtil.threadLocalDirectBuffer();
54 if (buffer == null) {
55 buffer = DefaultBufferAllocators.offHeapAllocator().allocate(readableBytes);
56 } else {
57 dispose = false;
58 }
59 }
60 buffer.writeBytes(src.duplicate());
61 try (var iterator = buffer.forEachReadable()) {
62 var component = iterator.first();
63 ByteBuffer nioBuffer = component.readableBuffer();
64 written = fd.write(nioBuffer, nioBuffer.position(), nioBuffer.limit());
65 assert component.next() == null;
66 }
67 } catch (Throwable throwable) {
68 if (dispose) {
69 try {
70 Resource.dispose(buffer);
71 } catch (Exception e) {
72 throwable.addSuppressed(e);
73 }
74 }
75 throw throwable;
76 }
77 if (dispose) {
78 Resource.dispose(buffer);
79 }
80 }
81 if (written > 0) {
82 src.position(position + written);
83 }
84 return written;
85 }
86
87 @Override
88 public final boolean isOpen() {
89 return fd.isOpen();
90 }
91
92 @Override
93 public final void close() throws IOException {
94 fd.close();
95 }
96
97 protected abstract BufferAllocator alloc();
98 }