├── .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> listener) { 688 | inputFuture.addListener(listener); 689 | outputFuture.addListener(listener); 690 | return this; 691 | } 692 | 693 | @Override 694 | public ChannelFuture addListeners(GenericFutureListener>... listeners) { 695 | inputFuture.addListeners(listeners); 696 | outputFuture.addListeners(listeners); 697 | return this; 698 | } 699 | 700 | @Override 701 | public ChannelFuture removeListener(GenericFutureListener> listener) { 702 | inputFuture.removeListener(listener); 703 | outputFuture.removeListener(listener); 704 | return this; 705 | } 706 | 707 | @Override 708 | public ChannelFuture removeListeners(GenericFutureListener>... 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> 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>... listeners) { 180 | for (GenericFutureListener> listener: listeners) 181 | addListener(listener); 182 | return this; 183 | } 184 | 185 | @Override 186 | public ChannelFuture removeListener(GenericFutureListener> 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>... listeners) { 197 | synchronized (this) { 198 | if (this.listeners != null) { 199 | for (GenericFutureListener> 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 { 166 | private final long period; 167 | private int count = 1; 168 | private final long initialDelay; 169 | private FixedRateScheduledFuture(Runnable task, long delay, long period, TimeUnit unit) { 170 | super(Executors.callable(task), delay, unit); 171 | this.initialDelay = delay; 172 | this.period = period; 173 | } 174 | 175 | @Override 176 | public void run() { 177 | try { 178 | task.call(); 179 | start = System.nanoTime(); 180 | delay = initialDelay + period * (++count); 181 | key = executor.executeAfter(this,delay, TimeUnit.NANOSECONDS); 182 | } catch (Throwable cause) { 183 | tryFailure(cause); 184 | } 185 | } 186 | 187 | } 188 | 189 | private final class FixedScheduledFuture extends ScheduledFutureWrapper { 190 | private long furtherDelay; 191 | private FixedScheduledFuture(Runnable task, long initialDelay, long delay, TimeUnit unit) { 192 | super(Executors.callable(task), initialDelay, unit); 193 | this.furtherDelay = unit.toNanos(delay); 194 | } 195 | 196 | @Override 197 | public void run() { 198 | try { 199 | task.call(); 200 | start = System.nanoTime(); 201 | delay = furtherDelay; 202 | key = executor.executeAfter(this, furtherDelay, TimeUnit.NANOSECONDS); 203 | } catch (Throwable cause) { 204 | tryFailure(cause); 205 | } 206 | } 207 | 208 | } 209 | 210 | private class ScheduledFutureWrapper extends DefaultPromise implements ScheduledFuture, Runnable { 211 | protected volatile XnioExecutor.Key key; 212 | protected final Callable task; 213 | protected volatile long delay; 214 | protected volatile long start; 215 | 216 | ScheduledFutureWrapper(Callable task, long delay, TimeUnit unit) { 217 | this.task = task; 218 | this.start = System.nanoTime(); 219 | this.delay = unit.toNanos(delay); 220 | } 221 | 222 | @Override 223 | public long getDelay(TimeUnit unit) { 224 | long remaining = (start + delay) - System.nanoTime(); 225 | if (remaining < 1 || unit == TimeUnit.NANOSECONDS) { 226 | return remaining; 227 | } 228 | return unit.convert(remaining, TimeUnit.NANOSECONDS); 229 | } 230 | 231 | @Override 232 | public int compareTo(Delayed o) { 233 | long d = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS); 234 | if (d < 0) { 235 | return -1; 236 | } else if (d > 0) { 237 | return 1; 238 | } else { 239 | return 0; 240 | } 241 | } 242 | 243 | @Override 244 | public void run() { 245 | try { 246 | trySuccess(task.call()); 247 | } catch (Throwable t) { 248 | tryFailure(t); 249 | } 250 | } 251 | 252 | @Override 253 | public boolean cancel(boolean mayInterruptIfRunning) { 254 | return setUncancellable() && key.remove(); 255 | } 256 | } 257 | 258 | 259 | } 260 | -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioEventLoopGroup.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.Channel; 20 | import io.netty.channel.ChannelFuture; 21 | import io.netty.channel.ChannelPromise; 22 | import io.netty.channel.EventLoop; 23 | import io.netty.channel.EventLoopGroup; 24 | import io.netty.util.concurrent.AbstractEventExecutorGroup; 25 | import io.netty.util.concurrent.EventExecutor; 26 | import io.netty.util.concurrent.Future; 27 | import io.netty.util.concurrent.ImmediateEventExecutor; 28 | import org.xnio.OptionMap; 29 | import org.xnio.Options; 30 | import org.xnio.Xnio; 31 | import org.xnio.XnioWorker; 32 | 33 | import java.io.IOException; 34 | import java.util.Iterator; 35 | import java.util.concurrent.TimeUnit; 36 | import java.util.concurrent.TimeoutException; 37 | 38 | /** 39 | * {@link EventLoopGroup} implementation which uses a {@link XnioWorker} under the covers. This means all operations 40 | * will be performed by it. 41 | */ 42 | public final class XnioEventLoopGroup extends AbstractEventExecutorGroup implements EventLoopGroup { 43 | 44 | private final XnioWorker worker; 45 | 46 | /** 47 | * Create a new {@link XnioEventLoopGroup} using the provided {@link XnioWorker}. 48 | * 49 | */ 50 | public XnioEventLoopGroup(XnioWorker worker) { 51 | if (worker == null) { 52 | throw new NullPointerException("worker"); 53 | } 54 | this.worker = worker; 55 | } 56 | 57 | /** 58 | * Create a new {@link XnioEventLoopGroup} which creates a new {@link XnioWorker} 59 | * by itself and use it for all operations. 60 | * 61 | * @throws IOException 62 | */ 63 | public XnioEventLoopGroup() throws IOException { 64 | this(Runtime.getRuntime().availableProcessors() * 2); 65 | } 66 | 67 | /** 68 | * Create a new {@link XnioEventLoopGroup} which creates a new {@link XnioWorker} by itself and use it for all 69 | * operations. Using the given number of Threads to handle the IO. 70 | * 71 | * @throws IOException 72 | */ 73 | public XnioEventLoopGroup(int numThreads) throws IOException { 74 | this(Xnio.getInstance().createWorker(OptionMap.create(Options.WORKER_IO_THREADS, numThreads))); 75 | } 76 | 77 | @Override 78 | public void shutdown() { 79 | worker.shutdown(); 80 | } 81 | 82 | @Override 83 | public EventLoop next() { 84 | return new XnioEventLoop(this, worker.getIoThread()); 85 | } 86 | 87 | @Override 88 | public ChannelFuture register(Channel channel) { 89 | return register(channel, channel.newPromise()); 90 | } 91 | 92 | @Override 93 | public ChannelFuture register(ChannelPromise promise) { 94 | return register(promise.channel(), promise); 95 | } 96 | 97 | @Override 98 | public ChannelFuture register(Channel channel, ChannelPromise promise) { 99 | if (channel instanceof IoThreadPowered) { 100 | IoThreadPowered ch = (IoThreadPowered) channel; 101 | XnioEventLoop loop = new XnioEventLoop(this, ch.ioThread()); 102 | channel.unsafe().register(loop, promise); 103 | return promise; 104 | } 105 | return next().register(channel, promise); 106 | } 107 | 108 | @Override 109 | public boolean isShuttingDown() { 110 | return worker.isTerminated(); 111 | } 112 | 113 | @Override 114 | public Future shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) { 115 | shutdown(); 116 | if (isShutdown()) { 117 | return ImmediateEventExecutor.INSTANCE.newSucceededFuture(null); 118 | } else { 119 | return ImmediateEventExecutor.INSTANCE.newFailedFuture(new TimeoutException()); 120 | } 121 | } 122 | 123 | @Override 124 | public Future terminationFuture() { 125 | throw new UnsupportedOperationException(); 126 | } 127 | 128 | @Override 129 | public Iterator iterator() { 130 | throw new UnsupportedOperationException(); 131 | } 132 | 133 | @Override 134 | public boolean isShutdown() { 135 | return worker.isShutdown(); 136 | } 137 | 138 | @Override 139 | public boolean isTerminated() { 140 | return worker.isTerminated(); 141 | } 142 | 143 | @Override 144 | public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { 145 | return worker.awaitTermination(timeout, unit); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioServerSocketChannel.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.EventLoop; 20 | import org.xnio.*; 21 | import org.xnio.channels.AcceptingChannel; 22 | 23 | import java.io.IOException; 24 | import java.net.SocketAddress; 25 | 26 | /** 27 | * {@link io.netty.channel.socket.ServerSocketChannel} which uses XNIO. 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public final class XnioServerSocketChannel extends AbstractXnioServerSocketChannel { 32 | private final OptionMap.Builder options = OptionMap.builder(); 33 | 34 | private volatile AcceptingChannel channel; 35 | @Override 36 | protected boolean isCompatible(EventLoop loop) { 37 | return loop instanceof XnioEventLoop; 38 | } 39 | 40 | @Override 41 | protected void doBind(SocketAddress localAddress) throws Exception { 42 | XnioWorker worker = ((XnioEventLoop) eventLoop()).ioThread().getWorker(); 43 | // use the same thread count as the XnioWorker 44 | OptionMap map = options.set(Options.WORKER_IO_THREADS, worker.getIoThreadCount()).getMap(); 45 | XnioEventLoop eventLoop = (XnioEventLoop) eventLoop(); 46 | synchronized (this) { 47 | channel = eventLoop.ioThread().getWorker().createStreamConnectionServer(localAddress, new AcceptListener(), map); 48 | // start accepting 49 | channel.resumeAccepts(); 50 | } 51 | } 52 | 53 | @Override 54 | protected T getOption0(Option option) throws IOException { 55 | if (channel != null) { 56 | return channel.getOption(option); 57 | } 58 | return options.getMap().get(option); 59 | } 60 | 61 | @Override 62 | protected synchronized void setOption0(Option option, T value) throws IOException { 63 | if (channel != null) { 64 | channel.setOption(option, value); 65 | } else { 66 | options.set(option, value); 67 | } 68 | } 69 | 70 | @Override 71 | protected AcceptingChannel xnioChannel() { 72 | return channel; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioServerSocketChannelConfig.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.buffer.ByteBufAllocator; 20 | import io.netty.channel.MessageSizeEstimator; 21 | import io.netty.channel.RecvByteBufAllocator; 22 | import io.netty.channel.socket.ServerSocketChannelConfig; 23 | 24 | /** 25 | * {@link ServerSocketChannelConfig} which expose configuration settings which are specific to the XNIO transport. 26 | * 27 | * @author Norman Maurer 28 | */ 29 | public interface XnioServerSocketChannelConfig extends ServerSocketChannelConfig { 30 | 31 | /** 32 | * @see {@link XnioChannelOption#CONNECTION_HIGH_WATER} 33 | */ 34 | XnioServerSocketChannelConfig setConnectionHighWater(int connectionHighWater); 35 | 36 | /** 37 | * @see {@link XnioChannelOption#CONNECTION_HIGH_WATER} 38 | */ 39 | int getConnectionHighWater(); 40 | 41 | /** 42 | * @see {@link XnioChannelOption#CONNECTION_LOW_WATER} 43 | */ 44 | XnioServerSocketChannelConfig setConnectionLowWater(int connectionLowWater); 45 | 46 | /** 47 | * @see {@link XnioChannelOption#CONNECTION_LOW_WATER} 48 | */ 49 | int getConnectionLowWater(); 50 | 51 | /** 52 | * @see {@link XnioChannelOption#BALANCING_TOKENS} 53 | */ 54 | XnioServerSocketChannelConfig setBalancingTokens(int balancingTokens); 55 | 56 | /** 57 | * @see {@link XnioChannelOption#BALANCING_TOKENS} 58 | */ 59 | int getBalancingTokens(); 60 | 61 | /** 62 | * @see {@link XnioChannelOption#BALANCING_CONNECTIONS} 63 | */ 64 | XnioServerSocketChannelConfig setBalancingConnections(int connections); 65 | 66 | /** 67 | * @see {@link XnioChannelOption#BALANCING_CONNECTIONS} 68 | */ 69 | int getBalancingConnections(); 70 | 71 | @Override 72 | XnioServerSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis); 73 | 74 | @Override 75 | XnioServerSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead); 76 | 77 | @Override 78 | XnioServerSocketChannelConfig setWriteSpinCount(int writeSpinCount); 79 | 80 | @Override 81 | XnioServerSocketChannelConfig setAllocator(ByteBufAllocator allocator); 82 | 83 | @Override 84 | XnioServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator); 85 | 86 | @Override 87 | XnioServerSocketChannelConfig setAutoRead(boolean autoRead); 88 | 89 | @Deprecated 90 | XnioServerSocketChannelConfig setAutoClose(boolean autoClose); 91 | 92 | @Override 93 | XnioServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark); 94 | 95 | @Override 96 | XnioServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark); 97 | 98 | @Override 99 | XnioServerSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator); 100 | 101 | @Override 102 | XnioServerSocketChannelConfig setBacklog(int backlog); 103 | 104 | @Override 105 | XnioServerSocketChannelConfig setReuseAddress(boolean reuseAddress); 106 | 107 | @Override 108 | XnioServerSocketChannelConfig setReceiveBufferSize(int receiveBufferSize); 109 | 110 | @Override 111 | XnioServerSocketChannelConfig setPerformancePreferences(int connectionTime, int latency, int bandwidth); 112 | } -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioServerSocketChannelConfigImpl.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.util.Map; 20 | 21 | import org.xnio.Options; 22 | 23 | import io.netty.buffer.ByteBufAllocator; 24 | import io.netty.channel.ChannelOption; 25 | import io.netty.channel.DefaultChannelConfig; 26 | import io.netty.channel.MessageSizeEstimator; 27 | import io.netty.channel.RecvByteBufAllocator; 28 | import io.netty.channel.WriteBufferWaterMark; 29 | 30 | 31 | /** 32 | * @author Norman Maurer 33 | */ 34 | final class XnioServerSocketChannelConfigImpl extends DefaultChannelConfig implements XnioServerSocketChannelConfig { 35 | private final AbstractXnioServerSocketChannel channel; 36 | 37 | XnioServerSocketChannelConfigImpl(AbstractXnioServerSocketChannel channel) { 38 | super(channel); 39 | this.channel = channel; 40 | } 41 | 42 | @Override 43 | public Map, Object> getOptions() { 44 | return getOptions(super.getOptions(), XnioChannelOption.BALANCING_CONNECTIONS, 45 | XnioChannelOption.BALANCING_TOKENS, 46 | XnioChannelOption.CONNECTION_HIGH_WATER, 47 | XnioChannelOption.CONNECTION_LOW_WATER); 48 | } 49 | 50 | @SuppressWarnings("unchecked") 51 | @Override 52 | public T getOption(ChannelOption option) { 53 | if (option == XnioChannelOption.BALANCING_CONNECTIONS) { 54 | return (T) Integer.valueOf(getBalancingConnections()); 55 | } 56 | if (option == XnioChannelOption.BALANCING_TOKENS) { 57 | return (T) Integer.valueOf(getBalancingTokens()); 58 | } 59 | if (option == XnioChannelOption.CONNECTION_HIGH_WATER) { 60 | return (T) Integer.valueOf(getConnectionHighWater()); 61 | } 62 | if (option == XnioChannelOption.CONNECTION_LOW_WATER) { 63 | return (T) Integer.valueOf(getConnectionLowWater()); 64 | } 65 | return super.getOption(option); 66 | } 67 | 68 | @Override 69 | public boolean setOption(ChannelOption option, T value) { 70 | validate(option, value); 71 | 72 | if (option == XnioChannelOption.BALANCING_CONNECTIONS) { 73 | setBalancingConnections((Integer) value); 74 | } else if (option == XnioChannelOption.BALANCING_TOKENS) { 75 | setBalancingTokens((Integer) value); 76 | } else if (option == XnioChannelOption.CONNECTION_HIGH_WATER) { 77 | setConnectionHighWater((Integer) value); 78 | } else if (option == XnioChannelOption.CONNECTION_LOW_WATER) { 79 | setConnectionLowWater((Integer) value); 80 | } else { 81 | return super.setOption(option, value); 82 | } 83 | 84 | return true; 85 | } 86 | 87 | @Override 88 | public int getBacklog() { 89 | return channel.getOption(Options.BACKLOG); 90 | } 91 | 92 | @Override 93 | public XnioServerSocketChannelConfig setBacklog(int backlog) { 94 | channel.setOption(Options.BACKLOG, backlog); 95 | return this; 96 | } 97 | 98 | @Override 99 | public boolean isReuseAddress() { 100 | return channel.getOption(Options.REUSE_ADDRESSES); 101 | } 102 | 103 | @Override 104 | public XnioServerSocketChannelConfig setReuseAddress(boolean reuseAddress) { 105 | channel.setOption(Options.REUSE_ADDRESSES, reuseAddress); 106 | return this; 107 | } 108 | 109 | @Override 110 | public int getReceiveBufferSize() { 111 | return channel.getOption(Options.RECEIVE_BUFFER); 112 | } 113 | 114 | @Override 115 | public XnioServerSocketChannelConfig setReceiveBufferSize(int receiveBufferSize) { 116 | channel.setOption(Options.RECEIVE_BUFFER, receiveBufferSize); 117 | return this; 118 | } 119 | 120 | @Override 121 | public XnioServerSocketChannelConfig setPerformancePreferences(int connectionTime, int latency, int bandwidth) { 122 | throw new UnsupportedOperationException(); 123 | } 124 | 125 | @Override 126 | public XnioServerSocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) { 127 | super.setConnectTimeoutMillis(connectTimeoutMillis); 128 | return this; 129 | } 130 | 131 | @Override @Deprecated 132 | public XnioServerSocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) { 133 | super.setMaxMessagesPerRead(maxMessagesPerRead); 134 | return this; 135 | } 136 | 137 | @Override 138 | public XnioServerSocketChannelConfig setWriteSpinCount(int writeSpinCount) { 139 | super.setWriteSpinCount(writeSpinCount); 140 | return this; 141 | } 142 | 143 | @Override 144 | public XnioServerSocketChannelConfig setAllocator(ByteBufAllocator allocator) { 145 | super.setAllocator(allocator); 146 | return this; 147 | } 148 | 149 | @Override 150 | public XnioServerSocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { 151 | super.setRecvByteBufAllocator(allocator); 152 | return this; 153 | } 154 | 155 | @Override 156 | public XnioServerSocketChannelConfig setAutoRead(boolean autoRead) { 157 | super.setAutoRead(autoRead); 158 | return this; 159 | } 160 | 161 | @Override @Deprecated 162 | public XnioServerSocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { 163 | super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); 164 | return this; 165 | } 166 | 167 | @Override @Deprecated 168 | public XnioServerSocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { 169 | super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); 170 | return this; 171 | } 172 | 173 | public XnioServerSocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) { 174 | super.setWriteBufferWaterMark(writeBufferWaterMark); 175 | return this; 176 | } 177 | 178 | @Override 179 | public XnioServerSocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) { 180 | super.setMessageSizeEstimator(estimator); 181 | return this; 182 | } 183 | 184 | @Override 185 | public XnioServerSocketChannelConfig setAutoClose(boolean autoClose) { 186 | super.setAutoClose(autoClose); 187 | return this; 188 | } 189 | 190 | @Override 191 | public XnioServerSocketChannelConfig setConnectionHighWater(int connectionHighWater) { 192 | channel.setOption(Options.CONNECTION_HIGH_WATER, connectionHighWater); 193 | return this; 194 | } 195 | 196 | @Override 197 | public XnioServerSocketChannelConfig setConnectionLowWater(int connectionLowWater) { 198 | channel.setOption(Options.CONNECTION_LOW_WATER, connectionLowWater); 199 | return this; 200 | } 201 | 202 | @Override 203 | public XnioServerSocketChannelConfig setBalancingTokens(int balancingTokens) { 204 | channel.setOption(Options.BALANCING_TOKENS, balancingTokens); 205 | return this; 206 | } 207 | 208 | @Override 209 | public XnioServerSocketChannelConfig setBalancingConnections(int connections) { 210 | channel.setOption(Options.BALANCING_CONNECTIONS, connections); 211 | return this; 212 | } 213 | 214 | @Override 215 | public int getConnectionHighWater() { 216 | return channel.getOption(Options.CONNECTION_HIGH_WATER); 217 | } 218 | 219 | @Override 220 | public int getConnectionLowWater() { 221 | return channel.getOption(Options.CONNECTION_LOW_WATER); 222 | } 223 | 224 | @Override 225 | public int getBalancingTokens() { 226 | return channel.getOption(Options.BALANCING_TOKENS); 227 | } 228 | 229 | @Override 230 | public int getBalancingConnections() { 231 | return channel.getOption(Options.BALANCING_CONNECTIONS); 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioSocketChannel.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 | import java.util.concurrent.CancellationException; 22 | 23 | import org.xnio.IoFuture; 24 | import org.xnio.Option; 25 | import org.xnio.OptionMap; 26 | import org.xnio.StreamConnection; 27 | import org.xnio.XnioIoThread; 28 | 29 | import io.netty.channel.ChannelFuture; 30 | import io.netty.channel.ChannelFutureListener; 31 | import io.netty.channel.ChannelPromise; 32 | 33 | /** 34 | * {@link io.netty.channel.socket.SocketChannel} which uses XNIO. 35 | * 36 | * @author Norman Maurer 37 | */ 38 | public class XnioSocketChannel extends AbstractXnioSocketChannel { 39 | private final OptionMap.Builder options = OptionMap.builder(); 40 | private volatile StreamConnection channel; 41 | private volatile XnioChannelCloseFuture closeFuture; 42 | 43 | public XnioSocketChannel() { 44 | super(null); 45 | config().setTcpNoDelay(true); 46 | } 47 | 48 | @Override 49 | protected AbstractXnioUnsafe newUnsafe() { 50 | return new XnioUnsafe(); 51 | } 52 | 53 | @Override 54 | protected void setOption0(Option option, T value) throws IOException { 55 | if (channel == null) { 56 | options.set(option, value); 57 | } else { 58 | channel.setOption(option, value); 59 | } 60 | } 61 | 62 | @Override 63 | protected T getOption0(Option option) throws IOException { 64 | if (channel == null) { 65 | return options.getMap().get(option); 66 | } else { 67 | return channel.getOption(option); 68 | } 69 | } 70 | 71 | @Override 72 | protected StreamConnection connection() { 73 | return channel; 74 | } 75 | 76 | @Override 77 | protected void doBind(SocketAddress localAddress) throws Exception { 78 | throw new UnsupportedOperationException("Not supported to bind in a separate step"); 79 | } 80 | 81 | @Override 82 | public ChannelFuture shutdownInput() { 83 | if (closeFuture != null) { 84 | closeFuture = new XnioChannelCloseFuture(this); 85 | } 86 | channel.getSourceChannel().setCloseListener(closeFuture); 87 | try { 88 | channel.getSourceChannel().shutdownReads(); 89 | } catch (IOException e) { 90 | closeFuture.setError(e); 91 | } 92 | return closeFuture; 93 | } 94 | 95 | @Override 96 | public ChannelFuture shutdownInput(ChannelPromise channelPromise) { 97 | closeFuture = new XnioChannelPromiseCloseFuture(this, channelPromise); 98 | return shutdownInput(); 99 | } 100 | 101 | private final class XnioUnsafe extends AbstractXnioUnsafe { 102 | @Override 103 | public void connect(SocketAddress remoteAddress, SocketAddress localAddress, ChannelPromise promise) { 104 | if (!ensureOpen(promise)) { 105 | return; 106 | } 107 | 108 | final boolean wasActive = isActive(); 109 | XnioIoThread thread = ((XnioEventLoop) eventLoop()).ioThread(); 110 | IoFuture future; 111 | if (localAddress == null) { 112 | future = thread.openStreamConnection(remoteAddress, null, null, options.getMap()); 113 | } else { 114 | future = thread.openStreamConnection(localAddress, remoteAddress, null, null, options.getMap()); 115 | } 116 | 117 | promise.addListener(new ChannelFutureListener() { 118 | @Override 119 | public void operationComplete(ChannelFuture channelFuture) throws Exception { 120 | if (channelFuture.isSuccess()) { 121 | if (!wasActive && isActive()) { 122 | pipeline().fireChannelActive(); 123 | } 124 | } else { 125 | closeIfClosed(); 126 | } 127 | } 128 | }); 129 | 130 | future.addNotifier(new IoFuture.Notifier() { 131 | @Override 132 | public void notify(IoFuture ioFuture, ChannelPromise promise) { 133 | IoFuture.Status status = ioFuture.getStatus(); 134 | if (status== IoFuture.Status.DONE) { 135 | try { 136 | channel = ioFuture.get(); 137 | channel.getSourceChannel().getReadSetter().set(new ReadListener()); 138 | 139 | promise.setSuccess(); 140 | channel.getSourceChannel().resumeReads(); 141 | } catch (Throwable cause) { 142 | promise.setFailure(cause); 143 | } 144 | } else { 145 | Exception error; 146 | if (status == IoFuture.Status.FAILED) { 147 | error = ioFuture.getException(); 148 | } else { 149 | error = new CancellationException(); 150 | } 151 | promise.setFailure(error); 152 | } 153 | } 154 | }, promise); 155 | 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/org/xnio/netty/transport/XnioSocketChannelConfig.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.Options; 20 | 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.channel.DefaultChannelConfig; 23 | import io.netty.channel.MessageSizeEstimator; 24 | import io.netty.channel.RecvByteBufAllocator; 25 | import io.netty.channel.WriteBufferWaterMark; 26 | import io.netty.channel.socket.SocketChannelConfig; 27 | 28 | 29 | /** 30 | * @author Norman Maurer 31 | */ 32 | final class XnioSocketChannelConfig extends DefaultChannelConfig implements SocketChannelConfig { 33 | 34 | private final AbstractXnioSocketChannel channel; 35 | 36 | XnioSocketChannelConfig(AbstractXnioSocketChannel channel) { 37 | super(channel); 38 | this.channel = channel; 39 | } 40 | 41 | @Override 42 | public boolean isTcpNoDelay() { 43 | return channel.getOption(Options.TCP_NODELAY); 44 | } 45 | 46 | @Override 47 | public SocketChannelConfig setTcpNoDelay(boolean tcpNoDelay) { 48 | channel.setOption(Options.TCP_NODELAY, tcpNoDelay); 49 | return this; 50 | } 51 | 52 | @Override 53 | public int getSoLinger() { 54 | return 0; 55 | } 56 | 57 | @Override 58 | public SocketChannelConfig setSoLinger(int soLinger) { 59 | throw new UnsupportedOperationException(); 60 | } 61 | 62 | @Override 63 | public int getSendBufferSize() { 64 | return channel.getOption(Options.SEND_BUFFER); 65 | } 66 | 67 | @Override 68 | public SocketChannelConfig setSendBufferSize(int sendBufferSize) { 69 | channel.setOption(Options.SEND_BUFFER, sendBufferSize); 70 | return this; 71 | } 72 | 73 | @Override 74 | public int getReceiveBufferSize() { 75 | return channel.getOption(Options.RECEIVE_BUFFER); 76 | } 77 | 78 | @Override 79 | public SocketChannelConfig setReceiveBufferSize(int receiveBufferSize) { 80 | channel.setOption(Options.RECEIVE_BUFFER, receiveBufferSize); 81 | return this; 82 | } 83 | 84 | @Override 85 | public boolean isKeepAlive() { 86 | return channel.getOption(Options.KEEP_ALIVE); 87 | } 88 | 89 | @Override 90 | public SocketChannelConfig setKeepAlive(boolean keepAlive) { 91 | channel.setOption(Options.KEEP_ALIVE, keepAlive); 92 | return this; 93 | } 94 | 95 | @Override 96 | public int getTrafficClass() { 97 | return channel.getOption(Options.IP_TRAFFIC_CLASS); 98 | } 99 | 100 | @Override 101 | public SocketChannelConfig setTrafficClass(int trafficClass) { 102 | channel.setOption(Options.IP_TRAFFIC_CLASS, trafficClass); 103 | return this; 104 | } 105 | 106 | @Override 107 | public boolean isReuseAddress() { 108 | return channel.getOption(Options.REUSE_ADDRESSES); 109 | 110 | } 111 | 112 | @Override 113 | public SocketChannelConfig setReuseAddress(boolean reuseAddress) { 114 | channel.setOption(Options.REUSE_ADDRESSES, reuseAddress); 115 | return this; 116 | } 117 | 118 | @Override 119 | public SocketChannelConfig setPerformancePreferences(int connectionTime, int latency, int bandwidth) { 120 | throw new UnsupportedOperationException(); 121 | } 122 | 123 | @Override 124 | public boolean isAllowHalfClosure() { 125 | return false; 126 | } 127 | 128 | @Override 129 | public SocketChannelConfig setAllowHalfClosure(boolean allowHalfClosure) { 130 | throw new UnsupportedOperationException(); 131 | } 132 | 133 | @Override 134 | public SocketChannelConfig setConnectTimeoutMillis(int connectTimeoutMillis) { 135 | super.setConnectTimeoutMillis(connectTimeoutMillis); 136 | return this; 137 | } 138 | 139 | @Override @Deprecated 140 | public SocketChannelConfig setMaxMessagesPerRead(int maxMessagesPerRead) { 141 | super.setMaxMessagesPerRead(maxMessagesPerRead); 142 | return this; 143 | } 144 | 145 | @Override 146 | public SocketChannelConfig setWriteSpinCount(int writeSpinCount) { 147 | super.setWriteSpinCount(writeSpinCount); 148 | return this; 149 | } 150 | 151 | @Override 152 | public SocketChannelConfig setAllocator(ByteBufAllocator allocator) { 153 | super.setAllocator(allocator); 154 | return this; 155 | } 156 | 157 | @Override 158 | public SocketChannelConfig setRecvByteBufAllocator(RecvByteBufAllocator allocator) { 159 | super.setRecvByteBufAllocator(allocator); 160 | return this; 161 | } 162 | 163 | @Override 164 | public SocketChannelConfig setAutoRead(boolean autoRead) { 165 | super.setAutoRead(autoRead); 166 | return this; 167 | } 168 | 169 | @Override @Deprecated 170 | public SocketChannelConfig setWriteBufferHighWaterMark(int writeBufferHighWaterMark) { 171 | super.setWriteBufferHighWaterMark(writeBufferHighWaterMark); 172 | return this; 173 | } 174 | 175 | @Override 176 | public SocketChannelConfig setMessageSizeEstimator(MessageSizeEstimator estimator) { 177 | super.setMessageSizeEstimator(estimator); 178 | return this; 179 | } 180 | 181 | @Override @Deprecated 182 | public SocketChannelConfig setWriteBufferLowWaterMark(int writeBufferLowWaterMark) { 183 | super.setWriteBufferLowWaterMark(writeBufferLowWaterMark); 184 | return this; 185 | } 186 | 187 | @Override 188 | public SocketChannelConfig setWriteBufferWaterMark(WriteBufferWaterMark writeBufferWaterMark) { 189 | super.setWriteBufferWaterMark(writeBufferWaterMark); 190 | return this; 191 | } 192 | 193 | @Override 194 | public SocketChannelConfig setAutoClose(boolean autoClose) { 195 | super.setAutoClose(autoClose); 196 | return this; 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketEchoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketEchoTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public class XnioSocketEchoTest extends SocketEchoTest { 32 | @Override 33 | protected List newAllocators() { 34 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 35 | } 36 | 37 | @Override 38 | protected List> newFactories() { 39 | return XnioTestsuiteUtils.newFactories(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketFileRegionTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketFileRegionTest; 24 | 25 | 26 | import java.util.List; 27 | import org.junit.jupiter.api.Disabled; 28 | 29 | /** 30 | * 31 | * @author Norman Maurer 32 | */ 33 | @Disabled("Test hangs") 34 | public class XnioSocketFileRegionTest extends SocketFileRegionTest { 35 | @Override 36 | protected List newAllocators() { 37 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 38 | } 39 | 40 | @Override 41 | protected List> newFactories() { 42 | return XnioTestsuiteUtils.newFactories(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketFixedLengthEchoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketFixedLengthEchoTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public class XnioSocketFixedLengthEchoTest extends SocketFixedLengthEchoTest { 32 | @Override 33 | protected List newAllocators() { 34 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 35 | } 36 | 37 | @Override 38 | protected List> newFactories() { 39 | return XnioTestsuiteUtils.newFactories(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketGatheringWriteTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketGatheringWriteTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public class XnioSocketGatheringWriteTest extends SocketGatheringWriteTest { 32 | @Override 33 | protected List newAllocators() { 34 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 35 | } 36 | 37 | @Override 38 | protected List> newFactories() { 39 | return XnioTestsuiteUtils.newFactories(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketObjectEchoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketObjectEchoTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public class XnioSocketObjectEchoTest extends SocketObjectEchoTest { 32 | @Override 33 | protected List newAllocators() { 34 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 35 | } 36 | 37 | @Override 38 | protected List> newFactories() { 39 | return XnioTestsuiteUtils.newFactories(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketSslEchoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.util.List; 20 | 21 | import io.netty.bootstrap.Bootstrap; 22 | import io.netty.bootstrap.ServerBootstrap; 23 | import io.netty.buffer.ByteBufAllocator; 24 | import io.netty.testsuite.transport.TestsuitePermutation; 25 | import io.netty.testsuite.transport.socket.SocketSslEchoTest; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | * @author Flavia Rainone 31 | */ 32 | public class XnioSocketSslEchoTest extends SocketSslEchoTest { 33 | @Override 34 | protected List newAllocators() { 35 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 36 | } 37 | 38 | @Override 39 | protected List> newFactories() { 40 | return XnioTestsuiteUtils.newFactories(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketStartTlsTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketStartTlsTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | * @author Flavia Rainone 31 | */ 32 | public class XnioSocketStartTlsTest extends SocketStartTlsTest { 33 | 34 | @Override 35 | protected List newAllocators() { 36 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 37 | } 38 | 39 | @Override 40 | protected List> newFactories() { 41 | return XnioTestsuiteUtils.newFactories(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioSocketStringEchoTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.testsuite.transport.TestsuitePermutation; 23 | import io.netty.testsuite.transport.socket.SocketStringEchoTest; 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 29 | * @author Norman Maurer 30 | */ 31 | public class XnioSocketStringEchoTest extends SocketStringEchoTest { 32 | @Override 33 | protected List newAllocators() { 34 | return XnioTestsuiteUtils.newAllocators(super.newAllocators()); 35 | } 36 | 37 | @Override 38 | protected List> newFactories() { 39 | return XnioTestsuiteUtils.newFactories(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/test/java/org/xnio/netty/transport/XnioTestsuiteUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 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.bootstrap.Bootstrap; 20 | import io.netty.bootstrap.ServerBootstrap; 21 | import io.netty.buffer.ByteBufAllocator; 22 | import io.netty.channel.EventLoopGroup; 23 | import io.netty.testsuite.transport.TestsuitePermutation; 24 | import org.xnio.netty.buffer.XnioByteBufAllocator; 25 | 26 | import java.io.IOException; 27 | import java.util.ArrayList; 28 | import java.util.Collections; 29 | import java.util.List; 30 | import org.xnio.ByteBufferPool; 31 | 32 | /** 33 | * 34 | * @author Norman Maurer 35 | */ 36 | final class XnioTestsuiteUtils { 37 | private static final EventLoopGroup GROUP; 38 | 39 | static { 40 | try { 41 | GROUP = new XnioEventLoopGroup(); 42 | } catch (IOException e) { 43 | throw new IllegalStateException(e); 44 | } 45 | } 46 | 47 | static List newAllocators(List allocs) { 48 | List allocators = new ArrayList<>(allocs); 49 | allocators.add(new XnioByteBufAllocator(ByteBufferPool.LARGE_DIRECT)); 50 | return allocators; 51 | } 52 | 53 | static List> newFactories() { 54 | return Collections.>singletonList( 55 | new TestsuitePermutation.BootstrapComboFactory() { 56 | @Override 57 | public ServerBootstrap newServerInstance() { 58 | return new ServerBootstrap().channel(XnioServerSocketChannel.class).group(GROUP); 59 | } 60 | 61 | @Override 62 | public Bootstrap newClientInstance() { 63 | return new Bootstrap().channel(XnioSocketChannel.class).group(GROUP); 64 | } 65 | }); 66 | } 67 | 68 | private XnioTestsuiteUtils() { 69 | // utility 70 | } 71 | } 72 | --------------------------------------------------------------------------------