sanketbajoria / ssh2-promise

ssh with promise/async await and typescript support
https://www.npmjs.com/package/ssh2-promise
MIT License
148 stars 24 forks source link

SSHConnections not closing properly and SSHConnection sharing uniqueIDs #88

Open dominusmars opened 8 months ago

dominusmars commented 8 months ago

I'm having an issue where I'm unable to close the SSH connections properly and I have to restart my application for them to close. My code keeps the ssh connection live for the duration of the application. I ran into an issue before that the socket for the SSH connection because unwritable but even when I .connect() its still unwritable. I fixed this by exec a command on the ssh and waiting to see if it crashes. here is my code for creating and maintaining the connections, I thought adding uniqueIDs would help because the connection that's there would have no ref and the gc would end it but it doesn't seem to work that way. I had a bunch of code here that's just me testing to see if it would remove the ref. but it doesn't.

this function gets executed every min to run the .exec("hostname") on the target computer to check if the socket is still writeable. If not it makes a new connection with the new ServerInfo.


async function makePermanentConnection(Server: ServerInfo, useKey?: boolean, statusLog = true, timeout = 3000): Promise<SSH2CONN | false> {
    let findConnection = servers_connections.get(Server["IP Address"]);
    try {
        if (!findConnection) {
            throw new Error("Connection doesn't exist");
        }
        await findConnection.exec("hostname");
        return findConnection;
    } catch (error) {
        statusLog && findConnection?.error(`Unable to connect, making new connection: ${error}`);
        connectionLog.log(`[${Server.Name}] [${Server["IP Address"]}] Event: ERROR ${error}`);

        findConnection?.removeAllListeners();
        try {
            await findConnection?.close();

        } catch (error) {
            connectionLog.log(`[${Server.Name}] [${Server["IP Address"]}] Event: unable to close  ${error}`);
        } finally {
        }
        findConnection && connectionLog.log("deleting connection: " + `[${Server.Name}] [${Server["IP Address"]}]`);

        servers_connections.delete(Server["IP Address"]);
    }
    try {
        const sshConfig: SSHConfig = {
            host: Server["IP Address"],
            username: Server.Username,
            password: Server.Password,
            privateKey: await runningDB.getPrivateSSHKey(),
            authHandler: useKey ? ["publickey", "password"] : ["password"],
            reconnect: true,
            keepaliveInterval: 6 * 1000,
            keepaliveCountMax: 999,
            reconnectTries: 3,
            readyTimeout: timeout,
            uniqueId: "Permanent" + Server["IP Address"] + Server.Username + Server.Name
        };
        const ssh = new SSH2CONN(Server.Name, sshConfig);
        statusLog && ssh.log("Attempting Connection");
        await ssh.connect();
        ssh.on("ssh", async (e) => {
            connectionLog.log(`[${ssh.config[0].host}] [${Server.Name}] Event: ${e}`);
        });
        ssh.on("close", async () => {
            connectionLog.log(`[${ssh.config[0].host}] [${Server.Name}] Event: Closed Connections`);
        });

        ssh.on(SSH2CONN.errorMonitor, (err) => {
            connectionLog.log(`[${ssh.config[0].host}] [${Server.Name}] Event: ERROR ${err}`);
        });
        statusLog && ssh.log("Connected");
        servers_connections.set(Server["IP Address"], ssh);

        return ssh;
    } catch (error) {
        statusLog && log(`[${Server["IP Address"]}] [${Server.Name}] Unable to connect: ${error}`, "error");
        logger.log(`[${Server["IP Address"]}] [${Server.Name}] Unable to connect: ${error}`, "error");
        return false;
    }
}

The good news is no more than the required amount of SSH2Promises are being made. Its the SSHConnection class that isnt being stopped or ended?. Note: SSH2CONN is just a wrapper I made to do Logging.

image image image