API
sshDigger.hpp
Go to the documentation of this file.
1 /** \file sshDigger.hpp
2  * \brief The MagAO-X SSH tunnel manager
3  *
4  * \ingroup sshDigger_files
5  */
6 
7 #ifndef sshDigger_hpp
8 #define sshDigger_hpp
9 
10 #include <sys/wait.h>
11 
12 #include <iostream>
13 
14 #include <mx/sys/timeUtils.hpp>
15 
16 #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
17 #include "../../magaox_git_version.h"
18 
19 /** \defgroup sshDigger SSH Tunnel Manager
20  * \brief Manage the SSH tunnels for MagAO-X communications..
21  *
22  * <a href="../handbook/operating/software/apps/sshDigger.html">Application Documentation</a>
23  *
24  * \ingroup apps
25  *
26  */
27 
28 /** \defgroup sshDigger_files SSH Tunnel Files
29  * \ingroup sshDigger
30  */
31 
32 //Return codes, these are primarily for testing purposes
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)
38 
39 namespace MagAOX
40 {
41 namespace app
42 {
43 
44 /// The MagAO-X SSH tunnel manager
45 /** Each instance of this app manages one SSH tunnel to another computer.
46  * These tunnels are opened via the `autossh` app, which itself calls `ssh`.
47  *
48  *
49  * \todo add options for verboseness of ssh and autossh (loglevel)
50  * \todo add options for ssh and autossh log thread priorities
51  *
52  * \ingroup sshDigger
53  */
54 class sshDigger : public MagAOXApp<false>
55 {
56 
57  //Give the test harness access.
58  friend class sshDigger_test;
59 
60 protected:
61 
62  /** \name Configurable Parameters
63  *@{
64  */
65  std::string m_remoteHost; ///< The name of the remote host
66  int m_localPort {0}; ///< The local port to forward from
67  int m_remotePort {0}; ///< The remote port to forward to
68  int m_monitorPort {0}; ///< The monitor port
69  bool m_compress {false}; ///< Control compression on this tunnel. True is on, false is off.
70  ///@}
71 
72  int m_tunnelPID {0}; ///< The PID of the autossh process
73 
74  /** \name ssh log capture
75  * @{
76  */
77  int m_sshSTDERR {-1}; ///< The output of stderr of the ssh process
78  int m_sshSTDERR_input {-1}; ///< The input end of stderr, used to wake up the log thread on shutdown.
79 
80  int m_sshLogThreadPrio {0}; ///< Priority of the ssh log capture thread, should normally be 0.
81 
82  std::thread m_sshLogThread; ///< A separate thread for capturing ssh logs
83 
84  std::string m_lastSSHLogs;
85  int m_sshError {0}; ///< Flag to signal when ssh logs an error, and should be restarted via SIGUSR1 to autossh.
86 
87  ///@}
88 
89  /** \name autossh log capture
90  * @{
91  */
92  std::string m_autosshLogFile; ///< Name of the autossh logfile.
93  int m_autosshLogFD {0}; ///< File descriptor of the autossh logfile.
94 
95  int m_autosshLogThreadPrio {0}; ///< Priority of the autossh log capture thread, should normally be 0.
96 
97  std::thread m_autosshLogThread; ///< A separate thread for capturing autossh logs
98  ///@}
99 
100 
101 public:
102  /// Default c'tor.
103  sshDigger();
104 
105  /// D'tor, declared and defined for noexcept.
106  ~sshDigger() noexcept
107  {}
108 
109  virtual void setupConfig();
110 
111  /// Implementation of loadConfig logic, separated for testing.
112  /** This is called by loadConfig().
113  */
114  int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
115 
116  virtual void loadConfig();
117 
118  /// Create the tunnel specification string, [localPort]:localhost:[remotePort].
119  /**
120  * \returns a string containing the tunnel specification.
121  */
122  std::string tunnelSpec();
123 
124  /// Generate the argv vector for the exec of autossh.
125  void genArgsV( std::vector<std::string> & argsV /**< [out] will contain the argv vector for an autssh exec call */);
126 
127  /// Generate the envp vector for the exec of autossh.
128  void genEnvp( std::vector<std::string> & envp /**< [out] will contain the envp vector for an autssh exec call */);
129 
130  /// Creates the tunnel in a child process using exec.
131  int execTunnel();
132 
133  ///Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
134  static void _sshLogThreadStart( sshDigger * s /**< [in] a pointer to an sshDigger instance (normally this) */);
135 
136  /// Start the log capture.
137  int sshLogThreadStart();
138 
139  /// Execute the log capture.
140  void sshLogThreadExec();
141 
142  /// Process a log entry from indiserver, putting it into MagAO-X standard form
143  int processSSHLog( const std::string & logs );
144 
145  ///Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
146  static void _autosshLogThreadStart( sshDigger * s /**< [in] a pointer to an sshDigger instance (normally this) */);
147 
148  /// Start the log capture.
149  int autosshLogThreadStart();
150 
151  /// Execute the log capture.
152  void autosshLogThreadExec();
153 
154  /// Process a log entry from indiserver, putting it into MagAO-X standard form
155  int processAutoSSHLog( const std::string & logs );
156 
157  /// Startup function
158  /**
159  *
160  */
161  virtual int appStartup();
162 
163  /// Implementation of the FSM for sshDigger.
164  /** Monitors status of m_sshError flag, and sends a signal to autossh if an error is indicated.
165  *
166  * Checks that autossh is still alive, and if it has died restarts it.
167  *
168  * \returns 0 on no critical error
169  * \returns -1 on an error requiring shutdown
170  */
171  virtual int appLogic();
172 
173  /// Shutdown the app.
174  /** Sends SIGTERM to autossh.
175  *
176  * Tells the two logging threads to exit, and waits for them to complete.
177  *
178  */
179  virtual int appShutdown();
180 
181 
182 };
183 
184 sshDigger::sshDigger() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
185 {
186  //Use the sshTunnels.conf config file
187  m_configBase = "sshTunnels";
188 
189  //set mx::app::application flag to not report lack of config file for this app.
190  m_requireConfigPathLocal = false;
191 
192  return;
193 }
194 
196 {
197 }
198 
199 int sshDigger::loadConfigImpl( mx::app::appConfigurator & _config )
200 {
201 
202  std::vector<std::string> sections;
203 
204  _config.unusedSections(sections);
205 
206  if( sections.size() == 0 )
207  {
208  log<text_log>("No tunnels found in config.", logPrio::LOG_CRITICAL);
209 
210  return SSHDIGGER_E_NOTUNNELS;
211  }
212 
213  //Now see if any sections match our m_configName
214 
215  bool found =false;
216  for(size_t i=0;i<sections.size(); ++i)
217  {
218  if( sections[i] == m_configName )
219  {
220  found = true;
221  }
222  }
223 
224  if( found == false )
225  {
226  log<text_log>("No matching tunnel configuration found.", logPrio::LOG_CRITICAL);
228  }
229 
230  //Now we configure the tunnel.
231 
232  _config.configUnused( m_remoteHost, mx::app::iniFile::makeKey(m_configName, "remoteHost" ) );
233  if( m_remoteHost == "" )
234  {
235  log<text_log>("No remote host specified.", logPrio::LOG_CRITICAL);
236  return SSHDIGGER_E_NOHOSTNAME;
237  }
238 
239  _config.configUnused( m_localPort, mx::app::iniFile::makeKey(m_configName, "localPort" ) );
240  if( m_localPort == 0 )
241  {
242  log<text_log>("No local port specified.", logPrio::LOG_CRITICAL);
243 
245  }
246 
247  _config.configUnused( m_remotePort, mx::app::iniFile::makeKey(m_configName, "remotePort" ) );
248  if( m_remotePort == 0 )
249  {
250  log<text_log>("No remote port specified.", logPrio::LOG_CRITICAL);
251 
253  }
254 
255  _config.configUnused( m_monitorPort, mx::app::iniFile::makeKey(m_configName, "monitorPort" ) );
256 
257  _config.configUnused( m_compress, mx::app::iniFile::makeKey(m_configName, "compress" ) );
258 
259  //Here we go through and access each unused config just to avoid the critical error for unrecognized configs.
260  for(size_t i=0;i<sections.size(); ++i)
261  {
262  if( sections[i] == "") continue; //this is an error
263  if( sections[i] == m_configName ) continue; //already done.
264  std::string rh;
265  _config.configUnused(rh, mx::app::iniFile::makeKey(sections[i], "remoteHost" ) );
266  if( rh == "" )
267  {
268  log<text_log>( "Config section [" + sections[i] + "] may be an invalid tunnel configuration (no remoteHost).", logPrio::LOG_WARNING);
269  }
270  int lp=0;
271  _config.configUnused(lp, mx::app::iniFile::makeKey(sections[i], "localPort" ) );
272  if( lp == 0 )
273  {
274  log<text_log>( "Config section [" + sections[i] + "] may be an invalid tunnel configuration (no localPort).", logPrio::LOG_WARNING);
275  }
276  int rp = 0;
277  _config.configUnused(rp, mx::app::iniFile::makeKey(sections[i], "remotePort" ) );
278  if( rp == 0 )
279  {
280  log<text_log>( "Config section [" + sections[i] + "] may be an invalid tunnel configuration (no remotePort).", logPrio::LOG_WARNING);
281  }
282  int mp = 0;
283  _config.configUnused( mp, mx::app::iniFile::makeKey(sections[i], "monitorPort" ) );
284  bool cmp = false;
285  _config.configUnused( cmp, mx::app::iniFile::makeKey(sections[i], "compress" ) );
286  }
287 
288  return 0;
289 }
290 
292 {
293  loadConfigImpl(config);
294 }
295 
297 {
298  std::string ts = mx::ioutils::convertToString(m_localPort) + ":localhost:" + mx::ioutils::convertToString(m_remotePort);
299 
300  return ts;
301 }
302 
303 void sshDigger::genArgsV( std::vector<std::string> & argsV )
304 {
305  std::string comp = "";
306  if(m_compress) comp = "-C";
307  argsV = {"autossh", "-M" + std::to_string(m_monitorPort), comp, "-nNTL", tunnelSpec(), m_remoteHost};
308 }
309 
310 void sshDigger::genEnvp( std::vector<std::string> & envp )
311 {
312  std::string logenv="AUTOSSH_LOGFILE=" + m_autosshLogFile;
313 
314  envp = {logenv};
315 }
316 
318 {
319  std::vector<std::string> argsV;
320  genArgsV(argsV);
321 
322  std::vector<std::string> envps;
323  genEnvp(envps);
324 
326  {
327  std::string coml = "Starting autossh with command: ";
328  for(size_t i=0;i<argsV.size();++i)
329  {
330  coml += argsV[i];
331  coml += " ";
332  }
333  log<text_log>(coml);
334  }
335 
336  int filedes[2];
337  if (pipe(filedes) == -1)
338  {
339  log<software_error>({__FILE__, __LINE__, errno});
340  return -1;
341  }
342 
343  m_tunnelPID = fork();
344 
345  if(m_tunnelPID < 0)
346  {
347  log<software_error>({__FILE__, __LINE__, errno, std::string("fork failed: ") + strerror(errno)});
348  return -1;
349  }
350 
351  if(m_tunnelPID == 0)
352  {
353  //Route STDERR of child to pipe input.
354  while ((dup2(filedes[1], STDERR_FILENO) == -1) && (errno == EINTR)) {}
355  close(filedes[1]);
356  close(filedes[0]);
357 
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;
361 
362 
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;
366 
367  execvpe("autossh", (char * const*) args, (char * const*) envp);
368 
369  std::cerr << "returned\n";
370  log<software_error>({__FILE__, __LINE__, errno, std::string("execvp returned: ") + strerror(errno)});
371 
372  delete[] args;
373 
374  return -1;
375  }
376 
377 
378 
379  m_sshSTDERR = filedes[0];
380  m_sshSTDERR_input = filedes[1];
381 
383  {
384  std::string coml = "autossh tunnel started with PID " + mx::ioutils::convertToString(m_tunnelPID);
385  log<text_log>(coml);
386  }
387  return 0;
388 }
389 
390 inline
392 {
393  s->sshLogThreadExec();
394 }
395 
396 inline
398 {
399  try
400  {
401  m_sshLogThread = std::thread( _sshLogThreadStart, this);
402  }
403  catch( const std::exception & e )
404  {
405  log<software_error>({__FILE__,__LINE__, std::string("Exception on ssh log thread start: ") + e.what()});
406  return -1;
407  }
408  catch( ... )
409  {
410  log<software_error>({__FILE__,__LINE__, "Unkown exception on ssh log thread start"});
411  return -1;
412  }
413 
414  if(!m_sshLogThread.joinable())
415  {
416  log<software_error>({__FILE__, __LINE__, "ssh log thread did not start"});
417  return -1;
418  }
419 
420  sched_param sp;
421  sp.sched_priority = m_sshLogThreadPrio;
422 
423  int rv = pthread_setschedparam( m_sshLogThread.native_handle(), SCHED_OTHER, &sp);
424 
425  if(rv != 0)
426  {
427  log<software_error>({__FILE__, __LINE__, rv, "Error setting thread params."});
428  return -1;
429  }
430 
431  return 0;
432 
433 }
434 
435 inline
437 {
438  char buffer[4096];
439 
440  std::string logs;
441  while(m_shutdown == 0 && m_sshSTDERR > 0)
442  {
443  ssize_t count = read(m_sshSTDERR, buffer, sizeof(buffer)-1);
444  if (count <= 0)
445  {
446  continue;
447  }
448  else
449  {
450  buffer[count] = '\0';
451 
452  logs += buffer;
453 
454  //Keep reading until \n found, then process.
455  if(logs.back() == '\n')
456  {
457  size_t bol = 0;
458  while(bol < logs.size())
459  {
460  size_t eol = logs.find('\n', bol);
461  if(eol == std::string::npos) break;
462 
463  processSSHLog(logs.substr(bol, eol-bol));
464  bol = eol + 1;
465  }
466  logs = "";
467  }
468  }
469  }
470 
471 }
472 
473 inline
474 int sshDigger::processSSHLog( const std::string & logs )
475 {
477 
478  if(logs.find("bind: Address already in use") != std::string::npos)
479  {
480  lp = logPrio::LOG_ERROR;
481  m_sshError = 1; //Means we'll need a restart
482  }
483 
484  if(logs.find("channel_setup_fwd_listener_tcpip: cannot listen to port:") != std::string::npos)
485  {
486  lp = logPrio::LOG_ERROR;
487  m_sshError = 1; //Means we'll need a restart
488  }
489 
490  if(logs.find("connect failed:") != std::string::npos)
491  {
492  lp = logPrio::LOG_ERROR;
493  m_sshError = 2;
494  }
495 
496  if(logs != m_lastSSHLogs)
497  {
498  m_log.log<text_log>({"SSH: " + logs}, lp);
499  m_lastSSHLogs = logs;
500  }
501 
502  return 0;
503 }
504 
505 
506 inline
508 {
510 }
511 
512 inline
514 {
515  try
516  {
517  m_autosshLogThread = std::thread( _autosshLogThreadStart, this);
518  }
519 
520  catch( const std::exception & e )
521  {
522  log<software_error>({__FILE__,__LINE__, std::string("Exception on autossh log thread start: ") + e.what()});
523  return -1;
524  }
525  catch( ... )
526  {
527  log<software_error>({__FILE__,__LINE__, "Unkown exception on autossh log thread start"});
528  return -1;
529  }
530 
531  if(!m_autosshLogThread.joinable())
532  {
533  log<software_error>({__FILE__, __LINE__, "autossh log thread did not start"});
534  return -1;
535  }
536 
537  sched_param sp;
538  sp.sched_priority = m_autosshLogThreadPrio;
539 
540  int rv = pthread_setschedparam( m_autosshLogThread.native_handle(), SCHED_OTHER, &sp);
541 
542  if(rv != 0)
543  {
544  log<software_error>({__FILE__, __LINE__, rv, "Error setting thread params."});
545  return -1;
546  }
547 
548  return 0;
549 
550 }
551 
552 inline
554 {
555  char buffer[4096];
556 
557  //Open the FIFO
558  m_autosshLogFD = 0;
559 
560  //We currently aren't monitoring this thread status, so we might as well retry if there is an error
561  while(m_autosshLogFD <= 0)
562  {
563  m_autosshLogFD = open(m_autosshLogFile.c_str(), O_RDONLY);
564 
565  if( m_autosshLogFD < 0 )
566  {
567  log<software_error>({__FILE__, __LINE__, errno});
568  log<software_error>({__FILE__, __LINE__, "unable to open auto ssh log fifo"});
569  mx::sys::sleep(1);
570  }
571  }
572 
573 
574  std::string logs;
575  while(m_shutdown == 0)
576  {
577  ssize_t count = read(m_autosshLogFD, buffer, sizeof(buffer)-1);
578  if (count <= 0)
579  {
580  continue;
581  }
582  else
583  {
584  buffer[count] = '\0';
585 
586  logs += buffer;
587 
588  //Keep reading until \n found, then process.
589  if(logs.back() == '\n')
590  {
591  size_t bol = 0;
592  while(bol < logs.size())
593  {
594  size_t eol = logs.find('\n', bol);
595  if(eol == std::string::npos) break;
596 
597  processAutoSSHLog(logs.substr(bol, eol-bol));
598  bol = eol + 1;
599  }
600  logs = "";
601  }
602  }
603  }
604 
605 }
606 
607 inline
608 int sshDigger::processAutoSSHLog( const std::string & logs )
609 {
610  ///\todo interpret logs, giving errors vs info vs debug, strip timestamps, etc.
611 
612  m_log.log<text_log>({"AUTOSSH: " + logs});
613 
614  return 0;
615 }
616 
618 {
619  m_autosshLogFile = "/dev/shm/sshDigger_autossh_" + m_configName + "_" + std::to_string(m_pid);
620 
621  if( mkfifo( m_autosshLogFile.c_str(), S_IRUSR | S_IWUSR) < 0)
622  {
623  log<software_critical>({__FILE__, __LINE__, errno});
624  log<software_critical>({__FILE__, __LINE__, "unable to create autossh log fifo"});
625  return -1;
626  }
627 
628 
629  if(execTunnel() < 0)
630  {
631  log<software_critical>({__FILE__,__LINE__});
632  return -1;
633  }
634 
635  if(autosshLogThreadStart() < 0)
636  {
637  log<software_critical>({__FILE__, __LINE__});
638  return -1;
639  }
640 
641  if(sshLogThreadStart() < 0)
642  {
643  log<software_critical>({__FILE__, __LINE__});
644  return -1;
645  }
646 
647 
648  return 0;
649 }
650 
652 {
653  if(!m_sshError)
654  {
655  m_lastSSHLogs = "";
657  }
658 
659  if(m_sshError == 1)
660  {
661  log<text_log>("sending SIGUSR1 to restart ssh");
662  kill(m_tunnelPID, SIGUSR1);
664  m_sshError = 0;
665  }
666 
667  if(m_sshError == 2)
668  {
670  m_sshError = 0;
671  }
672 
673  //Check if autossh has died for any reason
674  int status;
675  pid_t exited = waitpid(m_tunnelPID, &status, WNOHANG);
676 
677  if(exited == m_tunnelPID)
678  {
679  log<text_log>("autossh exited, restarting.");
680  m_sshSTDERR = -1; //This tells the sshLogThread to exit
681  char w = '\0';
682  ssize_t nwr = write(m_sshSTDERR_input, &w, 1); //And this wakes it up from the blocking read
683 
684  if(m_sshLogThread.joinable()) m_sshLogThread.join();
685  if(nwr != 1)
686  {
687  log<software_error>({__FILE__, __LINE__, errno });
688  log<software_error>({__FILE__, __LINE__, "Error on write to ssh log thread. restart failed."});
689  return -1;
690  }
691 
692  //And now we can restart autossh
693  if(execTunnel() < 0)
694  {
695  log<software_critical>({__FILE__,__LINE__,"restart of tunnel failed."});
696  return -1;
697  }
698 
699  //And the ssh log thread.
700  if(sshLogThreadStart() < 0)
701  {
702  log<software_critical>({__FILE__, __LINE__, "restart of ssh log thread failed."});
703  return -1;
704  }
705 
706  //Don't need to restart the autossh log thread, becuase we'll give it the same file as log file.
707  }
708 
709  return 0;
710 }
711 
713 {
714  kill(m_tunnelPID, SIGTERM);
715  waitpid(m_tunnelPID, 0, 0);
716 
717  //Write the the ssh stderr to wake up the ssh log thread, which will then see shutdown is set.
718  char w = '\0';
719  ssize_t nwr = write(m_sshSTDERR_input, &w, 1);
720  if(nwr != 1)
721  {
722  log<software_error>({__FILE__, __LINE__, errno });
723  log<software_error>({__FILE__, __LINE__, "Error on write to ssh log thread. Sending SIGTERM."});
724  pthread_kill(m_sshLogThread.native_handle(), SIGTERM);
725 
726  }
727 
728  if(m_sshLogThread.joinable()) m_sshLogThread.join();
729 
730  //Close the autossh FD to get that thread to shutdown.
731  close(m_autosshLogFD);
732  if(m_autosshLogThread.joinable()) m_autosshLogThread.join();
733 
734  return 0;
735 }
736 
737 } //namespace app
738 } //namespace MagAOX
739 
740 #endif //sshDigger_hpp
The base-class for MagAO-X applications.
Definition: MagAOXApp.hpp:75
std::string m_configName
The name of the configuration file (minus .conf).
Definition: MagAOXApp.hpp:88
stateCodes::stateCodeT state()
Get the current state code.
Definition: MagAOXApp.hpp:2082
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
Definition: MagAOXApp.hpp:102
pid_t m_pid
This process's PID.
Definition: MagAOXApp.hpp:394
std::string m_configBase
The name of a base config class for this app (minus .conf).
Definition: MagAOXApp.hpp:92
The MagAO-X SSH tunnel manager.
Definition: sshDigger.hpp:55
~sshDigger() noexcept
D'tor, declared and defined for noexcept.
Definition: sshDigger.hpp:106
std::thread m_sshLogThread
A separate thread for capturing ssh logs.
Definition: sshDigger.hpp:82
int m_autosshLogThreadPrio
Priority of the autossh log capture thread, should normally be 0.
Definition: sshDigger.hpp:95
int sshLogThreadStart()
Start the log capture.
Definition: sshDigger.hpp:397
virtual int appLogic()
Implementation of the FSM for sshDigger.
Definition: sshDigger.hpp:651
int m_sshSTDERR_input
The input end of stderr, used to wake up the log thread on shutdown.
Definition: sshDigger.hpp:78
int execTunnel()
Creates the tunnel in a child process using exec.
Definition: sshDigger.hpp:317
std::string m_remoteHost
The name of the remote host.
Definition: sshDigger.hpp:65
static void _sshLogThreadStart(sshDigger *s)
Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
Definition: sshDigger.hpp:391
int m_localPort
The local port to forward from.
Definition: sshDigger.hpp:66
int m_tunnelPID
The PID of the autossh process.
Definition: sshDigger.hpp:72
void autosshLogThreadExec()
Execute the log capture.
Definition: sshDigger.hpp:553
int processSSHLog(const std::string &logs)
Process a log entry from indiserver, putting it into MagAO-X standard form.
Definition: sshDigger.hpp:474
static void _autosshLogThreadStart(sshDigger *s)
Thread starter, called by sshLogThreadStart on thread construction. Calls sshLogThreadExec.
Definition: sshDigger.hpp:507
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition: sshDigger.hpp:199
int m_autosshLogFD
File descriptor of the autossh logfile.
Definition: sshDigger.hpp:93
int m_sshLogThreadPrio
Priority of the ssh log capture thread, should normally be 0.
Definition: sshDigger.hpp:80
std::string m_lastSSHLogs
Definition: sshDigger.hpp:84
int m_remotePort
The remote port to forward to.
Definition: sshDigger.hpp:67
int m_sshSTDERR
The output of stderr of the ssh process.
Definition: sshDigger.hpp:77
int m_monitorPort
The monitor port.
Definition: sshDigger.hpp:68
void sshLogThreadExec()
Execute the log capture.
Definition: sshDigger.hpp:436
int autosshLogThreadStart()
Start the log capture.
Definition: sshDigger.hpp:513
virtual int appShutdown()
Shutdown the app.
Definition: sshDigger.hpp:712
virtual int appStartup()
Startup function.
Definition: sshDigger.hpp:617
sshDigger()
Default c'tor.
Definition: sshDigger.hpp:184
virtual void setupConfig()
Definition: sshDigger.hpp:195
int processAutoSSHLog(const std::string &logs)
Process a log entry from indiserver, putting it into MagAO-X standard form.
Definition: sshDigger.hpp:608
int m_sshError
Flag to signal when ssh logs an error, and should be restarted via SIGUSR1 to autossh.
Definition: sshDigger.hpp:85
void genEnvp(std::vector< std::string > &envp)
Generate the envp vector for the exec of autossh.
Definition: sshDigger.hpp:310
std::string tunnelSpec()
Create the tunnel specification string, [localPort]:localhost:[remotePort].
Definition: sshDigger.hpp:296
void genArgsV(std::vector< std::string > &argsV)
Generate the argv vector for the exec of autossh.
Definition: sshDigger.hpp:303
std::string m_autosshLogFile
Name of the autossh logfile.
Definition: sshDigger.hpp:92
virtual void loadConfig()
Definition: sshDigger.hpp:291
std::thread m_autosshLogThread
A separate thread for capturing autossh logs.
Definition: sshDigger.hpp:97
bool m_compress
Control compression on this tunnel. True is on, false is off.
Definition: sshDigger.hpp:69
int8_t logPrioT
The type of the log priority code.
Definition: logDefs.hpp:21
@ CONNECTED
The application has connected to the device or service.
Definition: stateCodes.hpp:45
@ NOTCONNECTED
The application is not connected to the device or service.
Definition: stateCodes.hpp:44
std::ostream & cerr()
Definition: dm.hpp:24
constexpr static logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
Definition: logPriority.hpp:37
constexpr static logPrioT LOG_ERROR
An error has occured which the software will attempt to correct.
Definition: logPriority.hpp:40
constexpr static logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
Definition: logPriority.hpp:49
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
Definition: logPriority.hpp:43
#define SSHDIGGER_E_NOLOCALPORT
Definition: sshDigger.hpp:36
#define SSHDIGGER_E_NOTUNNELFOUND
Definition: sshDigger.hpp:34
#define SSHDIGGER_E_NOREMOTEPORT
Definition: sshDigger.hpp:37
#define SSHDIGGER_E_NOHOSTNAME
Definition: sshDigger.hpp:35
#define SSHDIGGER_E_NOTUNNELS
Definition: sshDigger.hpp:33
void log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry, including a message.
Definition: logManager.hpp:527
int logLevel(logPrioT newLev)
Set a new value of logLevel.
Definition: logManager.hpp:299
A simple text log, a string-type log.
Definition: text_log.hpp:24