Getting [Bad Use Error] when trying to read/write for two different sessions parallely
Closed this issue · 7 comments
Hi @volks73,
Within the same application instance, I would like to maintain two Sessions in different loops. It is observed when we try to read/write to channels of different sessions in parallel, the lib throws below error.
Error -8142 occurred at Field_RnD_Services_LIBSSH2_Toolkit.lvlib:Channel.lvclass:Read.vi
Possible reason(s):
[Bad Use Error]
I tried creating single session and passed the ref to other loop where only channel would be created and closed. Alternatively, tried creating different sessions and channels in parallel. There is no issue while creating session/ channel in parallel but when there is write or read operation occurring in parallel, the issue crops up.
Your feedback on this would be great.
Thanks
update: I went ahead and initialized the lib in the parallel process as well and it worked without error. I was of the understanding that within a application instance we must use the initialize lib function at the start of the app and shutdown lib function at the app shutdown sequence. So I decided to initialize and create session at one place and handle channel create and destroy randomly on need basis, this approach was leading to the [Bad Use Error]
Can you please help me answer the below questions;
- Is it safe to initialize and shutdown the the lib in different processes within the same application instance?
2.. Can't we create multiple sessions or multiple channels from a single session by passing references around?
Thanks
- Is it safe to initialize and shutdown the the lib in different processes within the same application instance?
Yes. You should only have to initialize and shutdown once within an application instance (My Computer or Real-Time Target, for example). However, if you are talking about two separate executables built from the same project, then each executable must initialization/shutdown. If you cannot create multiple sessions from one initialization/shutdown pair, then this is a bug or I have misunderstood the LIBSSH2 documentation.
- Can't we create multiple sessions or multiple channels from a single session by passing references around?
I have to look back into this because it has been awhile and distracted, but no I don't think you can create multiple sessions from a single session. Each session is a distinct TCP connection that is "elevated" to a secure connection. Similar to how it is not possible to create a new TCP connection from an existing TCP connection, it is not possible to create a Session from an existing Session.
As for multiple channels from a single session, I would think this is possible but maybe not recommended. I have to look back into the code and review the documentation for the LIBSSH2 C library. This may also depend on what you are trying to accomplish.
I cannot commitment to any kind of schedule, but I will try to obtain more definitive answers this weekend. In the mean time, do you have an example VI/snippet you can share demonstrating what has and has not worked?
@temin4u I have pushed an update that includes a new example for "Multiple Sessions with a Raspberry Pi". Note, it does not have to be a Raspberry Pi, it is just what I used to create the example and it is a relatively inexpensive SSH server that is good for testing and debugging.
If you look at the block diagram for the example, then you will see I found creating parallel sessions is not straightforward. You do only need to initialize and shutdown once, but the connecting and authentication should happen in series. The rest of the implementation can occur in parallel. I also had to increase the timeout from 500 ms to 1000 ms as sometimes the channels would timeout. I think multiple connections to the same port (22) could be causing some congestion issue.
The parallel sessions are all in one VI for the example. I think you are trying to have multiple parallel VIs with multiple sessions. In this case you, can use a single Initialize but must pass the SSH wire/object to the parallel VIs, then create the sessions in parallel. I am not sure if you could connect and authenticate in parallel. I would initialize, create two sessions, connect and authenticate each session in series, then pass the Session objects for each session to the parallel VIs. If using the VI server to dynamically call the VIs, then you will need to signal the calling VI when both VIs are completed and call the Shutdown VI only once.
If you want both VIs to be truly independent and run as separate OS processes, then you will need to initialize and shutdown within each process/VI.
You cannot pass around Channel objects. You can split them into read/write halves, but you cannot create separate channels for an already established channel. Same for creating a session from an already created session. I think it is easier to think of sessions and channels as just TCP connections. You cannot create a new TCP connection from an existing connection. You much use the TCP Connect function for each TCP reference. This is the same for sessions and channel.
Could you provide a little more context on what you are trying to achieve? Parallel VIs, multiple TCP connections, etc. is all very complex and typically this type of complexity is not needed. Also, please keep in mind the libssh2 library and this LabVIEW library are not really intended to be full-blown SSH shells. These libraries are more for "get in and get out" type of tasks.
I don't think there is a bug related to these questions and issue. Spawning parallel sessions and multiple channels from a single session does not appear to be supported in the libssh2 library; thus, it is not supported in this library. I tried to enforce this restriction through the various class hierarchies and composition.
I don't think there is a bug related to these questions and issue. Spawning parallel sessions and multiple channels from a single session does not appear to be supported in the libssh2 library; thus, it is not supported in this library. I tried to enforce this restriction through the various class hierarchies and composition.
@volks73 sorry for the late response. I believe your last comment is inline with my current understanding.
Background is I thought of having 3 parallel while loops(processes).One master process basically manages the SSH and Session objects(creating and destroying). Intention was if I can pass the session object to other processes, they will use it to manage their own channel objects(create and destroy on need basis).
case 1, when I created multiple channels from a single session, when parallel read occurs, I encountered the [Bad Use Error].
case 2, I modified the master process to manage only the SSH object, I tried creating two independent sessions from the SSH object passed by master process. still I got errors( not sure if the same error as before).
case 3, Got rid of the master loop, Managed all the SSH, Session, Channel objects independently in both the loops. Found it to be working fine without any issues.
Now to quote my initial question
Is it safe to initialize and shutdown the the lib in different loops (processes) within the same application instance?
I'm assuming if I call the Initialize API in the parallel loops to create a SSH object , new memory will be allocated for each call and it should not have any adverse effects on the overall application. Please advice on the same.
P.S the need for two loops(process) is that one will be used to tail -f a file for a given time period and the other will be primarily used for "get in and get out" task. there is a need that both may be required at a given point of time.
@temin4u Thank you for the information and update.
I'm assuming if I call the Initialize API in the parallel loops to create a SSH object , new memory will be allocated for each call and it should not have any adverse effects on the overall application. Please advice on the same.
Yes, you can use the initialize API multiple times within an application, you just should do it in a single thread (which I have already ensured and handled for you within the library) as the underlying libssh2 C function is not thread safe. This will allocate double the memory and the underlying cryptography library will be independently seeded.
There should be no issues with multiple Initialize calls, but best practice would be to initialize once and branch the SSH object wire to create two separate sessions. I would possibly recommend wrapping the SSH object in a Functional Global Variable (FGV) that could be passed around between parallel loops to create different sessions and then shutdown at a single location in your application. This would avoid the double memory allocation and multiple seeds. However, this is a possible micro-optimization and/or style recommendation, so please implement in whatever manner best fits your style and constraints.
It looks like the question has been answered. I am going to close this issue.