14 #include <mx/sys/timeUtils.hpp>
16 #include "../../libMagAOX/libMagAOX.hpp"
17 #include "../../magaox_git_version.h"
33 #define SSHDIGGER_E_NOTUNNELS (-10)
34 #define SSHDIGGER_E_NOTUNNELFOUND (-11)
35 #define SSHDIGGER_E_NOHOSTNAME (-12)
36 #define SSHDIGGER_E_NOLOCALPORT (-13)
37 #define SSHDIGGER_E_NOREMOTEPORT (-14)
125 void genArgsV( std::vector<std::string> & argsV );
128 void genEnvp( std::vector<std::string> & envp );
190 m_requireConfigPathLocal =
false;
202 std::vector<std::string> sections;
204 _config.unusedSections(sections);
206 if( sections.size() == 0 )
216 for(
size_t i=0;i<sections.size(); ++i)
260 for(
size_t i=0;i<sections.size(); ++i)
262 if( sections[i] ==
"")
continue;
265 _config.configUnused(rh, mx::app::iniFile::makeKey(sections[i],
"remoteHost" ) );
268 log<text_log>(
"Config section [" + sections[i] +
"] may be an invalid tunnel configuration (no remoteHost).",
logPrio::LOG_WARNING);
271 _config.configUnused(lp, mx::app::iniFile::makeKey(sections[i],
"localPort" ) );
274 log<text_log>(
"Config section [" + sections[i] +
"] may be an invalid tunnel configuration (no localPort).",
logPrio::LOG_WARNING);
277 _config.configUnused(rp, mx::app::iniFile::makeKey(sections[i],
"remotePort" ) );
280 log<text_log>(
"Config section [" + sections[i] +
"] may be an invalid tunnel configuration (no remotePort).",
logPrio::LOG_WARNING);
283 _config.configUnused( mp, mx::app::iniFile::makeKey(sections[i],
"monitorPort" ) );
285 _config.configUnused( cmp, mx::app::iniFile::makeKey(sections[i],
"compress" ) );
298 std::string ts = mx::ioutils::convertToString(
m_localPort) +
":localhost:" + mx::ioutils::convertToString(
m_remotePort);
305 std::string comp =
"";
319 std::vector<std::string> argsV;
322 std::vector<std::string> envps;
327 std::string coml =
"Starting autossh with command: ";
328 for(
size_t i=0;i<argsV.size();++i)
337 if (pipe(filedes) == -1)
339 log<software_error>({__FILE__, __LINE__, errno});
347 log<software_error>({__FILE__, __LINE__, errno, std::string(
"fork failed: ") + strerror(errno)});
354 while ((dup2(filedes[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}
358 const char ** args =
new const char*[argsV.size() + 1];
359 for(
size_t i=0; i< argsV.size();++i) args[i] = argsV[i].data();
360 args[argsV.size()] = NULL;
363 const char ** envp =
new const char*[envps.size() + 1];
364 for(
size_t i=0; i< envps.size();++i) envp[i] = envps[i].data();
365 envp[envps.size()] = NULL;
367 execvpe(
"autossh", (
char *
const*) args, (
char *
const*) envp);
370 log<software_error>({__FILE__, __LINE__, errno, std::string(
"execvp returned: ") + strerror(errno)});
384 std::string coml =
"autossh tunnel started with PID " + mx::ioutils::convertToString(
m_tunnelPID);
403 catch(
const std::exception & e )
405 log<software_error>({__FILE__,__LINE__, std::string(
"Exception on ssh log thread start: ") + e.what()});
410 log<software_error>({__FILE__,__LINE__,
"Unkown exception on ssh log thread start"});
416 log<software_error>({__FILE__, __LINE__,
"ssh log thread did not start"});
423 int rv = pthread_setschedparam(
m_sshLogThread.native_handle(), SCHED_OTHER, &sp);
427 log<software_error>({__FILE__, __LINE__, rv,
"Error setting thread params."});
443 ssize_t count = read(
m_sshSTDERR, buffer,
sizeof(buffer)-1);
450 buffer[count] =
'\0';
455 if(logs.back() ==
'\n')
458 while(bol < logs.size())
460 size_t eol = logs.find(
'\n', bol);
461 if(eol == std::string::npos)
break;
478 if(logs.find(
"bind: Address already in use") != std::string::npos)
484 if(logs.find(
"channel_setup_fwd_listener_tcpip: cannot listen to port:") != std::string::npos)
490 if(logs.find(
"connect failed:") != std::string::npos)
520 catch(
const std::exception & e )
522 log<software_error>({__FILE__,__LINE__, std::string(
"Exception on autossh log thread start: ") + e.what()});
527 log<software_error>({__FILE__,__LINE__,
"Unkown exception on autossh log thread start"});
533 log<software_error>({__FILE__, __LINE__,
"autossh log thread did not start"});
540 int rv = pthread_setschedparam(
m_autosshLogThread.native_handle(), SCHED_OTHER, &sp);
544 log<software_error>({__FILE__, __LINE__, rv,
"Error setting thread params."});
567 log<software_error>({__FILE__, __LINE__, errno});
568 log<software_error>({__FILE__, __LINE__,
"unable to open auto ssh log fifo"});
584 buffer[count] =
'\0';
589 if(logs.back() ==
'\n')
592 while(bol < logs.size())
594 size_t eol = logs.find(
'\n', bol);
595 if(eol == std::string::npos)
break;
623 log<software_critical>({__FILE__, __LINE__, errno});
624 log<software_critical>({__FILE__, __LINE__,
"unable to create autossh log fifo"});
631 log<software_critical>({__FILE__,__LINE__});
637 log<software_critical>({__FILE__, __LINE__});
643 log<software_critical>({__FILE__, __LINE__});
661 log<text_log>(
"sending SIGUSR1 to restart ssh");
675 pid_t exited = waitpid(
m_tunnelPID, &status, WNOHANG);
679 log<text_log>(
"autossh exited, restarting.");
687 log<software_error>({__FILE__, __LINE__, errno });
688 log<software_error>({__FILE__, __LINE__,
"Error on write to ssh log thread. restart failed."});
695 log<software_critical>({__FILE__,__LINE__,
"restart of tunnel failed."});
702 log<software_critical>({__FILE__, __LINE__,
"restart of ssh log thread failed."});
722 log<software_error>({__FILE__, __LINE__, errno });
723 log<software_error>({__FILE__, __LINE__,
"Error on write to ssh log thread. Sending SIGTERM."});
The base-class for MagAO-X applications.
std::string m_configName
The name of the configuration file (minus .conf).
stateCodes::stateCodeT state()
Get the current state code.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
pid_t m_pid
This process's PID.
std::string m_configBase
The name of a base config class for this app (minus .conf).
The MagAO-X SSH tunnel manager.
~sshDigger() noexcept
D'tor, declared and defined for noexcept.
std::thread m_sshLogThread
A separate thread for capturing ssh logs.
int m_autosshLogThreadPrio
Priority of the autossh log capture thread, should normally be 0.
int sshLogThreadStart()
Start the log capture.
virtual int appLogic()
Implementation of the FSM for sshDigger.
int m_sshSTDERR_input
The input end of stderr, used to wake up the log thread on shutdown.
int execTunnel()
Creates the tunnel in a child process using exec.
std::string m_remoteHost
The name of the remote host.
static void _sshLogThreadStart(sshDigger *s)
Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
int m_localPort
The local port to forward from.
int m_tunnelPID
The PID of the autossh process.
void autosshLogThreadExec()
Execute the log capture.
int processSSHLog(const std::string &logs)
Process a log entry from indiserver, putting it into MagAO-X standard form.
static void _autosshLogThreadStart(sshDigger *s)
Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
int m_autosshLogFD
File descriptor of the autossh logfile.
int m_sshLogThreadPrio
Priority of the ssh log capture thread, should normally be 0.
std::string m_lastSSHLogs
int m_remotePort
The remote port to forward to.
int m_sshSTDERR
The output of stderr of the ssh process.
int m_monitorPort
The monitor port.
void sshLogThreadExec()
Execute the log capture.
int autosshLogThreadStart()
Start the log capture.
virtual int appShutdown()
Shutdown the app.
virtual int appStartup()
Startup function.
sshDigger()
Default c'tor.
virtual void setupConfig()
int processAutoSSHLog(const std::string &logs)
Process a log entry from indiserver, putting it into MagAO-X standard form.
int m_sshError
Flag to signal when ssh logs an error, and should be restarted via SIGUSR1 to autossh.
void genEnvp(std::vector< std::string > &envp)
Generate the envp vector for the exec of autossh.
std::string tunnelSpec()
Create the tunnel specification string, [localPort]:localhost:[remotePort].
void genArgsV(std::vector< std::string > &argsV)
Generate the argv vector for the exec of autossh.
std::string m_autosshLogFile
Name of the autossh logfile.
virtual void loadConfig()
std::thread m_autosshLogThread
A separate thread for capturing autossh logs.
bool m_compress
Control compression on this tunnel. True is on, false is off.
int8_t logPrioT
The type of the log priority code.
@ CONNECTED
The application has connected to the device or service.
@ NOTCONNECTED
The application is not connected to the device or service.
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
constexpr static logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
#define SSHDIGGER_E_NOLOCALPORT
#define SSHDIGGER_E_NOTUNNELFOUND
#define SSHDIGGER_E_NOREMOTEPORT
#define SSHDIGGER_E_NOHOSTNAME
#define SSHDIGGER_E_NOTUNNELS
void log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry, including a message.
int logLevel(logPrioT newLev)
Set a new value of logLevel.
A simple text log, a string-type log.