ewmscp  ..
libsshCommon.cpp
Go to the documentation of this file.
1 #include <OptionsChrono.h>
2 #include "libsshCommon.h"
3 #include "timer.h"
4 #include <forward_list>
5 #include "escapism.h"
6 #include "errMsgQueue.h"
7 
8 static const std::string parPrefix("libssh");
9 
10 genericSftpStat::genericSftpStat(const sftp_attributes_struct& attrs,
11  const sftp_statvfs_struct& vfsStat) {
12  device = vfsStat.f_fsid;
13  size = attrs.size;
14  sizeOnDisk = attrs.size;
15  blksize = vfsStat.f_bsize;
16  aTime = clock_type::time_point(std::chrono::seconds(attrs.atime)
17  + std::chrono::nanoseconds(attrs.atime_nseconds));
18  mTime = clock_type::time_point(std::chrono::seconds(attrs.mtime)
19  + std::chrono::nanoseconds(attrs.mtime_nseconds));
20  timeResolution = std::chrono::microseconds(1);
21  mode = attrs.permissions;
22  ownerUid = attrs.uid;
23  ownerGid = attrs.gid;
24 }
25 
26 libsshCommon::sshOptions::sshOptions(const std::string& optPrefix):
27  host('\0', optPrefix + "_host",
28  "host to connect to"),
29  knownHostFile('\0', optPrefix + "_knownHosts",
30  "known hosts file to use"),
31  configFile('\0', optPrefix + "_config",
32  "path to ssh config file"),
33  verbosity('\0', optPrefix + "_verbosity",
34  "libssh verbosity", "SSH_LOG_NOLOG") {
35  verbosity.fAddToRange("SSH_LOG_NOLOG");
36  verbosity.fAddToRange("SSH_LOG_WARNING");
37  verbosity.fAddToRange("SSH_LOG_PROTOCOL");
38  verbosity.fAddToRange("SSH_LOG_PACKET");
39  verbosity.fAddToRange("SSH_LOG_FUNCTIONS");
40 };
41 
43  session = throwcall::badval(ssh_new(), nullptr, "create new ssh session");
44  throwcall::good0(ssh_options_set(session, SSH_OPTIONS_HOST, opt.host.c_str()),
45  "can't set host");
46  if (opt.knownHostFile.fIsSet()) {
47  throwcall::ssh::good0(ssh_options_set(session, SSH_OPTIONS_KNOWNHOSTS,
48  opt.knownHostFile.c_str()), *this,
49  "can't add global known hosts file");
50  }
51 
52  throwcall::ssh::good0(ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY_STR,
53  opt.verbosity.c_str()),
54  *this, "set verbosity");
55  throwcall::good0(ssh_options_parse_config(session, opt.configFile.empty() ? nullptr : opt.configFile.c_str()),
56  "can't read ssh config file ", opt.configFile.empty() ? "(default)" : opt.configFile.c_str());
57  throwcall::ssh::goodval(ssh_connect(session), SSH_OK, *this,
58  "can't connect to ", opt.host);
59  #if LIBSSH_VERSION_MINOR > 7
60  switch (ssh_session_is_known_server(session)) {
61  case SSH_KNOWN_HOSTS_OK:
62  break;
63  case SSH_KNOWN_HOSTS_CHANGED:
64  throw std::runtime_error("host " + opt.host + " key changed");
65  case SSH_KNOWN_HOSTS_OTHER:
66  throw std::runtime_error("host " + opt.host + " not found but other key exists");
67  case SSH_KNOWN_HOSTS_NOT_FOUND:
68  throw std::runtime_error("known hosts file not found");
69  case SSH_KNOWN_HOSTS_UNKNOWN:
70  throw std::runtime_error("host " + opt.host + " is unknown");
71  case SSH_KNOWN_HOSTS_ERROR:
72  throw std::runtime_error(std::string("host check error ") + ssh_get_error(session));
73  }
74  #else
75  throwcall::ssh::goodval(ssh_is_server_known(session), SSH_SERVER_KNOWN_OK, *this,
76  "can't verify host ", opt.host);
77  #endif
78  if (ssh_userauth_gssapi(session) != SSH_AUTH_SUCCESS) {
79  if (ssh_userauth_publickey_auto(session, nullptr, nullptr) != SSH_AUTH_SUCCESS) {
80  if (ssh_userauth_agent(session, nullptr) != SSH_AUTH_SUCCESS) {
81  throw std::runtime_error("can't authenticate at " + opt.host);
82  }
83  }
84  }
86  "ssh", "connect", "sucessfully authenticated user");
87  sftp = throwcall::ssh::badval(sftp_new(session), nullptr, *this,
88  "create new sftp session");
89  throwcall::sftp::good0(sftp_init(sftp), *this, "can't init sftp session");
90 }
92  sftp_free(sftp);
93  sftp = nullptr;
94  ssh_disconnect(session);
95  ssh_free(session);
96  session = nullptr;
97 }
99  if (reconnecting) {
101  "ssh", "reconnect", "error while reconnecting");
102  return;
103  }
104  reconnecting = true;
105  closeSessions();
107  "ssh", "reconnect", "trying reconnect");
108  openSessions();
109  reconnecting = false;
110 }
111 
112 
114  openSessions();
115 }
117  closeSessions();
118 }
119 
120 bool libsshCommon::pathExists(const std::string& path) {
121  auto stat = getUniquePtr(sftp_lstat(sftp, path.c_str()), sftp_attributes_free);
122  if (stat == nullptr) {
123  if (sftp_get_error(sftp) == SSH_FX_NO_SUCH_FILE) {
124  return false;
125  }
126  throwcall::sftp::badval(nullptr, nullptr, *this, "can't stat ", path);
127  }
128  return true;
129 };
130 std::unique_ptr<const genericStat> libsshCommon::getStat(const std::string& path,
131  bool followLink) {
132  sftp_attributes stat;
133  if (followLink) {
134  timerInst(sftp_stat);
135  stat = sftp_stat(sftp, path.c_str());
136  } else {
137  timerInst(sftp_lstat);
138  stat = sftp_lstat(sftp, path.c_str());
139  }
140  if (stat == nullptr) {
141  if (sftp_get_error(sftp) == SSH_FX_NO_SUCH_FILE) {
142  return nullptr;
143  }
144  return nullptr;
145  throwcall::sftp::badval(nullptr, nullptr, *this, "can't stat ", path);
146  }
147  auto retval = new genericSftpStat(*stat, getVfsStat(path));
148  sftp_attributes_free(stat);
149  return std::unique_ptr<const genericStat>(retval);
150 };
151 
152 const sftp_statvfs_struct& libsshCommon::getVfsStat(const std::string& path) {
153  static std::map<std::string, sftp_statvfs_struct*> statMap;
154  auto lastSlashAt = path.find_last_of('/');
155  if (lastSlashAt == 0) {
156  lastSlashAt = std::string::npos;
157  }
158  auto dir = path.substr(0, lastSlashAt);
159  auto item = statMap.find(dir);
160  if (item == statMap.end()) {
161  timerInst(sftp_statvfs);
162  auto retval = sftp_statvfs(sftp, dir.c_str());
163  if (retval == nullptr) {
164  std::string msg(ssh_get_error(session));
165  if (msg.find("Operation unsupported")) {
166  static sftp_statvfs_struct fakeData;
167  fakeData.f_bsize = 4096;
169  dir, "statvfs", "not supported, using fake data");
170  auto result = statMap.emplace(dir, &fakeData);
171  item = result.first;
172  } else {
173  throwcall::sftp::badval(retval, nullptr, *this,
174  "can't stat fvs for path ", dir);
175  }
176  } else {
177  auto result = statMap.emplace(dir, retval);
178  item = result.first;
180  dir, "statvfs",
181  "bsize: ", retval->f_bsize,
182  " frsize:", retval->f_frsize,
183  " blocks:", retval->f_blocks,
184  " bfree:", retval->f_bfree,
185  " bavail:", retval->f_bavail,
186  " files:", retval->f_files,
187  " ffree:", retval->f_ffree,
188  " favail:", retval->f_favail,
189  " fsid:", retval->f_fsid,
190  " flag:", retval->f_flag,
191  " namemax:", retval->f_namemax);
192  }
193  }
194  return *(item->second);
195 }
196 
197 
198 libsshIoCommon::libsshIoCommon(const std::string& aPath,
199  libsshCommon& aHandler):
200  handler(aHandler),
201  path(aPath) {
202 }
203 
204 
205 
206 
207 
208 std::unique_ptr<const genericStat> libsshIoCommon::getStat() {
209  timerInst(sftp_fstat);
210  auto stat = throwcall::sftp::badval(sftp_fstat(file), nullptr, handler,
211  "can't stat", path);
212  auto retval = new genericSftpStat(*stat, handler.getVfsStat(path));
213  sftp_attributes_free(stat);
214  return std::unique_ptr<const genericStat>(retval);
215 }
genericStat::ownerGid
gid_t ownerGid
Definition: genericStat.h:24
genericStat::mode
mode_t mode
Definition: genericStat.h:22
libsshCommon::session
ssh_session session
Definition: libsshCommon.h:27
errMsgQueue.h
errMsg::location
class for defining the location of a error message in the source code.
Definition: errMsgQueue.h:14
options::internal::typed_base::fAddToRange
virtual void fAddToRange(rangeValueType aValue)
add a value to the range of allowed values
Definition: Options.h:458
throwcall::badval
T badval(T call, t badvalue, const Args &... args)
template function to wrap system calls that return a special bad value on failure
Definition: throwcall.h:54
libsshCommon::opt
sshOptions & opt
Definition: libsshCommon.h:39
libsshCommon
Definition: libsshCommon.h:25
libsshCommon::pathExists
bool pathExists(const std::string &path) override
Definition: libsshCommon.cpp:120
genericStat::mTime
clock_type::time_point mTime
Definition: genericStat.h:20
libsshCommon::sshOptions::sshOptions
sshOptions(const std::string &optPrefix)
Definition: libsshCommon.cpp:26
libsshCommon.h
options::base::fIsSet
virtual bool fIsSet() const
check if this option was set, regardless of from command line or config file
Definition: Options.h:263
libsshIoCommon::file
sftp_file file
Definition: libsshCommon.h:60
genericStat::sizeOnDisk
size_t sizeOnDisk
Definition: genericStat.h:17
libsshCommon::reconnecting
bool reconnecting
Definition: libsshCommon.h:42
parPrefix
static const std::string parPrefix("libssh")
libsshIoCommon::getStat
std::unique_ptr< const genericStat > getStat() override
Definition: libsshCommon.cpp:208
libsshCommon::sshOptions
Definition: libsshCommon.h:30
genericStat::aTime
clock_type::time_point aTime
Definition: genericStat.h:19
errMsg::level::debug
@ debug
genericStat::blksize
size_t blksize
Definition: genericStat.h:18
libsshCommon::openSessions
void openSessions()
Definition: libsshCommon.cpp:42
genericStat::size
size_t size
Definition: genericStat.h:16
escapism.h
OptionsChrono.h
libsshIoCommon::path
const std::string path
Definition: libsshCommon.h:59
libsshCommon::closeSessions
void closeSessions()
Definition: libsshCommon.cpp:91
timer.h
genericSftpStat::genericSftpStat
genericSftpStat(const sftp_attributes_struct &attrs, const sftp_statvfs_struct &vfsStat)
Definition: libsshCommon.cpp:10
genericStat::device
dev_t device
Definition: genericStat.h:15
libsshIoCommon::handler
libsshCommon & handler
Definition: libsshCommon.h:58
libsshIoCommon::libsshIoCommon
libsshIoCommon(const std::string &aPath, libsshCommon &aHandler)
Definition: libsshCommon.cpp:198
libsshCommon::sshOptions::knownHostFile
options::single< std::string > knownHostFile
Definition: libsshCommon.h:34
throwcall::ssh::badval
T badval(T call, t badvalue, libsshCommon &handler, const Args &... args)
Definition: libsshCommon.h:120
libsshCommon::sshOptions::verbosity
options::single< std::string > verbosity
Definition: libsshCommon.h:36
errMsg::emit
void emit(level aLogLevel, const location &loc, const std::string &aObject, const std::string &aAction, const Args &... args)
function to create and enqueue a message, this is the only way that messages should be created!
Definition: errMsgQueue.h:148
timerInst
#define timerInst(subfunc)
Definition: timer.h:157
libsshCommon::getUniquePtr
std::unique_ptr< T, void(*)(T *)> getUniquePtr(T *obj, void(*deleter)(T *))
Definition: libsshCommon.h:45
libsshCommon::getStat
std::unique_ptr< const genericStat > getStat(const std::string &path, bool followLink) override
Definition: libsshCommon.cpp:130
libsshCommon::sftp
sftp_session sftp
Definition: libsshCommon.h:28
genericSftpStat
Definition: libsshCommon.h:16
libsshCommon::sshOptions::configFile
options::single< std::string > configFile
Definition: libsshCommon.h:35
libsshCommon::~libsshCommon
~libsshCommon() override
Definition: libsshCommon.cpp:116
throwcall::good0
void good0(T call, const Args &... args)
template function to wrap system calls that return 0 on success
Definition: throwcall.h:40
libsshCommon::sshOptions::host
options::single< std::string > host
Definition: libsshCommon.h:33
throwcall::sftp::badval
T badval(T call, t badvalue, libsshCommon &handler, const Args &... args)
Definition: libsshCommon.h:82
genericStat::timeResolution
clock_type::duration timeResolution
Definition: genericStat.h:21
libsshCommon::getVfsStat
const sftp_statvfs_struct & getVfsStat(const std::string &path)
Definition: libsshCommon.cpp:152
throwcall::ssh::goodval
T goodval(T call, t goodvalue, libsshCommon &handler, const Args &... args)
Definition: libsshCommon.h:108
genericStat::ownerUid
uid_t ownerUid
Definition: genericStat.h:23
throwcall::ssh::good0
void good0(T call, libsshCommon &handler, const Args &... args)
Definition: libsshCommon.h:97
libsshCommon::libsshCommon
libsshCommon(sshOptions &aOpt)
Definition: libsshCommon.cpp:113
libsshCommon::reconnectSessions
void reconnectSessions()
Definition: libsshCommon.cpp:98
throwcall::sftp::good0
void good0(T call, libsshCommon &handler, const Args &... args)
Definition: libsshCommon.h:70