[ 
https://issues.apache.org/jira/browse/SSHD-975?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17077165#comment-17077165
 ] 

Robert Varga commented on SSHD-975:
-----------------------------------

This is OSGi runtime with Equinox. We have:
 * sshd-osgi.jar, which contains AbstractFactoryManager and SshClient
 * netty-util.jar, which contains NetconfSshClient, a subclass of SshClient 
(and therefore a subclass of AbstractFactoryManager)

Obviously, each of those jars has its own ClassLoader, and hence when 
AbstractFactoryManager calls getClass().getClassLoader(), it is an instance 
invocation, hence it results in either SshClient.class.getClassLoader() (i.e. 
sshd-osgi.jar) or NeconfSshClient.class.getClassLoader() (i.e. netty-util.jar).

netty-util.jar performs just some data shuffling, hence it does not interact 
with anything in org.apache.sshd.common.\{forward,util.net} packages, so it 
does not contain Import-Package OSGi MANIFEST.MF entries for those packages, 
hence PortForwardingEventListener and SshdSocketAddress cannot be resolved 
through it, which leads to the reported splat.

Now the Netty thing is a bit more convoluted: we are implementing a NETCONF 
(RFC6241) endpoint, which is defining its own SSH subsystem ("netconf"), i.e. 
sshd is used as a transport alternative to plain TCP sockets (or TLS). The 
protocol logic itself is implemented in terms of Netty handlers.

So what is going on here is that we are running SSHD with NIO2 to get the SSH 
session going, but once we establish the session, we open the "netconf" SSH 
subsystem and funnel any data on it to a Netty channel, which is wired with 
those handlers – hence the protocol implementation does not know nor care what 
the actual transport is (see (1) in 
[https://tools.ietf.org/html/rfc6241#page-9)]

Currently, we use plain SshClient async reads to achieve the funnelling, but 
that has three major downsides:
 * async read requires us to allocate an additional bounce buffer for each 
session
 * we have unnecessary queuing inside AbstractClientChannel, as we end up 
pushing the data away anyway
 * as we can have a large number (10000+ sessions), that bounce buffer is small 
(2KiB), which in turn causes fragmentation, which we need to reassemble at the 
Netty layer

So we have a prototype, which subclasses SshClient so that (through some 
ceremony) we end up with our own ClientChannel implementation, whose 
doWriteData() just moves the data from provided byte[] into a Netty ByteBuf and 
throws it into the the Netty pipeline for processing – minimizing buffering, 
fragmentation and latency, hopefully significantly improving performance.

> SshClient subclasses fail in OSGi environment
> ---------------------------------------------
>
>                 Key: SSHD-975
>                 URL: https://issues.apache.org/jira/browse/SSHD-975
>             Project: MINA SSHD
>          Issue Type: Bug
>    Affects Versions: 2.3.0, 2.4.0
>            Reporter: Robert Varga
>            Priority: Major
>          Time Spent: 10m
>  Remaining Estimate: 0h
>
> Attempting to subclass SshClient and use it in OSGi environment can fail with 
> the following:
> {noformat}
> 2020-04-07T07:46:19,968 | WARN  | nioEventLoopGroupCloseable-3-1 | 
> ChannelInitializer               | 64 - io.netty.common - 4.1.45.Final | 
> Failed to initialize a channel. Closing: [id: 0xfedebbf7]
> java.lang.ExceptionInInitializerError: null
>       at 
> org.opendaylight.netconf.client.SshClientChannelInitializer.initialize(SshClientChannelInitializer.java:43)
>  ~[402:org.opendaylight.netconf.client:1.9.0.SNAPSHOT]
>       at 
> org.opendaylight.netconf.nettyutil.ReconnectPromise.lambda$connect$0(ReconnectPromise.java:54)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]
>       at 
> org.opendaylight.netconf.nettyutil.AbstractNetconfDispatcher$3.initChannel(AbstractNetconfDispatcher.java:206)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]
>       at 
> org.opendaylight.netconf.nettyutil.AbstractNetconfDispatcher$3.initChannel(AbstractNetconfDispatcher.java:203)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]
>       at 
> io.netty.channel.ChannelInitializer.initChannel(ChannelInitializer.java:129) 
> [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.ChannelInitializer.handlerAdded(ChannelInitializer.java:112) 
> [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.AbstractChannelHandlerContext.callHandlerAdded(AbstractChannelHandlerContext.java:956)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.DefaultChannelPipeline.callHandlerAdded0(DefaultChannelPipeline.java:609)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.DefaultChannelPipeline.access$100(DefaultChannelPipeline.java:46)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.DefaultChannelPipeline$PendingHandlerAddedTask.execute(DefaultChannelPipeline.java:1463)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.DefaultChannelPipeline.callHandlerAddedForAllHandlers(DefaultChannelPipeline.java:1115)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.DefaultChannelPipeline.invokeHandlerAddedIfNeeded(DefaultChannelPipeline.java:650)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.AbstractChannel$AbstractUnsafe.register0(AbstractChannel.java:502)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.AbstractChannel$AbstractUnsafe.access$200(AbstractChannel.java:417)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.channel.AbstractChannel$AbstractUnsafe$1.run(AbstractChannel.java:474)
>  [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
>  [64:io.netty.common:4.1.45.Final]
>       at 
> io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
>  [64:io.netty.common:4.1.45.Final]
>       at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500) 
> [67:io.netty.transport:4.1.45.Final]
>       at 
> io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
>  [64:io.netty.common:4.1.45.Final]
>       at 
> io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) 
> [64:io.netty.common:4.1.45.Final]
>       at 
> io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
>  [64:io.netty.common:4.1.45.Final]
>       at java.lang.Thread.run(Thread.java:834) [?:?]
> Caused by: java.lang.IllegalArgumentException: 
> org.apache.sshd.common.forward.PortForwardingEventListener referenced from a 
> method is not visible from class loader
>       at java.lang.reflect.Proxy$ProxyBuilder.ensureVisible(Proxy.java:858) 
> ~[?:?]
>       at 
> java.lang.reflect.Proxy$ProxyBuilder.validateProxyInterfaces(Proxy.java:681) 
> ~[?:?]
>       at java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:627) ~[?:?]
>       at java.lang.reflect.Proxy$ProxyBuilder.<init>(Proxy.java:635) ~[?:?]
>       at java.lang.reflect.Proxy.lambda$getProxyConstructor$0(Proxy.java:415) 
> ~[?:?]
>       at 
> jdk.internal.loader.AbstractClassLoaderValue$Memoizer.get(AbstractClassLoaderValue.java:329)
>  ~[?:?]
>       at 
> jdk.internal.loader.AbstractClassLoaderValue.computeIfAbsent(AbstractClassLoaderValue.java:205)
>  ~[?:?]
>       at java.lang.reflect.Proxy.getProxyConstructor(Proxy.java:413) ~[?:?]
>       at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:1006) ~[?:?]
>       at 
> org.apache.sshd.common.util.EventListenerUtils.proxyWrapper(EventListenerUtils.java:193)
>  ~[144:org.apache.sshd.osgi:2.3.0]
>       at 
> org.apache.sshd.common.helpers.AbstractFactoryManager.<init>(AbstractFactoryManager.java:107)
>  ~[144:org.apache.sshd.osgi:2.3.0]
>       at org.apache.sshd.client.SshClient.<init>(SshClient.java:189) 
> ~[144:org.apache.sshd.osgi:2.3.0]
>       at 
> org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfSshClient.<init>(NetconfSshClient.java:19)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]
>       at org.apache.sshd.common.BaseBuilder.build(BaseBuilder.java:256) 
> ~[144:org.apache.sshd.osgi:2.3.0]
>       at org.apache.sshd.client.ClientBuilder.build(ClientBuilder.java:183) 
> ~[144:org.apache.sshd.osgi:2.3.0]
>       at org.apache.sshd.client.ClientBuilder.build(ClientBuilder.java:51) 
> ~[144:org.apache.sshd.osgi:2.3.0]
>       at org.apache.sshd.common.BaseBuilder.build(BaseBuilder.java:276) 
> ~[144:org.apache.sshd.osgi:2.3.0]
>       at 
> org.opendaylight.netconf.nettyutil.handler.ssh.client.NetconfClientBuilder.build(NetconfClientBuilder.java:23)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]
>       at 
> org.opendaylight.netconf.nettyutil.handler.ssh.client.AsyncSshHandler.<clinit>(AsyncSshHandler.java:45)
>  ~[420:org.opendaylight.netconf.netty-util:1.9.0.SNAPSHOT]{noformat}
>  
>  



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@mina.apache.org
For additional commands, e-mail: dev-h...@mina.apache.org

Reply via email to