├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── org
│ └── xnio
│ └── netty
│ ├── buffer
│ ├── PooledByteBuf.java
│ ├── XnioByteBufAllocator.java
│ ├── XnioByteBufUtil.java
│ ├── XnioDirectByteBuf.java
│ ├── XnioHeapByteBuf.java
│ └── XnioUnsafeDirectByteBuf.java
│ └── transport
│ ├── AbstractXnioServerSocketChannel.java
│ ├── AbstractXnioSocketChannel.java
│ ├── IoThreadPowered.java
│ ├── WrappingXnioServerSocketChannel.java
│ ├── WrappingXnioSocketChannel.java
│ ├── XnioChannelCloseFuture.java
│ ├── XnioChannelOption.java
│ ├── XnioChannelPromiseCloseFuture.java
│ ├── XnioEventLoop.java
│ ├── XnioEventLoopGroup.java
│ ├── XnioServerSocketChannel.java
│ ├── XnioServerSocketChannelConfig.java
│ ├── XnioServerSocketChannelConfigImpl.java
│ ├── XnioSocketChannel.java
│ └── XnioSocketChannelConfig.java
└── test
└── java
└── org
└── xnio
└── netty
└── transport
├── XnioSocketEchoTest.java
├── XnioSocketFileRegionTest.java
├── XnioSocketFixedLengthEchoTest.java
├── XnioSocketGatheringWriteTest.java
├── XnioSocketObjectEchoTest.java
├── XnioSocketSslEchoTest.java
├── XnioSocketStartTlsTest.java
├── XnioSocketStringEchoTest.java
└── XnioTestsuiteUtils.java
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a Java project with Maven
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
3 |
4 | name: Netty XNIO Transport CI
5 |
6 | on:
7 | pull_request:
8 | types: [opened, synchronize, reopened, ready_for_review]
9 |
10 | jobs:
11 | build-test-matrix:
12 | name: ${{ matrix.jdk-distribution }}-${{ matrix.jdk-version }}-${{ matrix.os }}
13 | runs-on: ${{ matrix.os }}
14 | timeout-minutes: 10
15 | strategy:
16 | fail-fast: false
17 | matrix:
18 | os: [ubuntu-latest, windows-latest]
19 | jdk-distribution: [temurin]
20 | jdk-version: ['11', '17', '21']
21 | steps:
22 | - name: Configure runner - Linux
23 | if: contains(matrix.os, 'ubuntu')
24 | run: |
25 | sudo bash -c "echo '127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4' > /etc/hosts"
26 | sudo bash -c "echo '::1 localhost localhost.localdomain localhost6 localhost6.localdomain6' >> /etc/hosts"
27 | - name: Configure Runner - Windows
28 | if: contains(matrix.os, 'windows')
29 | run: |
30 | echo '127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4' > %SystemRoot%\System32\drivers\etc\hosts
31 | echo '::1 localhost localhost.localdomain localhost6 localhost6.localdomain6' >> %SystemRoot%\System32\drivers\etc\hosts
32 | shell: cmd
33 | - uses: actions/checkout@v3
34 | - name: Set up JDK ${{ matrix.jdk-distribution }} ${{ matrix.jdk-version }}
35 | uses: actions/setup-java@v3
36 | with:
37 | distribution: ${{ matrix.jdk-distribution }}
38 | java-version: ${{ matrix.jdk-version }}
39 | - name: Run Tests
40 | run: mvn -ntp -U -B -fae clean install
41 | - uses: actions/upload-artifact@v3
42 | if: failure()
43 | with:
44 | name: surefire-${{ matrix.jdk-distribution }}-${{ matrix.jdk-version }}-${{ matrix.os }}
45 | path: '**/surefire-reports/*.txt'
46 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .project
2 | .classpath
3 | .settings
4 | *.iml
5 | *.ipr
6 | *.iws
7 | .idea/
8 | .geany
9 | /target
10 | */target
11 | /reports
12 | */reports
13 | .DS_Store
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction, and
10 | distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by the copyright
13 | owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all other entities
16 | that control, are controlled by, or are under common control with that entity.
17 | For the purposes of this definition, "control" means (i) the power, direct or
18 | indirect, to cause the direction or management of such entity, whether by
19 | contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
20 | outstanding shares, or (iii) beneficial ownership of such entity.
21 |
22 | "You" (or "Your") shall mean an individual or Legal Entity exercising
23 | permissions granted by this License.
24 |
25 | "Source" form shall mean the preferred form for making modifications, including
26 | but not limited to software source code, documentation source, and configuration
27 | files.
28 |
29 | "Object" form shall mean any form resulting from mechanical transformation or
30 | translation of a Source form, including but not limited to compiled object code,
31 | generated documentation, and conversions to other media types.
32 |
33 | "Work" shall mean the work of authorship, whether in Source or Object form, made
34 | available under the License, as indicated by a copyright notice that is included
35 | in or attached to the work (an example is provided in the Appendix below).
36 |
37 | "Derivative Works" shall mean any work, whether in Source or Object form, that
38 | is based on (or derived from) the Work and for which the editorial revisions,
39 | annotations, elaborations, or other modifications represent, as a whole, an
40 | original work of authorship. For the purposes of this License, Derivative Works
41 | shall not include works that remain separable from, or merely link (or bind by
42 | name) to the interfaces of, the Work and Derivative Works thereof.
43 |
44 | "Contribution" shall mean any work of authorship, including the original version
45 | of the Work and any modifications or additions to that Work or Derivative Works
46 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
47 | by the copyright owner or by an individual or Legal Entity authorized to submit
48 | on behalf of the copyright owner. For the purposes of this definition,
49 | "submitted" means any form of electronic, verbal, or written communication sent
50 | to the Licensor or its representatives, including but not limited to
51 | communication on electronic mailing lists, source code control systems, and
52 | issue tracking systems that are managed by, or on behalf of, the Licensor for
53 | the purpose of discussing and improving the Work, but excluding communication
54 | that is conspicuously marked or otherwise designated in writing by the copyright
55 | owner as "Not a Contribution."
56 |
57 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf
58 | of whom a Contribution has been received by Licensor and subsequently
59 | incorporated within the Work.
60 |
61 | 2. Grant of Copyright License.
62 |
63 | Subject to the terms and conditions of this License, each Contributor hereby
64 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
65 | irrevocable copyright license to reproduce, prepare Derivative Works of,
66 | publicly display, publicly perform, sublicense, and distribute the Work and such
67 | Derivative Works in Source or Object form.
68 |
69 | 3. Grant of Patent License.
70 |
71 | Subject to the terms and conditions of this License, each Contributor hereby
72 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
73 | irrevocable (except as stated in this section) patent license to make, have
74 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
75 | such license applies only to those patent claims licensable by such Contributor
76 | that are necessarily infringed by their Contribution(s) alone or by combination
77 | of their Contribution(s) with the Work to which such Contribution(s) was
78 | submitted. If You institute patent litigation against any entity (including a
79 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
80 | Contribution incorporated within the Work constitutes direct or contributory
81 | patent infringement, then any patent licenses granted to You under this License
82 | for that Work shall terminate as of the date such litigation is filed.
83 |
84 | 4. Redistribution.
85 |
86 | You may reproduce and distribute copies of the Work or Derivative Works thereof
87 | in any medium, with or without modifications, and in Source or Object form,
88 | provided that You meet the following conditions:
89 |
90 | You must give any other recipients of the Work or Derivative Works a copy of
91 | this License; and
92 | You must cause any modified files to carry prominent notices stating that You
93 | changed the files; and
94 | You must retain, in the Source form of any Derivative Works that You distribute,
95 | all copyright, patent, trademark, and attribution notices from the Source form
96 | of the Work, excluding those notices that do not pertain to any part of the
97 | Derivative Works; and
98 | If the Work includes a "NOTICE" text file as part of its distribution, then any
99 | Derivative Works that You distribute must include a readable copy of the
100 | attribution notices contained within such NOTICE file, excluding those notices
101 | that do not pertain to any part of the Derivative Works, in at least one of the
102 | following places: within a NOTICE text file distributed as part of the
103 | Derivative Works; within the Source form or documentation, if provided along
104 | with the Derivative Works; or, within a display generated by the Derivative
105 | Works, if and wherever such third-party notices normally appear. The contents of
106 | the NOTICE file are for informational purposes only and do not modify the
107 | License. You may add Your own attribution notices within Derivative Works that
108 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
109 | provided that such additional attribution notices cannot be construed as
110 | modifying the License.
111 | You may add Your own copyright statement to Your modifications and may provide
112 | additional or different license terms and conditions for use, reproduction, or
113 | distribution of Your modifications, or for any such Derivative Works as a whole,
114 | provided Your use, reproduction, and distribution of the Work otherwise complies
115 | with the conditions stated in this License.
116 |
117 | 5. Submission of Contributions.
118 |
119 | Unless You explicitly state otherwise, any Contribution intentionally submitted
120 | for inclusion in the Work by You to the Licensor shall be under the terms and
121 | conditions of this License, without any additional terms or conditions.
122 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
123 | any separate license agreement you may have executed with Licensor regarding
124 | such Contributions.
125 |
126 | 6. Trademarks.
127 |
128 | This License does not grant permission to use the trade names, trademarks,
129 | service marks, or product names of the Licensor, except as required for
130 | reasonable and customary use in describing the origin of the Work and
131 | reproducing the content of the NOTICE file.
132 |
133 | 7. Disclaimer of Warranty.
134 |
135 | Unless required by applicable law or agreed to in writing, Licensor provides the
136 | Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
137 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
138 | including, without limitation, any warranties or conditions of TITLE,
139 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
140 | solely responsible for determining the appropriateness of using or
141 | redistributing the Work and assume any risks associated with Your exercise of
142 | permissions under this License.
143 |
144 | 8. Limitation of Liability.
145 |
146 | In no event and under no legal theory, whether in tort (including negligence),
147 | contract, or otherwise, unless required by applicable law (such as deliberate
148 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
149 | liable to You for damages, including any direct, indirect, special, incidental,
150 | or consequential damages of any character arising as a result of this License or
151 | out of the use or inability to use the Work (including but not limited to
152 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
153 | any and all other commercial damages or losses), even if such Contributor has
154 | been advised of the possibility of such damages.
155 |
156 | 9. Accepting Warranty or Additional Liability.
157 |
158 | While redistributing the Work or Derivative Works thereof, You may choose to
159 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
160 | other liability obligations and/or rights consistent with this License. However,
161 | in accepting such obligations, You may act only on Your own behalf and on Your
162 | sole responsibility, not on behalf of any other Contributor, and only if You
163 | agree to indemnify, defend, and hold each Contributor harmless for any liability
164 | incurred by, or claims asserted against, such Contributor by reason of your
165 | accepting any such warranty or additional liability.
166 |
167 | END OF TERMS AND CONDITIONS
168 |
169 | APPENDIX: How to apply the Apache License to your work
170 |
171 | To apply the Apache License to your work, attach the following boilerplate
172 | notice, with the fields enclosed by brackets "[]" replaced with your own
173 | identifying information. (Don't include the brackets!) The text should be
174 | enclosed in the appropriate comment syntax for the file format. We also
175 | recommend that a file or class name and description of purpose be included on
176 | the same "printed page" as the copyright notice for easier identification within
177 | third-party archives.
178 |
179 | Copyright [yyyy] [name of copyright owner]
180 |
181 | Licensed under the Apache License, Version 2.0 (the "License");
182 | you may not use this file except in compliance with the License.
183 | You may obtain a copy of the License at
184 |
185 | http://www.apache.org/licenses/LICENSE-2.0
186 |
187 | Unless required by applicable law or agreed to in writing, software
188 | distributed under the License is distributed on an "AS IS" BASIS,
189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
190 | See the License for the specific language governing permissions and
191 | limitations under the License.
192 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | netty-xnio-transport
2 | ====================
3 |
4 | This is a Netty Transport powered by XNIO. It can be used to either wrap an existing `StreamConnection` and `AcceptingChannel` or to bootstrap a Netty powered server directly.
5 |
6 | To bootstrap a server use it the same way as other transport implementations. The following code snipped shows an example:
7 |
8 | ```java
9 | public void run() throws Exception {
10 | // Configure the server.
11 | EventLoopGroup group = new XnioEventLoopGroup(4);
12 | try {
13 | ServerBootstrap b = new ServerBootstrap();
14 | b.group(group)
15 | .childHandler(new HelloServerInitializer())
16 |
17 | .channel(XnioServerSocketChannel.class)
18 | .option(XnioChannelOption.BALANCING_TOKENS, 1)
19 | .option(XnioChannelOption.BALANCING_CONNECTIONS, 2)
20 | .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
21 | Channel ch = b.bind(port).sync().channel();
22 | ch.closeFuture().sync();
23 | } finally {
24 | group.shutdownGracefully().sync();
25 | }
26 | }
27 | ```
28 |
29 | The branch 0.1.x is there to support Java 8.
30 |
31 |
32 | Releasing
33 | ============
34 |
35 | ```
36 | mvn release:prepare -Pjboss-release
37 | mvn release:perform -Pjboss-release
38 | ```
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 | org.jboss
23 | jboss-parent
24 | 42
25 |
26 |
27 | 4.0.0
28 | org.jboss.xnio.netty
29 | netty-xnio-transport
30 | netty-xnio-transport
31 | 0.2.0.Final-SNAPSHOT
32 | 2013
33 | jar
34 |
35 |
36 | JBoss, a division of Red Hat
37 | http://www.jboss.org/
38 |
39 |
40 |
41 |
42 | ASL 2.0
43 | http://www.apache.org/licenses/LICENSE-2.0.txt
44 | repo
45 |
46 |
47 |
48 |
49 | scm:git:git://github.com/xnio/netty-xnio-transport.git
50 | scm:git:https://github.com/xnio/netty-xnio-transport.git
51 | https://github.com/xnio/netty-xnio-transport
52 | HEAD
53 |
54 |
55 |
56 |
57 | jboss-releases-repository
58 | JBoss Releases Repository
59 | https://repository.jboss.org/nexus/service/local/staging/deploy/maven2/
60 |
61 |
62 | jboss-snapshots-repository
63 | JBoss Snapshots Repository
64 | https://repository.jboss.org/nexus/content/repositories/snapshots/
65 |
66 |
67 |
68 |
69 | 3.9.6
70 |
71 |
72 |
73 |
74 |
75 | org.apache.maven.plugins
76 | maven-compiler-plugin
77 |
78 | true
79 | ${target.jdk}
80 | ${target.jdk}
81 |
82 |
83 |
84 | org.apache.maven.plugins
85 | maven-surefire-plugin
86 |
87 | --add-opens java.base/jdk.internal.misc=ALL-UNNAMED -Dio.netty.tryReflectionSetAccessible=true
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | io.netty
96 | netty-transport
97 | ${netty.version}
98 |
99 |
100 | io.netty
101 | netty-buffer
102 | ${netty.version}
103 |
104 |
105 | org.jboss.xnio
106 | xnio-api
107 | ${xnio.version}
108 |
109 |
110 | io.netty
111 | netty-testsuite
112 | ${netty.version}
113 |
114 | test
115 |
116 |
117 |
118 | org.junit.jupiter
119 | junit-jupiter-api
120 | ${junit.version}
121 | test
122 |
123 |
124 | org.junit.jupiter
125 | junit-jupiter-engine
126 | ${junit.version}
127 | test
128 |
129 |
130 | org.junit.jupiter
131 | junit-jupiter-params
132 | ${junit.version}
133 | test
134 |
135 |
136 | org.jboss.xnio
137 | xnio-nio
138 | ${xnio.version}
139 | test
140 |
141 |
142 | org.jboss.logging
143 | jboss-logging
144 | ${jboss.logging.version}
145 | test
146 |
147 |
148 | org.bouncycastle
149 | bcpkix-jdk15on
150 | ${org.bouncycastle.version}
151 | test
152 |
153 |
154 |
155 |
156 | ${maven.compiler.target}
157 | 11
158 | 4.1.104.Final
159 | 3.8.12.Final
160 | 3.5.3.Final
161 | 5.10.1
162 | 1.70
163 |
164 |
165 |
166 |
167 | jboss-public-repository-group
168 | JBoss Public Repository Group
169 | https://repository.jboss.org/nexus/content/groups/public/
170 | default
171 |
172 | true
173 | never
174 |
175 |
176 | true
177 | never
178 |
179 |
180 |
181 |
182 |
183 |
184 | jboss-public-repository-group
185 | JBoss Public Repository Group
186 | https://repository.jboss.org/nexus/content/groups/public/
187 |
188 | true
189 |
190 |
191 | true
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/PooledByteBuf.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.util.internal.PlatformDependent;
20 | import org.xnio.Pooled;
21 |
22 | import java.nio.ByteBuffer;
23 |
24 | /**
25 | * @author Norman Maurer
26 | */
27 | final class PooledByteBuf implements Pooled {
28 | private final ByteBuffer buffer;
29 |
30 | PooledByteBuf(ByteBuffer buffer) {
31 | this.buffer = buffer;
32 | }
33 |
34 | @Override
35 | public void discard() {
36 | // NOOP
37 | }
38 |
39 | @Override
40 | public void free() {
41 | PlatformDependent.freeDirectBuffer(buffer);
42 | }
43 |
44 | @Override
45 | public ByteBuffer getResource() throws IllegalStateException {
46 | return buffer;
47 | }
48 |
49 | @Override
50 | public void close() {
51 | free();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/XnioByteBufAllocator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.buffer.AbstractByteBufAllocator;
20 | import io.netty.buffer.ByteBuf;
21 | import io.netty.util.internal.PlatformDependent;
22 | import org.xnio.ByteBufferPool;
23 | import org.xnio.ByteBufferSlicePool;
24 |
25 | /**
26 | * {@link io.netty.buffer.ByteBufAllocator} which wraps an existing {@link ByteBufferSlicePool} and use it to allocate direct
27 | * {@link ByteBuf}. If the requested {@link ByteBuf} is to big it will be allocated directly and not pooled at all.
28 | *
29 | * @author Norman Maurer
30 | */
31 | public final class XnioByteBufAllocator extends AbstractByteBufAllocator {
32 | final ByteBufferPool pool;
33 |
34 | public XnioByteBufAllocator(ByteBufferPool pool) {
35 | if (pool == null) {
36 | throw new NullPointerException("pool");
37 | }
38 | this.pool = pool;
39 | }
40 |
41 | @Override
42 | protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
43 | return new XnioHeapByteBuf(this, initialCapacity, maxCapacity);
44 | }
45 |
46 | @Override
47 | protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
48 | if (PlatformDependent.hasUnsafe()) {
49 | return new XnioUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
50 | }
51 | return new XnioDirectByteBuf(this, initialCapacity, maxCapacity);
52 | }
53 |
54 | @Override
55 | public boolean isDirectBufferPooled() {
56 | return true;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/XnioByteBufUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.util.internal.PlatformDependent;
20 | import org.xnio.Pooled;
21 |
22 | import java.nio.ByteBuffer;
23 | import org.xnio.ByteBufferPool;
24 |
25 | /**
26 | * @author Norman Maurer
27 | */
28 | final class XnioByteBufUtil {
29 |
30 | private XnioByteBufUtil() {
31 | // Utility
32 | }
33 |
34 | static Pooled allocateDirect(ByteBufferPool pool, int initialCapacity) {
35 | Pooled pooled;
36 | if (initialCapacity <= pool.getSize()) {
37 | pooled = new PooledByteBuf(pool.allocate());
38 | } else {
39 | pooled = new PooledByteBuf(ByteBuffer.allocateDirect(initialCapacity));
40 | }
41 | return pooled;
42 | }
43 |
44 | static void freeDirect(ByteBuffer buffer, ByteBuffer newBuffer) {
45 | if (buffer != newBuffer) {
46 | PlatformDependent.freeDirectBuffer(buffer);
47 | }
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/XnioDirectByteBuf.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.buffer.ByteBuf;
20 | import io.netty.buffer.ByteBufAllocator;
21 | import io.netty.buffer.UnpooledDirectByteBuf;
22 | import org.xnio.Pooled;
23 |
24 | import java.nio.ByteBuffer;
25 |
26 | /**
27 | * @author Norman Maurer
28 | */
29 | final class XnioDirectByteBuf extends UnpooledDirectByteBuf {
30 | private Pooled pooled;
31 |
32 | XnioDirectByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
33 | super(alloc, initialCapacity, maxCapacity);
34 | }
35 |
36 | @Override
37 | public ByteBuf capacity(int newCapacity) {
38 | ensureAccessible();
39 | if (newCapacity < 0 || newCapacity > maxCapacity()) {
40 | throw new IllegalArgumentException("newCapacity: " + newCapacity);
41 | }
42 | Pooled oldPooled = this.pooled;
43 | super.capacity(newCapacity);
44 | if (oldPooled != pooled) {
45 | oldPooled.free();
46 | }
47 | return this;
48 | }
49 |
50 | @Override
51 | protected ByteBuffer allocateDirect(int initialCapacity) {
52 | Pooled pooled = XnioByteBufUtil.allocateDirect(
53 | ((XnioByteBufAllocator) alloc()).pool, initialCapacity);
54 | this.pooled = pooled;
55 | return pooled.getResource();
56 | }
57 |
58 | @Override
59 | protected void freeDirect(ByteBuffer buffer) {
60 | XnioByteBufUtil.freeDirect(buffer, pooled.getResource());
61 | }
62 |
63 | @Override
64 | protected void deallocate() {
65 | super.deallocate();
66 | pooled.free();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/XnioHeapByteBuf.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.buffer.ByteBufAllocator;
20 | import io.netty.buffer.UnpooledHeapByteBuf;
21 |
22 |
23 | /**
24 | * @author Norman Maurer
25 | */
26 | final class XnioHeapByteBuf extends UnpooledHeapByteBuf {
27 | XnioHeapByteBuf(ByteBufAllocator alloc, int initialCapacity, int maxCapacity) {
28 | super(alloc, initialCapacity, maxCapacity);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/buffer/XnioUnsafeDirectByteBuf.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.buffer;
18 |
19 | import io.netty.buffer.ByteBuf;
20 | import io.netty.buffer.UnpooledUnsafeDirectByteBuf;
21 | import org.xnio.Pooled;
22 |
23 | import java.nio.ByteBuffer;
24 |
25 | /**
26 | * @author Norman Maurer
27 | */
28 | final class XnioUnsafeDirectByteBuf extends UnpooledUnsafeDirectByteBuf {
29 |
30 | private Pooled pooled;
31 |
32 | XnioUnsafeDirectByteBuf(XnioByteBufAllocator alloc, int initialSize, int maxCapacity) {
33 | super(alloc, initialSize, maxCapacity);
34 | }
35 |
36 | @Override
37 | public ByteBuf capacity(int newCapacity) {
38 | ensureAccessible();
39 | if (newCapacity < 0 || newCapacity > maxCapacity()) {
40 | throw new IllegalArgumentException("newCapacity: " + newCapacity);
41 | }
42 | Pooled oldPooled = this.pooled;
43 | super.capacity(newCapacity);
44 | if (oldPooled != pooled) {
45 | oldPooled.free();
46 | }
47 | return this;
48 | }
49 |
50 | @Override
51 | protected ByteBuffer allocateDirect(int initialCapacity) {
52 | Pooled pooled = XnioByteBufUtil.allocateDirect(
53 | ((XnioByteBufAllocator) alloc()).pool, initialCapacity);
54 | this.pooled = pooled;
55 | return pooled.getResource();
56 | }
57 |
58 | @Override
59 | protected void freeDirect(ByteBuffer buffer) {
60 | XnioByteBufUtil.freeDirect(buffer, pooled.getResource());
61 | }
62 |
63 | @Override
64 | protected void deallocate() {
65 | super.deallocate();
66 | pooled.free();
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/AbstractXnioServerSocketChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import io.netty.channel.AbstractServerChannel;
20 | import io.netty.channel.ChannelException;
21 | import io.netty.channel.EventLoop;
22 | import io.netty.channel.socket.ServerSocketChannel;
23 | import org.xnio.ChannelListener;
24 | import org.xnio.Option;
25 | import org.xnio.StreamConnection;
26 | import org.xnio.channels.AcceptingChannel;
27 |
28 | import java.io.IOException;
29 | import java.net.InetSocketAddress;
30 | import java.net.SocketAddress;
31 |
32 |
33 | /**
34 | * {@link ServerSocketChannel} base class for our XNIO transport
35 | *
36 | * @author Norman Maurer
37 | */
38 | abstract class AbstractXnioServerSocketChannel extends AbstractServerChannel implements ServerSocketChannel {
39 | private final XnioServerSocketChannelConfigImpl config = new XnioServerSocketChannelConfigImpl(this);
40 | private static final ThreadLocal connections = new ThreadLocal();
41 |
42 | private static StreamConnection[] connectionsArray(int size) {
43 | StreamConnection[] array = connections.get();
44 | if (array == null || array.length < size) {
45 | array = new StreamConnection[size];
46 | connections.set(array);
47 | }
48 | return array;
49 | }
50 |
51 | @Override
52 | protected boolean isCompatible(EventLoop loop) {
53 | return loop instanceof XnioEventLoop;
54 | }
55 |
56 | @Override
57 | public boolean isActive() {
58 | return isOpen();
59 | }
60 |
61 | @Override
62 | public InetSocketAddress localAddress() {
63 | return (InetSocketAddress) super.localAddress();
64 | }
65 |
66 | @Override
67 | public InetSocketAddress remoteAddress() {
68 | return (InetSocketAddress) super.remoteAddress();
69 | }
70 |
71 | @Override
72 | public XnioServerSocketChannelConfigImpl config() {
73 | return config;
74 | }
75 |
76 | T getOption(Option option) {
77 | try {
78 | return getOption0(option);
79 | } catch (IOException e) {
80 | throw new ChannelException(e);
81 | }
82 | }
83 |
84 | void setOption(Option option, T value) {
85 | try {
86 | setOption0(option, value);
87 | } catch (IOException e) {
88 | throw new ChannelException(e);
89 | }
90 | }
91 |
92 |
93 | @Override
94 | protected SocketAddress localAddress0() {
95 | AcceptingChannel channel = xnioChannel();
96 | if (channel == null) {
97 | return null;
98 | }
99 | return channel.getLocalAddress();
100 | }
101 |
102 | @Override
103 | protected void doClose() throws Exception {
104 | AcceptingChannel channel = xnioChannel();
105 | if (channel == null) {
106 | return;
107 | }
108 | channel.suspendAccepts();
109 | channel.close();
110 | }
111 |
112 | @Override
113 | protected void doBeginRead() throws Exception {
114 | AcceptingChannel channel = xnioChannel();
115 | if (channel == null) {
116 | return;
117 | }
118 | channel.resumeAccepts();
119 | }
120 |
121 | @Override
122 | public boolean isOpen() {
123 | AcceptingChannel channel = xnioChannel();
124 | return channel == null || channel.isOpen();
125 | }
126 |
127 | /**
128 | * Return the underyling {@link AcceptingChannel}
129 | */
130 | protected abstract AcceptingChannel xnioChannel();
131 |
132 | /**
133 | * Set the given {@link Option} to the given value.
134 | */
135 | protected abstract void setOption0(Option option, T value) throws IOException;
136 |
137 | /**
138 | * Return the value for the given {@link Option}.
139 | */
140 | protected abstract T getOption0(Option option) throws IOException;
141 |
142 | /**
143 | * {@link ChannelListener} implementation which takes care of accept connections and fire them through the
144 | * {@link io.netty.channel.ChannelPipeline}.
145 | */
146 | final class AcceptListener implements ChannelListener> {
147 |
148 | @Override
149 | public void handleEvent(final AcceptingChannel channel) {
150 | if (!config.isAutoRead()) {
151 | channel.suspendAccepts();
152 | }
153 | EventLoop loop = eventLoop();
154 | if (loop.inEventLoop()) {
155 | try {
156 | int messagesToRead = config().getMaxMessagesPerRead();
157 | for (int i = 0; i < messagesToRead; i++) {
158 | StreamConnection conn = channel.accept();
159 | if (conn == null) {
160 | break;
161 | }
162 | pipeline().fireChannelRead(new WrappingXnioSocketChannel(AbstractXnioServerSocketChannel.this, conn));
163 | }
164 | } catch (Throwable cause) {
165 | pipeline().fireExceptionCaught(cause);
166 | }
167 | pipeline().fireChannelReadComplete();
168 | } else {
169 | Throwable cause;
170 | int messagesToRead = config().getMaxMessagesPerRead();
171 | final StreamConnection[] array = connectionsArray(messagesToRead);
172 | try {
173 | for (int i = 0; i < messagesToRead; i++) {
174 | StreamConnection conn = channel.accept();
175 | array[i] = conn;
176 | if (conn == null) {
177 | break;
178 | }
179 | }
180 | cause = null;
181 | } catch (Throwable e) {
182 | cause = e;
183 | }
184 | final Throwable acceptError = cause;
185 |
186 | eventLoop().execute( new Runnable() {
187 |
188 | @Override
189 | public void run() {
190 | try {
191 | for (int i = 0; i < array.length; i++) {
192 | StreamConnection conn = array[i];
193 | if (conn == null) {
194 | break;
195 | }
196 | pipeline().fireChannelRead(new WrappingXnioSocketChannel(AbstractXnioServerSocketChannel.this, conn));
197 | }
198 | } catch (Throwable cause) {
199 | pipeline().fireExceptionCaught(cause);
200 | }
201 | if (acceptError != null) {
202 | pipeline().fireExceptionCaught(acceptError);
203 | }
204 | pipeline().fireChannelReadComplete();
205 | }
206 | });
207 | }
208 |
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/AbstractXnioSocketChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import java.io.IOException;
20 | import java.net.InetSocketAddress;
21 | import java.net.SocketAddress;
22 | import java.nio.ByteBuffer;
23 | import java.nio.channels.GatheringByteChannel;
24 | import java.util.concurrent.ExecutionException;
25 | import java.util.concurrent.TimeUnit;
26 | import java.util.concurrent.TimeoutException;
27 |
28 | import org.xnio.ChannelListener;
29 | import org.xnio.Option;
30 | import org.xnio.StreamConnection;
31 | import org.xnio.conduits.ConduitStreamSinkChannel;
32 | import org.xnio.conduits.ConduitStreamSourceChannel;
33 |
34 | import io.netty.buffer.ByteBuf;
35 | import io.netty.buffer.ByteBufAllocator;
36 | import io.netty.channel.AbstractChannel;
37 | import io.netty.channel.Channel;
38 | import io.netty.channel.ChannelConfig;
39 | import io.netty.channel.ChannelException;
40 | import io.netty.channel.ChannelFuture;
41 | import io.netty.channel.ChannelMetadata;
42 | import io.netty.channel.ChannelOutboundBuffer;
43 | import io.netty.channel.ChannelPipeline;
44 | import io.netty.channel.ChannelPromise;
45 | import io.netty.channel.EventLoop;
46 | import io.netty.channel.FileRegion;
47 | import io.netty.channel.RecvByteBufAllocator;
48 | import io.netty.channel.socket.ServerSocketChannel;
49 | import io.netty.channel.socket.SocketChannel;
50 | import io.netty.channel.socket.SocketChannelConfig;
51 | import io.netty.util.IllegalReferenceCountException;
52 | import io.netty.util.concurrent.Future;
53 | import io.netty.util.concurrent.GenericFutureListener;
54 | import io.netty.util.internal.StringUtil;
55 |
56 |
57 | /**
58 | * {@link SocketChannel} base class for our XNIO transport
59 | *
60 | * @author Norman Maurer
61 | * @author Flavia Rainone
62 | */
63 | abstract class AbstractXnioSocketChannel extends AbstractChannel implements SocketChannel {
64 |
65 | private static final ChannelMetadata META_DATA = new ChannelMetadata(false);
66 | private final XnioSocketChannelConfig config = new XnioSocketChannelConfig(this);
67 |
68 | private Runnable flushTask;
69 | private ChannelListener writeListener;
70 | private volatile boolean closed;
71 |
72 | AbstractXnioSocketChannel(AbstractXnioServerSocketChannel parent) {
73 | super(parent);
74 | }
75 |
76 | @Override
77 | public ServerSocketChannel parent() {
78 | return (ServerSocketChannel) super.parent();
79 | }
80 |
81 | public InetSocketAddress remoteAddress() {
82 | return (InetSocketAddress) super.remoteAddress();
83 | }
84 |
85 | @Override
86 | public InetSocketAddress localAddress() {
87 | return (InetSocketAddress) super.localAddress();
88 | }
89 |
90 | @Override
91 | protected abstract AbstractXnioUnsafe newUnsafe();
92 |
93 | @Override
94 | protected boolean isCompatible(EventLoop loop) {
95 | if (!(loop instanceof XnioEventLoop)) {
96 | return false;
97 | }
98 | ServerSocketChannel parent = parent();
99 | if (parent != null) {
100 | // if this channel has a parent we need to ensure that both EventLoopGroups are the same for XNIO
101 | // to be sure it uses a Thread from the correct Worker.
102 | if (parent.eventLoop().parent() != loop.parent()) {
103 | return false;
104 | }
105 | }
106 | return true;
107 | }
108 |
109 | @Override
110 | protected void doDisconnect() throws Exception {
111 | doClose();
112 | }
113 |
114 |
115 |
116 | private void incompleteWrite(boolean setOpWrite) {
117 | // Did not write completely.
118 | if (setOpWrite) {
119 | setOpWrite();
120 | } else {
121 | // Schedule flush again later so other tasks can be picked up in the meantime
122 | Runnable flushTask = this.flushTask;
123 | if (flushTask == null) {
124 | flushTask = this.flushTask = new Runnable() {
125 | @Override
126 | public void run() {
127 | flush();
128 | }
129 | };
130 | }
131 | eventLoop().execute(flushTask);
132 | }
133 | }
134 |
135 | private void setOpWrite() {
136 | ConduitStreamSinkChannel sink = connection().getSinkChannel();
137 | if (!sink.isWriteResumed()) {
138 | ChannelListener writeListener = this.writeListener;
139 | if (writeListener == null) {
140 | writeListener = this.writeListener = new WriteListener();
141 | }
142 | sink.getWriteSetter().set(writeListener);
143 | sink.resumeWrites();
144 | }
145 | }
146 |
147 |
148 | @Override
149 | protected void doWrite(ChannelOutboundBuffer in) throws Exception {
150 | int writeSpinCount = -1;
151 |
152 | GatheringByteChannel sink = connection().getSinkChannel();
153 | for (;;) {
154 | // Do gathering write for a non-single buffer case.
155 | final int msgCount = in.size();
156 | if (msgCount > 0) {
157 | // Ensure the pending writes are made of ByteBufs only.
158 | ByteBuffer[] nioBuffers = in.nioBuffers();
159 | if (nioBuffers != null) {
160 |
161 | int nioBufferCnt = in.nioBufferCount();
162 | long expectedWrittenBytes = in.nioBufferSize();
163 | if(nioBufferCnt > 0) {
164 |
165 | long writtenBytes = 0;
166 | boolean done = false;
167 | boolean setOpWrite = false;
168 | for (int i = config().getWriteSpinCount() - 1; i >= 0; i--) {
169 | final long localWrittenBytes = sink.write(nioBuffers, 0, nioBufferCnt);
170 | if (localWrittenBytes == 0) {
171 | setOpWrite = true;
172 | break;
173 | }
174 | expectedWrittenBytes -= localWrittenBytes;
175 | writtenBytes += localWrittenBytes;
176 | if (expectedWrittenBytes == 0) {
177 | done = true;
178 | break;
179 | }
180 | }
181 |
182 | if (done) {
183 | // Release all buffers
184 | for (int i = msgCount; i > 0; i--) {
185 | in.remove();
186 | }
187 |
188 | // Finish the write loop if no new messages were flushed by in.remove().
189 | if (in.isEmpty()) {
190 | connection().getSinkChannel().suspendWrites();
191 | break;
192 | }
193 | } else {
194 | // Did not write all buffers completely.
195 | // Release the fully written buffers and update the indexes of the partially written buffer.
196 |
197 | for (int i = msgCount; i > 0; i--) {
198 | final ByteBuf buf = (ByteBuf) in.current();
199 | final int readerIndex = buf.readerIndex();
200 | final int readableBytes = buf.writerIndex() - readerIndex;
201 |
202 | if (readableBytes < writtenBytes) {
203 | in.progress(readableBytes);
204 | in.remove();
205 | writtenBytes -= readableBytes;
206 | } else if (readableBytes > writtenBytes) {
207 | buf.readerIndex(readerIndex + (int) writtenBytes);
208 | in.progress(writtenBytes);
209 | break;
210 | } else { // readableBytes == writtenBytes
211 | in.progress(readableBytes);
212 | in.remove();
213 | break;
214 | }
215 | }
216 |
217 | incompleteWrite(setOpWrite);
218 | }
219 | }
220 | }
221 | }
222 | Object msg = in.current();
223 | if (msg == null) {
224 | // Wrote all messages.
225 | connection().getSinkChannel().suspendWrites();
226 | break;
227 | }
228 |
229 | if (msg instanceof ByteBuf) {
230 | ByteBuf buf = (ByteBuf) msg;
231 | int readableBytes = buf.readableBytes();
232 | if (readableBytes == 0) {
233 | in.remove();
234 | continue;
235 | }
236 |
237 | // code corresponding to previous if (!buf.isDirect()) { ... }
238 | // has been removed in corresponding Netty's AbstractNioByteChannel
239 | // in https://github.com/netty/netty/pull/2242
240 |
241 | boolean setOpWrite = false;
242 | boolean done = false;
243 | long flushedAmount = 0;
244 | if (writeSpinCount == -1) {
245 | writeSpinCount = config().getWriteSpinCount();
246 | }
247 | for (int i = writeSpinCount - 1; i >= 0; i --) {
248 | int localFlushedAmount = buf.readBytes(sink, buf.readableBytes());
249 | if (localFlushedAmount == 0) {
250 | setOpWrite = true;
251 | break;
252 | }
253 |
254 | flushedAmount += localFlushedAmount;
255 | if (!buf.isReadable()) {
256 | done = true;
257 | break;
258 | }
259 | }
260 |
261 | in.progress(flushedAmount);
262 |
263 | if (done) {
264 | in.remove();
265 | } else {
266 | incompleteWrite(setOpWrite);
267 | break;
268 | }
269 | } else if (msg instanceof FileRegion) {
270 | FileRegion region = (FileRegion) msg;
271 | boolean setOpWrite = false;
272 | boolean done = false;
273 | long flushedAmount = 0;
274 | if (writeSpinCount == -1) {
275 | writeSpinCount = config().getWriteSpinCount();
276 | }
277 | for (int i = writeSpinCount - 1; i >= 0; i --) {
278 | long localFlushedAmount = region.transferTo(sink, region.transferred());
279 | if (localFlushedAmount == 0) {
280 | setOpWrite = true;
281 | break;
282 | }
283 |
284 | flushedAmount += localFlushedAmount;
285 | if (region.transferred() >= region.count()) {
286 | done = true;
287 | break;
288 | }
289 | }
290 |
291 | in.progress(flushedAmount);
292 |
293 | if (done) {
294 | in.remove();
295 | } else {
296 | incompleteWrite(setOpWrite);
297 | break;
298 | }
299 | } else {
300 | throw new UnsupportedOperationException("unsupported message type: " + StringUtil.simpleClassName(msg));
301 | }
302 | }
303 | }
304 |
305 | @Override
306 | public SocketChannelConfig config() {
307 | return config;
308 | }
309 |
310 | @Override
311 | public ChannelFuture shutdownOutput() {
312 | return newFailedFuture(new UnsupportedOperationException());
313 | }
314 |
315 | @Override
316 | public ChannelFuture shutdownOutput(ChannelPromise future) {
317 | return newFailedFuture(new UnsupportedOperationException());
318 | }
319 |
320 | @Override
321 | public boolean isOpen() {
322 | StreamConnection conn = connection();
323 | return (conn == null || conn.isOpen()) && !closed;
324 | }
325 |
326 | @Override
327 | public boolean isActive() {
328 | StreamConnection conn = connection();
329 | return conn != null && conn.isOpen() && !closed;
330 | }
331 |
332 | @Override
333 | public ChannelMetadata metadata() {
334 | return META_DATA;
335 | }
336 |
337 | @Override
338 | protected SocketAddress localAddress0() {
339 | StreamConnection conn = connection();
340 | if (conn == null) {
341 | return null;
342 | }
343 | return conn.getLocalAddress();
344 | }
345 |
346 | @Override
347 | protected SocketAddress remoteAddress0() {
348 | StreamConnection conn = connection();
349 | if (conn == null) {
350 | return null;
351 | }
352 | return conn.getPeerAddress();
353 | }
354 |
355 | protected abstract class AbstractXnioUnsafe extends AbstractUnsafe {
356 | private boolean readPending = false;
357 |
358 | public void beginRead0() {
359 | readPending = true;
360 | }
361 |
362 | @Override
363 | protected void flush0() {
364 | // Flush immediately only when there's no pending flush.
365 | // If there's a pending flush operation, event loop will call forceFlush() later,
366 | // and thus there's no need to call it now.
367 | if (connection().getSinkChannel().isWriteResumed()) {
368 | return;
369 | }
370 | super.flush0();
371 | }
372 |
373 | public void forceFlush() {
374 | super.flush0();
375 | }
376 | }
377 |
378 | final class ReadListener implements ChannelListener {
379 | private RecvByteBufAllocator.Handle allocHandle;
380 |
381 | private void removeReadOp(ConduitStreamSourceChannel channel) {
382 | if (channel.isReadResumed()) {
383 | channel.suspendReads();
384 | }
385 | }
386 |
387 | private void closeOnRead() {
388 | StreamConnection connection = connection();
389 | suspend(connection);
390 | if (isOpen()) {
391 | unsafe().close(unsafe().voidPromise());
392 | }
393 | }
394 |
395 | private void handleReadException(ChannelPipeline pipeline, ByteBuf byteBuf, Throwable cause, boolean close) {
396 | if (byteBuf != null) {
397 | if (byteBuf.isReadable()) {
398 | pipeline.fireChannelRead(byteBuf);
399 | } else {
400 | try {
401 | byteBuf.release();
402 | } catch (IllegalReferenceCountException ignore) {
403 | // ignore as it may be released already
404 | }
405 | }
406 | }
407 | pipeline.fireChannelReadComplete();
408 | pipeline.fireExceptionCaught(cause);
409 | if (close || cause instanceof IOException) {
410 | closeOnRead();
411 | }
412 | }
413 |
414 | @Override
415 | public void handleEvent(ConduitStreamSourceChannel channel) {
416 | final ChannelConfig config = config();
417 | final ChannelPipeline pipeline = pipeline();
418 | final ByteBufAllocator allocator = config.getAllocator();
419 | final int maxMessagesPerRead = config.getMaxMessagesPerRead();
420 | RecvByteBufAllocator.Handle allocHandle = this.allocHandle;
421 | if (allocHandle == null) {
422 | this.allocHandle = allocHandle = config.getRecvByteBufAllocator().newHandle();
423 | this.allocHandle.reset(config);
424 | }
425 |
426 | ByteBuf byteBuf = null;
427 | int messages = 0;
428 | boolean close = false;
429 | try {
430 | int byteBufCapacity = allocHandle.guess();
431 | int totalReadAmount = 0;
432 | do {
433 | byteBuf = allocator.ioBuffer(byteBufCapacity);
434 | int writable = byteBuf.writableBytes();
435 | int localReadAmount = byteBuf.writeBytes(channel, byteBuf.writableBytes());
436 | if (localReadAmount <= 0) {
437 | // nothing was read release the buffer
438 | byteBuf.release();
439 | close = localReadAmount < 0;
440 | break;
441 | }
442 | ((AbstractXnioUnsafe) unsafe()).readPending = false;
443 | pipeline.fireChannelRead(byteBuf);
444 | byteBuf = null;
445 |
446 | if (totalReadAmount >= Integer.MAX_VALUE - localReadAmount) {
447 | // Avoid overflow.
448 | totalReadAmount = Integer.MAX_VALUE;
449 | break;
450 | }
451 |
452 | totalReadAmount += localReadAmount;
453 |
454 | // stop reading
455 | if (!config.isAutoRead()) {
456 | break;
457 | }
458 |
459 | if (localReadAmount < writable) {
460 | // Read less than what the buffer can hold,
461 | // which might mean we drained the recv buffer completely.
462 | break;
463 | }
464 | } while (++ messages < maxMessagesPerRead && allocHandle.continueReading());
465 |
466 | allocHandle.incMessagesRead(messages);
467 | allocHandle.lastBytesRead(totalReadAmount);
468 | allocHandle.readComplete();
469 |
470 | pipeline.fireChannelReadComplete();
471 |
472 | if (close) {
473 | closeOnRead();
474 | close = false;
475 | }
476 | } catch (Throwable t) {
477 | handleReadException(pipeline, byteBuf, t, close);
478 | } finally {
479 | // Check if there is a readPending which was not processed yet.
480 | // This could be for two reasons:
481 | // * The user called Channel.read() or ChannelHandlerContext.read() in channelRead(...) method
482 | // * The user called Channel.read() or ChannelHandlerContext.read() in channelReadComplete(...) method
483 | //
484 | // See https://github.com/netty/netty/issues/2254
485 | if (!config.isAutoRead() && !((AbstractXnioUnsafe) unsafe()).readPending) {
486 | removeReadOp(channel);
487 | }
488 | }
489 | }
490 | }
491 |
492 | private class WriteListener implements ChannelListener {
493 | @Override
494 | public void handleEvent(ConduitStreamSinkChannel channel) {
495 | ((AbstractXnioUnsafe)unsafe()).forceFlush();
496 | }
497 | }
498 |
499 | @Override
500 | public boolean isInputShutdown() {
501 | StreamConnection conn = connection();
502 | return conn == null || conn.isReadShutdown();
503 | }
504 |
505 | @Override
506 | public boolean isOutputShutdown() {
507 | StreamConnection conn = connection();
508 | return conn == null || conn.isWriteShutdown();
509 | }
510 |
511 | @Override
512 | protected void doBeginRead() throws Exception {
513 | StreamConnection conn = connection();
514 | if (conn == null) {
515 | return;
516 | }
517 | ((AbstractXnioUnsafe)unsafe()).beginRead0();
518 | ConduitStreamSourceChannel source = conn.getSourceChannel();
519 | if (!source.isReadResumed()) {
520 | source.resumeReads();
521 | }
522 | }
523 |
524 | @Override
525 | protected void doClose() throws Exception {
526 | closed = true;
527 | StreamConnection conn = connection();
528 | if (conn != null) {
529 | suspend(conn);
530 | conn.close();
531 | }
532 | }
533 |
534 | T getOption(Option option) {
535 | try {
536 | return getOption0(option);
537 | } catch (IOException e) {
538 | throw new ChannelException(e);
539 | }
540 | }
541 |
542 | void setOption(Option option, T value) {
543 | try {
544 | setOption0(option, value);
545 | } catch (IOException e) {
546 | throw new ChannelException(e);
547 | }
548 | }
549 | private static void suspend(StreamConnection connection) {
550 | if (connection == null) {
551 | return;
552 | }
553 | connection.getSourceChannel().suspendReads();
554 | connection.getSinkChannel().suspendWrites();
555 | }
556 |
557 | /**
558 | * Set the given {@link Option} to the given value.
559 | */
560 | protected abstract void setOption0(Option option, T value) throws IOException;
561 |
562 |
563 | /**
564 | * Return the value for the given {@link Option}.
565 | */
566 | protected abstract T getOption0(Option option) throws IOException;
567 |
568 | /**
569 | * Returns the underlying {@link StreamConnection} or {@code null} if not created yet.
570 | */
571 | protected abstract StreamConnection connection();
572 |
573 | @Override
574 | public boolean isShutdown() {
575 | return isInputShutdown() && isOutputShutdown();
576 | }
577 |
578 | @Override
579 | public ChannelFuture shutdown() {
580 | final ChannelFuture inputFuture = shutdownInput();
581 | final ChannelFuture outputFuture = shutdownOutput();
582 | return getShutdownChannelFuture(inputFuture, outputFuture);
583 | }
584 |
585 | @Override
586 | public ChannelFuture shutdown(ChannelPromise channelPromise) {
587 | final ChannelFuture inputFuture = shutdownInput(channelPromise);
588 | final ChannelFuture outputFuture = shutdownOutput(channelPromise);
589 | return getShutdownChannelFuture(inputFuture, outputFuture);
590 | }
591 |
592 | private ChannelFuture getShutdownChannelFuture(final ChannelFuture inputFuture, final ChannelFuture outputFuture) {
593 | return new ChannelFuture() {
594 |
595 | @Override
596 | public boolean isSuccess() {
597 | return inputFuture.isSuccess() && outputFuture.isSuccess();
598 | }
599 |
600 | @Override
601 | public boolean isCancellable() {
602 | return inputFuture.isCancellable() && outputFuture.isCancellable();
603 | }
604 |
605 | @Override
606 | public Throwable cause() {
607 | return inputFuture.cause() != null? inputFuture.cause(): outputFuture.cause();
608 | }
609 |
610 | @Override
611 | public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
612 | long currentTimeMillis = System.currentTimeMillis();
613 | if (inputFuture.await(timeout, unit)) {
614 | currentTimeMillis -= System.currentTimeMillis();
615 | if (currentTimeMillis <= 0)
616 | return outputFuture.isDone(); // not enough time to await outputFuture
617 | return outputFuture.await(currentTimeMillis, TimeUnit.MILLISECONDS);
618 | }
619 | return false;
620 | }
621 |
622 | @Override
623 | public boolean await(long timeoutMillis) throws InterruptedException {
624 | return await(timeoutMillis, TimeUnit.MILLISECONDS);
625 | }
626 |
627 | @Override
628 | public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
629 | long currentTimeMillis = System.currentTimeMillis();
630 | if (inputFuture.awaitUninterruptibly(timeout, unit)) {
631 | currentTimeMillis -= System.currentTimeMillis();
632 | if (currentTimeMillis <= 0)
633 | return outputFuture.isDone(); // not enough time to await outputFuture
634 | return outputFuture.awaitUninterruptibly(currentTimeMillis, TimeUnit.MILLISECONDS);
635 | }
636 | return false;
637 | }
638 |
639 | @Override
640 | public boolean awaitUninterruptibly(long timeoutMillis) {
641 | return awaitUninterruptibly(timeoutMillis, TimeUnit.MILLISECONDS);
642 | }
643 |
644 | @Override
645 | public Void getNow() {
646 | return inputFuture.isDone() && outputFuture.isDone()? inputFuture.getNow(): null;
647 | }
648 |
649 | @Override
650 | public boolean cancel(boolean mayInterruptIfRunning) {
651 | boolean cancelInput = inputFuture.cancel(mayInterruptIfRunning);
652 | boolean cancelOutput = outputFuture.cancel(mayInterruptIfRunning);
653 | return cancelInput && cancelOutput;
654 | }
655 |
656 | @Override
657 | public boolean isCancelled() {
658 | return inputFuture.isCancelled() && outputFuture.isCancelled();
659 | }
660 |
661 | @Override
662 | public boolean isDone() {
663 | return inputFuture.isDone() && outputFuture.isDone();
664 | }
665 |
666 | @Override
667 | public Void get() throws InterruptedException, ExecutionException {
668 | Void inputResult = inputFuture.get();
669 | outputFuture.get();
670 | return inputResult;
671 | }
672 |
673 | @Override
674 | public Void get(long timeout, TimeUnit unit)
675 | throws InterruptedException, ExecutionException, TimeoutException {
676 | Void inputResult = inputFuture.get(timeout, unit);
677 | outputFuture.get(timeout, unit);
678 | return inputResult;
679 | }
680 |
681 | @Override
682 | public Channel channel() {
683 | return AbstractXnioSocketChannel.this;
684 | }
685 |
686 | @Override
687 | public ChannelFuture addListener(GenericFutureListener extends Future super Void>> listener) {
688 | inputFuture.addListener(listener);
689 | outputFuture.addListener(listener);
690 | return this;
691 | }
692 |
693 | @Override
694 | public ChannelFuture addListeners(GenericFutureListener extends Future super Void>>... listeners) {
695 | inputFuture.addListeners(listeners);
696 | outputFuture.addListeners(listeners);
697 | return this;
698 | }
699 |
700 | @Override
701 | public ChannelFuture removeListener(GenericFutureListener extends Future super Void>> listener) {
702 | inputFuture.removeListener(listener);
703 | outputFuture.removeListener(listener);
704 | return this;
705 | }
706 |
707 | @Override
708 | public ChannelFuture removeListeners(GenericFutureListener extends Future super Void>>... listeners) {
709 | inputFuture.removeListeners(listeners);
710 | outputFuture.removeListeners(listeners);
711 | return this;
712 | }
713 |
714 | @Override
715 | public ChannelFuture sync() throws InterruptedException {
716 | inputFuture.sync();
717 | outputFuture.sync();
718 | return this;
719 | }
720 |
721 | @Override
722 | public ChannelFuture syncUninterruptibly() {
723 | inputFuture.syncUninterruptibly();
724 | outputFuture.syncUninterruptibly();
725 | return this;
726 | }
727 |
728 | @Override
729 | public ChannelFuture await() throws InterruptedException {
730 | inputFuture.await();
731 | outputFuture.await();
732 | return this;
733 | }
734 |
735 | @Override
736 | public ChannelFuture awaitUninterruptibly() {
737 | inputFuture.awaitUninterruptibly();
738 | outputFuture.awaitUninterruptibly();
739 | return this;
740 | }
741 |
742 | @Override
743 | public boolean isVoid() {
744 | return inputFuture.isVoid() || outputFuture.isVoid();
745 | }
746 | };
747 | }
748 |
749 | }
750 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/IoThreadPowered.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import org.xnio.XnioIoThread;
20 |
21 | /**
22 | *
23 | * @author Norman Maurer
24 | */
25 | interface IoThreadPowered {
26 |
27 | XnioIoThread ioThread();
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/WrappingXnioServerSocketChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import org.xnio.Option;
20 | import org.xnio.XnioIoThread;
21 | import org.xnio.channels.AcceptingChannel;
22 |
23 | import java.io.IOException;
24 | import java.net.SocketAddress;
25 |
26 | /**
27 | * {@link AbstractXnioServerSocketChannel} implementation which allows to use a {@link AcceptingChannel} and wrap it.
28 | *
29 | * @author Norman Maurer
30 | */
31 | public final class WrappingXnioServerSocketChannel extends AbstractXnioServerSocketChannel implements IoThreadPowered {
32 |
33 | private final AcceptingChannel channel;
34 | private final XnioIoThread thread;
35 |
36 | /**
37 | * Create a new instance wrapping the given {@link AcceptingChannel}
38 | */
39 | @SuppressWarnings("unchecked")
40 | public WrappingXnioServerSocketChannel(AcceptingChannel channel) {
41 | if (channel == null) {
42 | throw new NullPointerException("channel");
43 | }
44 | this.channel = channel;
45 | thread = channel.getIoThread();
46 | channel.getAcceptSetter().set(new AcceptListener());
47 | // register a EventLoop and start read
48 | unsafe().register(new XnioEventLoop(channel.getWorker().getIoThread()), unsafe().voidPromise());
49 | read();
50 | }
51 |
52 | @Override
53 | public XnioIoThread ioThread() {
54 | return thread;
55 | }
56 |
57 | @Override
58 | protected void setOption0(Option option, T value) throws IOException {
59 | channel.setOption(option, value);
60 | }
61 |
62 | @Override
63 | protected T getOption0(Option option) throws IOException {
64 | return channel.getOption(option);
65 | }
66 |
67 | @Override
68 | protected void doBind(SocketAddress localAddress) throws Exception {
69 | throw new UnsupportedOperationException("Wrapped XNIO Channel");
70 | }
71 |
72 | @Override
73 | protected AcceptingChannel xnioChannel() {
74 | return channel;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/WrappingXnioSocketChannel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import java.io.IOException;
20 | import java.net.SocketAddress;
21 |
22 | import org.xnio.Option;
23 | import org.xnio.StreamConnection;
24 | import org.xnio.XnioIoThread;
25 | import org.xnio.channels.AcceptingChannel;
26 |
27 | import io.netty.channel.ChannelFuture;
28 | import io.netty.channel.ChannelPromise;
29 |
30 | /**
31 | * {@link AbstractXnioSocketChannel} implementation which allows you to wrap a pre-created XNIO channel.
32 | *
33 | * @author Norman Maurer
34 | * @author Flavia Rainone
35 | */
36 | public final class WrappingXnioSocketChannel extends AbstractXnioSocketChannel implements IoThreadPowered {
37 | private final StreamConnection channel;
38 | private final XnioIoThread thread;
39 | private volatile XnioChannelCloseFuture closeFuture;
40 |
41 | WrappingXnioSocketChannel(AbstractXnioServerSocketChannel parent, StreamConnection channel) {
42 | super(parent);
43 | if (channel == null) {
44 | throw new NullPointerException("channel");
45 | }
46 | this.channel = channel;
47 | this.thread = channel.getIoThread();
48 | config().setTcpNoDelay(true);
49 | channel.getSourceChannel().getReadSetter().set(new ReadListener());
50 | }
51 |
52 | /**
53 | * Create a new {@link WrappingXnioSocketChannel} which was created via the given {@link AcceptingChannel} and uses
54 | * the given {@link StreamConnection} under the covers.
55 | */
56 | public WrappingXnioSocketChannel(AcceptingChannel parent, StreamConnection channel) {
57 | this(new WrappingXnioServerSocketChannel(parent), channel);
58 | // register a EventLoop and start read
59 | unsafe().register(new XnioEventLoop(thread), unsafe().voidPromise());
60 | read();
61 | }
62 |
63 | /**
64 | * Create a {@link WrappingXnioSocketChannel} which uses the given {@link StreamConnection} under the covers.
65 | */
66 | public WrappingXnioSocketChannel(StreamConnection channel) {
67 | this((AbstractXnioServerSocketChannel) null, channel);
68 | // register a EventLoop and start read
69 | unsafe().register(new XnioEventLoop(thread), unsafe().voidPromise());
70 | read();
71 | }
72 |
73 | @Override
74 | public XnioIoThread ioThread() {
75 | return thread;
76 | }
77 |
78 | @Override
79 | protected XnioUnsafe newUnsafe() {
80 | return new XnioUnsafe();
81 | }
82 |
83 | @Override
84 | protected void doBind(SocketAddress localAddress) throws Exception {
85 | throw new UnsupportedOperationException("Wrapped XNIO Channel");
86 | }
87 |
88 | private final class XnioUnsafe extends AbstractXnioUnsafe {
89 | @Override
90 | public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) {
91 | promise.setFailure(new UnsupportedOperationException("Wrapped XNIO Channel"));
92 | }
93 | }
94 |
95 | @Override
96 | protected void setOption0(Option option, T value) throws IOException {
97 | channel.setOption(option, value);
98 | }
99 |
100 | @Override
101 | protected T getOption0(Option option) throws IOException {
102 | return channel.getOption(option);
103 | }
104 |
105 | @Override
106 | protected StreamConnection connection() {
107 | return channel;
108 | }
109 |
110 | @Override
111 | public ChannelFuture shutdownInput() {
112 | if (closeFuture != null) {
113 | closeFuture = new XnioChannelCloseFuture(this);
114 | }
115 | channel.getSourceChannel().setCloseListener(closeFuture);
116 | try {
117 | channel.getSourceChannel().shutdownReads();
118 | } catch (IOException e) {
119 | closeFuture.setError(e);
120 | }
121 | return closeFuture;
122 | }
123 |
124 | @Override
125 | public ChannelFuture shutdownInput(ChannelPromise channelPromise) {
126 | closeFuture = new XnioChannelPromiseCloseFuture(this, channelPromise);
127 | return shutdownInput();
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/XnioChannelCloseFuture.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2016, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 | package org.xnio.netty.transport;
23 |
24 | import java.io.IOException;
25 | import java.util.ArrayList;
26 | import java.util.List;
27 | import java.util.concurrent.CountDownLatch;
28 | import java.util.concurrent.ExecutionException;
29 | import java.util.concurrent.TimeUnit;
30 | import java.util.concurrent.TimeoutException;
31 | import java.util.concurrent.atomic.AtomicBoolean;
32 |
33 | import org.xnio.ChannelListener;
34 | import org.xnio.conduits.ConduitStreamSourceChannel;
35 |
36 | import io.netty.channel.Channel;
37 | import io.netty.channel.ChannelFuture;
38 | import io.netty.util.concurrent.Future;
39 | import io.netty.util.concurrent.GenericFutureListener;
40 |
41 | /**
42 | * ChannelFuture to be provided when shutting down channels, performs as a close listener on the Xnio side.
43 | *
44 | *
45 | * @author Flavia Rainone
46 | *
47 | */
48 | public class XnioChannelCloseFuture implements ChannelFuture, ChannelListener{
49 |
50 | private IOException error;
51 | private final AtomicBoolean closed;
52 | private final AbstractXnioSocketChannel channel;
53 | private final CountDownLatch countDownLatch = new CountDownLatch(1);
54 | private List>> listeners;
55 |
56 | public XnioChannelCloseFuture(AbstractXnioSocketChannel channel/*, IOException error*/) {
57 | //this.error = error;
58 | this.closed = new AtomicBoolean(false);
59 | this.channel = channel;
60 | }
61 |
62 | public void setError(IOException error) {
63 | this.error = error;
64 | }
65 |
66 | @Override
67 | public boolean isSuccess() {
68 | return closed.get() && error != null;
69 | }
70 |
71 | @Override
72 | public boolean isCancellable() {
73 | return false;
74 | }
75 |
76 | @Override
77 | public Throwable cause() {
78 | return error;
79 | }
80 |
81 | @Override
82 | public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
83 | countDownLatch.await(timeout, unit);
84 | return closed.get();
85 | }
86 |
87 | @Override
88 | public boolean await(long timeoutMillis) throws InterruptedException {
89 | countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
90 | return closed.get();
91 | }
92 |
93 | @Override
94 | public boolean awaitUninterruptibly(long timeout, TimeUnit unit) {
95 | try {
96 | countDownLatch.await(timeout, unit);
97 | } catch (InterruptedException e) {
98 | // discard interrupted
99 | }
100 | return closed.get();
101 | }
102 |
103 | @Override
104 | public boolean awaitUninterruptibly(long timeoutMillis) {
105 | try {
106 | countDownLatch.await(timeoutMillis, TimeUnit.MILLISECONDS);
107 | } catch (InterruptedException e) {
108 | // discard interrupted
109 | }
110 | return closed.get();
111 | }
112 |
113 | @Override
114 | public Void getNow() {
115 | return null;
116 | }
117 |
118 | @Override
119 | public boolean cancel(boolean mayInterruptIfRunning) {
120 | return false;
121 | }
122 |
123 | @Override
124 | public boolean isCancelled() {
125 | return false;
126 | }
127 |
128 | @Override
129 | public boolean isDone() {
130 | return closed.get();
131 | }
132 |
133 | @Override
134 | public Void get() throws InterruptedException, ExecutionException {
135 | return null;
136 | }
137 |
138 | @Override
139 | public Void get(long timeout, TimeUnit unit)
140 | throws InterruptedException, ExecutionException, TimeoutException {
141 | countDownLatch.await(timeout, unit);
142 | return null;
143 | }
144 |
145 | @Override
146 | public Channel channel() {
147 | return channel;
148 | }
149 |
150 | @Override
151 | public ChannelFuture addListener(GenericFutureListener extends Future super Void>> listener) {
152 | final boolean notify;
153 | synchronized (this) {
154 | if (closed.get()) {
155 | notify = true;
156 | } else {
157 | notify = false;
158 | if (listeners == null) {
159 | listeners = new ArrayList>>();
160 | }
161 | listeners.add(listener);
162 | }
163 | }
164 | if (notify)
165 | notifyListener(listener);
166 | return this;
167 | }
168 |
169 | @SuppressWarnings("unchecked")
170 | private > void notifyListener(GenericFutureListener listener) {
171 | try {
172 | listener.operationComplete((T) this);
173 | } catch (Exception e) {
174 | throw new RuntimeException(e);
175 | }
176 | }
177 |
178 | @Override
179 | public ChannelFuture addListeners(GenericFutureListener extends Future super Void>>... listeners) {
180 | for (GenericFutureListener extends Future super Void>> listener: listeners)
181 | addListener(listener);
182 | return this;
183 | }
184 |
185 | @Override
186 | public ChannelFuture removeListener(GenericFutureListener extends Future super Void>> listener) {
187 | synchronized (this) {
188 | if (listeners != null) {
189 | listeners.remove(listener);
190 | }
191 | }
192 | return this;
193 | }
194 |
195 | @Override
196 | public ChannelFuture removeListeners(GenericFutureListener extends Future super Void>>... listeners) {
197 | synchronized (this) {
198 | if (this.listeners != null) {
199 | for (GenericFutureListener extends Future super Void>> listener: listeners)
200 | this.listeners.remove(listener);
201 | }
202 | }
203 | return this;
204 | }
205 |
206 | @Override
207 | public ChannelFuture sync() throws InterruptedException {
208 | closed.wait();
209 | if (error != null)
210 | throw new RuntimeException(error);
211 | return this;
212 | }
213 |
214 | @Override
215 | public ChannelFuture syncUninterruptibly() {
216 | try {
217 | closed.wait();
218 | } catch (InterruptedException e) {
219 | // ignore
220 | }
221 | if (error != null)
222 | throw new RuntimeException(error);
223 | return this;
224 | }
225 |
226 | @Override
227 | public ChannelFuture await() throws InterruptedException {
228 | countDownLatch.await();
229 | return this;
230 | }
231 |
232 | @Override
233 | public ChannelFuture awaitUninterruptibly() {
234 | try {
235 | countDownLatch.await();
236 | } catch (InterruptedException e) {
237 | // ignore
238 | }
239 | return this;
240 | }
241 |
242 | @Override
243 | public boolean isVoid() {
244 | return true;
245 | }
246 |
247 | @Override
248 | public void handleEvent(ConduitStreamSourceChannel channel) {
249 | closed.compareAndSet(false, true);
250 | countDownLatch.countDown();
251 | }
252 |
253 | }
254 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/XnioChannelOption.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 | import io.netty.channel.ChannelOption;
20 |
21 | /**
22 | * {@link ChannelOption}'s specific for the XNIO transport.
23 | *
24 | * @author Norman Maurer
25 | */
26 | public final class XnioChannelOption extends ChannelOption{
27 |
28 | /**
29 | * @see {@link org.xnio.Options#CONNECTION_HIGH_WATER}
30 | */
31 | public static final ChannelOption CONNECTION_HIGH_WATER = valueOf("CONNECTION_HIGH_WATER");
32 |
33 | /**
34 | * @see {@link org.xnio.Options#CONNECTION_LOW_WATER}
35 | */
36 | public static final ChannelOption CONNECTION_LOW_WATER = valueOf("CONNECTION_LOW_WATER");
37 |
38 | /**
39 | * @see {@link org.xnio.Options#BALANCING_TOKENS}
40 | */
41 | public static final ChannelOption BALANCING_TOKENS = valueOf("BALANCING_TOKENS");
42 |
43 | /**
44 | * @see {@link org.xnio.Options#BALANCING_CONNECTIONS}
45 | */
46 | public static final ChannelOption BALANCING_CONNECTIONS = valueOf("BALANCING_CONNECTIONS");
47 |
48 | @SuppressWarnings("unused")
49 | private XnioChannelOption(String name) {
50 | super(name);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/XnioChannelPromiseCloseFuture.java:
--------------------------------------------------------------------------------
1 | /*
2 | * JBoss, Home of Professional Open Source.
3 | * Copyright 2016, Red Hat, Inc., and individual contributors
4 | * as indicated by the @author tags. See the copyright.txt file in the
5 | * distribution for a full listing of individual contributors.
6 | *
7 | * This is free software; you can redistribute it and/or modify it
8 | * under the terms of the GNU Lesser General Public License as
9 | * published by the Free Software Foundation; either version 2.1 of
10 | * the License, or (at your option) any later version.
11 | *
12 | * This software is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 | * Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public
18 | * License along with this software; if not, write to the Free
19 | * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 | * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 | */
22 | package org.xnio.netty.transport;
23 |
24 | import java.io.IOException;
25 | import java.util.ArrayList;
26 | import java.util.concurrent.ExecutionException;
27 | import java.util.concurrent.TimeUnit;
28 | import java.util.concurrent.TimeoutException;
29 |
30 | import org.xnio.conduits.ConduitStreamSourceChannel;
31 |
32 | import io.netty.channel.Channel;
33 | import io.netty.channel.ChannelFuture;
34 | import io.netty.channel.ChannelPromise;
35 | import io.netty.util.concurrent.Future;
36 | import io.netty.util.concurrent.GenericFutureListener;
37 |
38 | /**
39 | * ChannelFuture to be provided when shutting down channels, performs as a close listener on the Xnio side.
40 | *
41 | *
42 | * @author Flavia Rainone
43 | *
44 | */
45 | public class XnioChannelPromiseCloseFuture extends XnioChannelCloseFuture {
46 |
47 | private final ChannelPromise channelPromise;
48 |
49 | public XnioChannelPromiseCloseFuture(AbstractXnioSocketChannel channel, ChannelPromise channelPromise) {
50 | super(channel);
51 | this.channelPromise = channelPromise;
52 | }
53 |
54 | @Override
55 | public void setError(IOException error) {
56 | super.setError(error);
57 | channelPromise.setFailure(error);
58 | }
59 |
60 | @Override
61 | public void handleEvent(ConduitStreamSourceChannel channel) {
62 | super.handleEvent(channel);
63 | channelPromise.trySuccess();
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/org/xnio/netty/transport/XnioEventLoop.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 Red Hat, Inc.
3 | *
4 | * Red Hat licenses this file to you under the Apache License, version 2.0
5 | * (the "License"); you may not use this file except in compliance with the
6 | * License. You may obtain a copy of the License at:
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations
14 | * under the License.
15 | *
16 | */
17 | package org.xnio.netty.transport;
18 |
19 |
20 | import io.netty.channel.Channel;
21 | import io.netty.channel.ChannelFuture;
22 | import io.netty.channel.ChannelPromise;
23 | import io.netty.channel.EventLoop;
24 | import io.netty.channel.EventLoopGroup;
25 | import io.netty.util.concurrent.AbstractEventExecutor;
26 | import io.netty.util.concurrent.DefaultPromise;
27 | import io.netty.util.concurrent.Future;
28 | import io.netty.util.concurrent.ScheduledFuture;
29 | import org.xnio.XnioExecutor;
30 | import org.xnio.XnioIoThread;
31 |
32 | import java.util.concurrent.Callable;
33 | import java.util.concurrent.Delayed;
34 | import java.util.concurrent.Executors;
35 | import java.util.concurrent.TimeUnit;
36 |
37 | /**
38 | * {@link EventLoop} implementation which uses a {@link XnioIoThread}.
39 | *
40 | * @author Norman Maurer
41 | */
42 | final class XnioEventLoop extends AbstractEventExecutor implements EventLoop, IoThreadPowered{
43 | private final XnioIoThread executor;
44 | private final EventLoopGroup parent;
45 |
46 | XnioEventLoop(EventLoopGroup parent, XnioIoThread executor) {
47 | this.parent = parent ;
48 | this.executor = executor;
49 | }
50 |
51 | XnioEventLoop(XnioIoThread executor) {
52 | this.parent = this;
53 | this.executor = executor;
54 | }
55 |
56 | @Override
57 | public XnioIoThread ioThread() {
58 | return executor;
59 | }
60 |
61 | @Override
62 | public void shutdown() {
63 | // Not supported, just ignore
64 | }
65 |
66 | @Override
67 | public EventLoopGroup parent() {
68 | return parent;
69 | }
70 |
71 | @Override
72 | public boolean inEventLoop(Thread thread) {
73 | return thread == executor;
74 | }
75 |
76 | @Override
77 | public ChannelFuture register(Channel channel) {
78 | return register(channel, channel.newPromise());
79 | }
80 |
81 | @Override
82 | public ChannelFuture register(final Channel channel, final ChannelPromise promise) {
83 | if (channel == null) {
84 | throw new NullPointerException("channel");
85 | }
86 | if (promise == null) {
87 | throw new NullPointerException("promise");
88 | }
89 | channel.unsafe().register(this, promise);
90 | return promise;
91 | }
92 |
93 |
94 | @Override
95 | public ChannelFuture register(ChannelPromise promise) {
96 | return register(promise.channel(), promise);
97 | }
98 |
99 | @Override
100 | public boolean isShuttingDown() {
101 | return executor.getWorker().isShutdown();
102 | }
103 |
104 | @Override
105 | public Future> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
106 | return newFailedFuture(new UnsupportedOperationException());
107 | }
108 |
109 | @Override
110 | public Future> terminationFuture() {
111 | return newFailedFuture(new UnsupportedOperationException());
112 | }
113 |
114 | @Override
115 | public boolean isShutdown() {
116 | return executor.getWorker().isShutdown();
117 | }
118 |
119 | @Override
120 | public boolean isTerminated() {
121 | return executor.getWorker().isTerminated();
122 | }
123 |
124 | @Override
125 | public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
126 | return executor.getWorker().awaitTermination(timeout, unit);
127 | }
128 |
129 | @Override
130 | public void execute(Runnable command) {
131 | executor.execute(command);
132 | }
133 |
134 | @Override
135 | public ScheduledFuture> schedule(Runnable command, long delay, TimeUnit unit) {
136 | return schedule(Executors.callable(command), delay, unit);
137 | }
138 |
139 | @Override
140 | public ScheduledFuture schedule(Callable callable, long delay, TimeUnit unit) {
141 | ScheduledFutureWrapper wrapper = new ScheduledFutureWrapper(callable, delay, unit);
142 | wrapper.key = executor.executeAfter(wrapper, delay, unit);
143 | return wrapper;
144 | }
145 |
146 | @Override
147 | public ScheduledFuture> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
148 | FixedScheduledFuture wrapper = new FixedScheduledFuture(command, initialDelay, delay, unit);
149 | wrapper.key = executor.executeAfter(wrapper, delay, unit);
150 | return wrapper;
151 | }
152 |
153 | @Override
154 | public ScheduledFuture> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
155 | FixedRateScheduledFuture wrapper = new FixedRateScheduledFuture(command, initialDelay, period, unit);
156 | wrapper.key = executor.executeAfter(wrapper, initialDelay, unit);
157 | return wrapper;
158 | }
159 |
160 | @Override
161 | public XnioEventLoop next() {
162 | return this;
163 | }
164 |
165 | private final class FixedRateScheduledFuture extends ScheduledFutureWrapper