📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

文字列「__FORCETOC__」を「{{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This pag…
 
(同じ利用者による、間の25版が非表示)
2行目: 2行目:
Qtにおいて、簡潔にSSH接続を確立する手順を記載する。<br>
Qtにおいて、簡潔にSSH接続を確立する手順を記載する。<br>
<br>
<br>
* libsshまたはlibssh2を使用する。
* libSSHライブラリ (LGPLライセンス) を使用する。
* QProcessクラスを使用して、外部のSSHプロセスを呼び出して接続を確立する。
* libSSH2ライブラリ (3条項BSDライセンス) を使用する。
* 他のSSHライブラリを購入する。<br>http://netsieben.com/products/ssh
* <code>QProcess</code>クラスを使用して、外部のSSHプロセスをフォークして接続を確立する。
* wolfSSH
*: wolfSSHライブラリは、wolfSSLと連携して使用する。
*: 無償版は、<u>GPL v2ライセンス</u>である。
*: 有償版は、独自ライセンスである。
*: https://wolfssl.jp/products/wolfssh/
*: Github : https://github.com/wolfSSL/wolfssh
*: wolfSSLのGithub : https://github.com/wolfSSL/wolfssl
*: <br>
*: また、wolfSSLは、IoTデバイス、組み込み向け小型デバイスにも対応した軽量のSSL/TLSライブラリである。
* QSshライブラリを使用する。
*: QSshは、QtアプリケーションにSSHとSFTPのサポートを提供する。
*: QSshプロジェクトは、過去のQt CreatorのSSHプラグインに基づいており、全てのクレジットはQt Creatorチームに帰属する。
*: ただし、現在では、Qt CreatorはOpenSSHを使用している。
*: <br>
*: https://github.com/sandsmark/QSsh
<br><br>
<br><br>


192行目: 207行目:
  #include <libssh/libssh.h>
  #include <libssh/libssh.h>
   
   
  int VerifyKnownsHost(ssh_session session, QString &strErrMsg);
  int VerifyKnownsHost(ssh_session my_ssh_session, QString &strErrMsg);
   
   
  int main(int argc, char *argv[])
  int main(int argc, char *argv[])
199行目: 214行目:
   
   
     // SSHセッションの作成
     // SSHセッションの作成
     ssh_session ssh_session = ssh_new();
     ssh_session my_ssh_session = ssh_new();
     if (my_ssh_session == NULL) {
     if (my_ssh_session == NULL) {
       // 作成に失敗した場合
       // 作成に失敗した場合
210行目: 225行目:
     QString port = "<SSHポート番号  例: 22>";
     QString port = "<SSHポート番号  例: 22>";


     ssh_options_set(ssh_session, SSH_OPTIONS_HOST, host.toUtf8().data());
     ssh_options_set(my_ssh_session, SSH_OPTIONS_HOST, host.toUtf8().data());
     ssh_options_set(ssh_session, SSH_OPTIONS_USER, user.toUtf8().data());
     ssh_options_set(my_ssh_session, SSH_OPTIONS_USER, user.toUtf8().data());
     ssh_options_set(ssh_session, SSH_OPTIONS_PORT_STR, port.toUtf8().data());
     ssh_options_set(my_ssh_session, SSH_OPTIONS_PORT_STR, port.toUtf8().data());
   
   
     // SSH接続
     // SSH接続
     int rc = ssh_connect(ssh_session);
     int rc = ssh_connect(my_ssh_session);
     if (rc != SSH_OK) {
     if (rc != SSH_OK) {
       // 接続に失敗した場合
       // 接続に失敗した場合
       fprintf(stderr, "Error connecting to host: %s\n", ssh_get_error(ssh_session));
       fprintf(stderr, "Error connecting to host: %s\n", ssh_get_error(my_ssh_session));
       ssh_free(ssh_session);
       ssh_free(my_ssh_session);
   
   
       return -1;
       return -1;
226行目: 241行目:
     // ~/.sshディレクトリ等にあるファイルに記述されているサーバのIDを検証
     // ~/.sshディレクトリ等にあるファイルに記述されているサーバのIDを検証
     QString strErrMsg = "";
     QString strErrMsg = "";
     if(VerifyKnownsHost(ssh_session, strErrMsg) < 0)
     if(VerifyKnownsHost(my_ssh_session, strErrMsg) < 0)
     {
     {
       fprintf(stderr, "%s\n", strErrMsg.toUtf8().constData();
       fprintf(stderr, "%s\n", strErrMsg.toUtf8().constData();
       if(ssh_session != nullptr)
       if(my_ssh_session != nullptr)
       {
       {
           ssh_disconnect(ssh_session);
           ssh_disconnect(my_ssh_session);
           ssh_free(ssh_session);
           ssh_free(my_ssh_session);
       }
       }
   
   
243行目: 258行目:
   
   
     // 秘密鍵のパスフレーズを設定していない場合
     // 秘密鍵のパスフレーズを設定していない場合
     rc = ssh_userauth_privatekey_file(ssh_session, nullptr, private_key_path, nullptr);
     rc = ssh_userauth_privatekey_file(my_ssh_session, nullptr, private_key_path, nullptr);
   
   
     // 秘密鍵のパスフレーズを設定している場合
     // 秘密鍵のパスフレーズを設定している場合
     rc = ssh_userauth_privatekey_file(ssh_session, nullptr, private_key_path, "<秘密鍵のパスフレーズ>");
     rc = ssh_userauth_privatekey_file(my_ssh_session, nullptr, private_key_path, "<秘密鍵のパスフレーズ>");
   
   
     if (rc != SSH_AUTH_SUCCESS) {
     if (rc != SSH_AUTH_SUCCESS) {
261行目: 276行目:
   
   
     // SSH接続の切断
     // SSH接続の切断
     ssh_disconnect(ssh_session);
     ssh_disconnect(my_ssh_session);
   
   
     // SSHセッションの解放
     // SSHセッションの解放
     ssh_free(ssh_session);
     ssh_free(my_ssh_session);
   
   
     return 0;
     return 0;
  }
  }
   
   
  int VerifyKnownsHost(ssh_session ssh_session, QString &strErrMsg)
  int VerifyKnownsHost(ssh_session my_ssh_session, QString &strErrMsg)
  {
  {
     // Authenticating the server.
     // Authenticating the server.
     ssh_key srv_pubkey = {};
     ssh_key srv_pubkey = {};
     if(ssh_get_server_publickey(ssh_session, &srv_pubkey) < 0)
     if(ssh_get_server_publickey(my_ssh_session, &srv_pubkey) < 0)
     {
     {
       strErrMsg = tr("Failed to get public key.");
       strErrMsg = tr("Failed to get public key.");
293行目: 308行目:
     }
     }
   
   
     auto state = ssh_session_is_known_server(ssh_session);
     auto state = ssh_session_is_known_server(my_ssh_session);
     if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_OK)
     if(state == ssh_known_hosts_e::SSH_KNOWN_HOSTS_OK)
     {  // Authentication Successful
     {  // Authentication Successful
341行目: 356行目:
       else
       else
       {
       {
           iRet = ssh_session_update_known_hosts(ssh_session);
           iRet = ssh_session_update_known_hosts(my_ssh_session);
           if(iRet < 0)
           if(iRet < 0)
           {
           {
368行目: 383行目:
       else
       else
       {
       {
           iRet = ssh_session_update_known_hosts(ssh_session);
           iRet = ssh_session_update_known_hosts(my_ssh_session);
           if(iRet < 0)
           if(iRet < 0)
           {
           {
389行目: 404行目:
   
   
     return 0;
     return 0;
  }
  } </syntaxhighlight>
</syntaxhighlight>
<br><br>
<br><br>


403行目: 417行目:
<br><br>
<br><br>


== libSSH2の使用例 ==
== libSSH2ライブラリを使用したコマンドの使用例 ==
以下の例では、リモート側のPCにSSH接続して、SCPでファイルを送信している。<br>
==== ブロッキングモード ====
<br>
以下の例では、リモート側のPCにSSH接続して、lsコマンドを実行してその結果をローカル側のPCに表示している。<br>
以下の例は、ノンブロッキングモードでSCPを実行している。<br>
ノンブロッキングモードを有効にする場合、libSSH2ライブラリの関数呼び出しは即座に返されて、処理がバックグラウンドで非同期に進行する。<br>
これにより、プログラムは他の処理を続行でき、必要に応じてリモートホストとの通信が完了するのを待つことができる。<br>
<br>
<br>
ノンブロッキングモードを使用する場合、特に入出力操作が発生する待ち時間を最小限に抑え、プログラムがより効率的に動作することが期待される。<br>
以下の例は、<u>ブロッキングモード</u>でlsコマンドを実行している。<br>
しかし、ノンブロッキングモードを扱う際には、非同期処理やイベント駆動型のプログラミングに慣れる必要がある。<br>
<br>
<br>
  <syntaxhighlight lang="make">
  <syntaxhighlight lang="make">
  # .pro プロジェクトファイル
  # .pro プロジェクトファイル
# QTcpSocketを使用する場合
QT += network
   
   
  # pkg-configを使用する場合
  # pkg-configを使用する場合
432行目: 445行目:
   
   
  #include <QCoreApplication>
  #include <QCoreApplication>
  #include <QFileInfo>
  #include <QTcpSocket>
#include <QTimer>
#include <QElapsedTimer>
  #include <QDebug>
  #include <QDebug>
  #include <libssh2.h>
  #include <libssh2.h>
#include <libssh2_sftp.h>
  #include "DivideByZeroException.h"
  #include "DivideByZeroException.h"
   
   
#ifdef Q_OS_LINUX
  void DisConnect(QTcpSocket &sock, LIBSSH2_SESSION *session);
#include <sys/socket.h>
  int  ExecCommand(QTcpSocket &sock, LIBSSH2_SESSION *session);
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#endif
  void DisConnect(int &sock, LIBSSH2_SESSION *session);
  int  Send(int &sock, LIBSSH2_SESSION *session);
int  waitsocket(libssh2_socket_t socket_fd, LIBSSH2_SESSION *session);
   
   
  int main(int argc, char *argv[])
  int main(int argc, char *argv[])
457行目: 458行目:
   
   
     int rc  = 0;
     int rc  = 0;
     int sock = 0;
     QTcpSocket sock;
     LIBSSH2_SESSION *session = nullptr;
     LIBSSH2_SESSION *session = nullptr;
   
   
#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
    // libSSH2オブジェクトの初期化
    WSADATA wsadata;
    auto rc = libssh2_init(0);
    if (rc != 0) {
        qDebug() << "libssh2 initialization failed";
        DisConnect(sock, session);
   
   
    rc = WSAStartup(MAKEWORD(2, 0), &wsadata);
        return -1;
    if(rc) {
      std::cerr << "WSAStartup failed with error: " << rc << std::endl;
      return -1;
     }
     }
#endif
   
   
     // 初期化
     // QTcpSocketクラスのインスタンスを生成して、リモートPCに接続
     rc = libssh2_init(0);
     sock.connectToHost(<リモートPCのIPアドレスまたはホスト名>, <リモートPCにSSH接続するポート番号>);
     if (rc != 0) {
       qDebug() << QString("libssh2 initialization failed %1").arg(rc);
    // 最大10[秒]待機
     if (!sock.waitForConnected(10000)) {
       qDebug() << "SSH接続に失敗:" << socket.errorString();
       DisConnect(sock, session);
       DisConnect(sock, session);
   
   
479行目: 482行目:
     }
     }
   
   
     // ソケットの作成
     // SSHのセッションの初期化
     sock = socket(AF_INET, SOCK_STREAM, 0);
     session = libssh2_session_init();
     if (sock == -1) {
     if (!session) {
       qDebug() << QString("failed to create socket.");
       qDebug() << "SSHのセッションの初期化に失敗";
       DisConnect(sock, session);
       DisConnect(sock, session);
   
   
488行目: 491行目:
     }
     }
   
   
    struct sockaddr_in sin = {};
     // SSHのハンドシェイク
    sin.sin_family = AF_INET;
     if (libssh2_session_handshake(session, sock.socketDescriptor()) != 0) {
    sin.sin_port = htons(50022);
       qDebug() << "SSHのハンドシェイクに失敗";
    sin.sin_addr.s_addr = inet_addr("<リモート側PCのIPアドレス または ホスト名>");
     // SSH接続
     if (connect(sock, (struct sockaddr*)(&sin), sizeof(struct sockaddr_in)) == -1) {
       qDebug() << QString("failed to connect.");
       DisConnect(sock, session);
       DisConnect(sock, session);
   
   
501行目: 499行目:
     }
     }
   
   
     // libSSH2のセッションを初期化
     // リモートPCのフィンガープリントを確認
     session = libssh2_session_init();
     auto fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
    qDebug() << "リモートPCのフィンガープリント:" << fingerprint;
   
   
     // リモート側のPCとのハンドシェイク
     // 認証方法の確認
     libssh2_session_handshake(session, sock);
     auto userauth_list = libssh2_userauth_list(session, "<リモートPCのユーザ名>", strlen(USERNAME));
    qDebug() << "認証方法:" << userauth_list;
   
   
     // パスワード認証
     // パスワード認証を行う場合
     if (libssh2_userauth_password(session, "<リモート側のユーザ名>", "<ユーザ名のパスワード>") != 0) {
     //if (libssh2_userauth_password(session, "<リモートPCのユーザ名>", "<リモートPCのユーザパスワード>") != 0) {
      qDebug() << QString("Authentication failed.");
    //  qDebug() << "パスワードによる認証に失敗";
    //  return -1;
    //}
 
    // 公開鍵認証
    if (libssh2_userauth_publickey_fromfile(session, "<リモートPCのユーザ名>", "<公開鍵ファイルのパス>", "<秘密鍵ファイルのパス>", "<秘密鍵のパスフレーズ>") != 0) {
      qDebug() << "公開鍵認証に失敗";
       DisConnect(sock, session);
       DisConnect(sock, session);
   
   
518行目: 524行目:
   
   
     // SSH接続後の処理
     // SSH接続後の処理
     // SCPでファイルを送信
     // リモートPC上でls -alコマンドを実行
     rc = Send(sock, session);
     rc = ExecCommand(sock, session);
     if (rc != 0) {
     if (rc != 0) {
       DisConnect(sock, session);
       DisConnect(sock, session);
532行目: 538行目:
  }
  }
   
   
  void DisConnect(int &sock, LIBSSH2_SESSION *session)
  void DisConnect(QTcpSocket &sock, LIBSSH2_SESSION *session)
  {
  {
     // セッションの終了
     // セッションの終了
542行目: 548行目:
   
   
     // ソケットを閉じる
     // ソケットを閉じる
     if (sock != LIBSSH2_INVALID_SOCKET) {
     if(sock.isOpen()) {
      shutdown(sock, 2);
        sock.close();
#if defined(Q_OS_WIN32) || defined(Q_OS_WIN64)
      closesocket(sock);
#else
      close(sock);
#endif
     }
     }
   
   
559行目: 558行目:
  }
  }
   
   
  int Send(int &sock, LIBSSH2_SESSION *session)
  int ExecCommand(QTcpSocket &sock, LIBSSH2_SESSION *session)
  {
  {
     // Send a file via scp. The mode parameter must only have permissions.
     // チャンネルをオープン
     LIBSSH2_CHANNEL *channel = nullptr;
     LIBSSH2_CHANNEL *channel = libssh2_channel_open_session(session);
     if (!channel) {
    QString localFilePath = "<ローカルPCのファイルパス  例: /tmp/hoge.png>";
       qDebug() << "チャンネルのオープンに失敗";
    QFile File(localFilePath);
     if(!File.open(QIODevice::ReadOnly))
    {
       qDebug() << QString("Cannot open local File(%1) Open Error: %2").arg(QFileInfo(File).fileName(), File.errorString());
       return -1;
       return -1;
     }
     }
   
   
     // QFileInfoクラスではパーミッションは16進数のため、libssh2_scp_send64関数で使用するため8進数に変換する
     // リモートPC上でls -alコマンドを実行
    // これは、見た目の数値を同じにする必要がある  例: 0x644(16進数) --> 0644(8進数)
     if (libssh2_channel_exec(channel, "ls -la") != 0) {
     QFileInfo FileInfo(localFilePath);
       qDebug() << "コマンドの実行に失敗";
    //// ステッキービットは不要なため削除
    auto hexPermisshionString = QString::number(FileInfo.permissions(), 16).mid(1);
    bool ok;
    //// 8進数に変換
    unsigned int octPermisshionValue = hexPermisshionString.toInt(&ok, 8);
    if (!ok) {
       qDebug() << QString("Failed to convert permission value.");
       return -1;
       return -1;
     }
     }
   
   
     QString remoteFilePath = "<リモート側PCのファイルパス  例: /home/remote-user/hoge.png>";
     // ls -alコマンドの実行結果を取得
    int rc = 0;
    QByteArray buffer;
    buffer.resize(1024); // バッファサイズを1024バイトに指定
     do {
     do {
       channel = libssh2_scp_send64(session, remoteFilePath.toUtf8().constData(), octPermisshionValue & 0777, FileInfo.size(), 0, 0);
       rc = libssh2_channel_read(channel, buffer.data(), buffer.size());
       if (!channel && libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) {
      if (rc > 0) {
          File.close();
          qDebug().noquote() << QString::fromUtf8(buffer.constData(), rc);
      }
      else if (rc < 0) {
          qDebug() << "Error reading channel:" << rc;
          break;
      }
    } while (rc > 0);
    // チャンネルの終了を確認
    // 終了コードおよび終了シグナルを取得して表示
    int  exitcode    = 127;
    char *exitsignal = nullptr;
    rc = libssh2_channel_close(channel);
    if (rc == 0) {
      exitcode = libssh2_channel_get_exit_status(channel);
       libssh2_channel_get_exit_signal(channel, &exitsignal, nullptr, nullptr, nullptr, nullptr, nullptr);
    }
    if (exitsignal) qDebug() << "Exit signal:" << exitsignal;
    else            qDebug() << "Exit code:" << exitcode;
    return 0;
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// DivideByZeroException.h
   
   
          char *err_msg;
#ifndef DIVIDEBYZEROEXCEPTION_H
          libssh2_session_last_error(session, &err_msg, NULL, 0);
#define DIVIDEBYZEROEXCEPTION_H
          qDebug() << err_msg;
   
   
          return -1;
#include <QException>
       }
     } while (!channel);
class DivideByZeroException : public QException
{
public:
    DivideByZeroException() {};
    virtual ~DivideByZeroException() {};
    const char* what() const noexcept override {
      return "Divide by zero exception";
    }
};
#endif // DIVIDEBYZEROEXCEPTION_H
</syntaxhighlight>
<br>
==== ノンブロッキングモード ====
以下の例では、リモート側のPCにSSH接続して、lsコマンドを実行してその結果をローカル側のPCに表示している。<br>
<br>
以下の例は、<u>ノンブロッキングモード</u>でlsコマンドを実行している。<br>
<u>ノンブロッキングモード</u> (シグナル / スロット) で設計する場合、libSSH2ライブラリの関数呼び出しは即座に返されて、処理がバックグラウンドで非同期に進行する。<br>
これにより、プログラムは他の処理を続行でき、必要に応じてリモートホストとの通信が完了するのを待つことができる。<br>
<br>
ノンブロッキングモードを使用する場合、特に入出力操作が発生する待ち時間を最小限に抑え、プログラムがより効率的に動作することが期待される。<br>
しかし、ノンブロッキングモードを扱う際には、非同期処理やイベント駆動型のプログラミングに慣れる必要がある。<br>
<br>
<syntaxhighlight lang="c++">
// SSHClient.hファイル
#include <QCoreApplication>
#include <QTcpSocket>
#include <QTimer>
#include <QDebug>
#include <libssh2.h>
 
class SSHClient : public QObject
{
    Q_OBJECT
private:
    QTcpSocket      *m_Socket;
    LIBSSH2_SESSION *m_Session;
    LIBSSH2_CHANNEL *m_Channel;
    QString        m_Host;
    quint16        m_Port;
    QString        m_User;
    QString        m_Passwaord;
    QString        m_PubKey;
    QString        m_PrivateKey;
    QString        m_Passphrase;
public:
    SSHClient(QString host, quint16 port, QString user, QString password, QObject *parent = nullptr);
    SSHClient(QString host, quint16 port, QString user,
              QString pubkey, QString privkey, QString phrase, QObject *parent = nullptr);
    ~SSHClient();
    void connectToHost();
private slots:
    void onConnected();
    void authenticateUser();
    void openChannel();
    void executeCommand();
    void onReadyRead();
    void readOutput();
    void closeChannel();
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// SSHClient.cppファイル
#include "SSHClient.h"
SSHClient::SSHClient(QString host, quint16 port, QString user, QString password, QObject *parent = nullptr) :
    QObject(parent), m_Session(nullptr), m_Channel(nullptr), m_Host(host), m_Port(port), m_User(user), m_Password(password)
{
    m_Socket = new QTcpSocket(this);
    connect(m_Socket, &QTcpSocket::connected, this, &SSHClient::onConnected);
    connect(m_Socket, &QTcpSocket::readyRead, this, &SSHClient::onReadyRead);
    // libSSH2ライブラリの初期化
    if (libssh2_init(0) != 0) {
      qDebug() << "libSSH2ライブラリの初期化に失敗";
      return;
    }
}
SSHClient::SSHClient(QString host, quint16 port, QString user, QString pubkey, QString privkey, QString phrase, QObject *parent = nullptr) :
    QObject(parent), m_Session(nullptr), m_Channel(nullptr),
    m_Host(host), m_Port(port), m_User(user), m_PublicKey(pubkey), m_PrivateKey(privkey), m_Passphrase(phrase)
{
    m_Socket = new QTcpSocket(this);
    connect(m_Socket, &QTcpSocket::connected, this, &SSHClient::onConnected);
    connect(m_Socket, &QTcpSocket::readyRead, this, &SSHClient::onReadyRead);
    // libSSH2ライブラリの初期化
    if (libssh2_init(0) != 0) {
      qDebug() << "libSSH2ライブラリの初期化に失敗";
      return;
    }
}
SSHClient::~SSHClient()
{
    if (m_Channel) libssh2_channel_free(m_Channel);
    if (m_Session) {
      libssh2_session_disconnect(m_Session, "Normal Shutdown");
       libssh2_session_free(m_Session);
    }
    libssh2_exit();
}
void SSHClient::connectToHost()
{
     m_Socket->connectToHost(m_Host, m_Port);
}
void SSHClient::onConnected()
{
    qDebug() << "ホストへの接続に成功";
    m_Session = libssh2_session_init();
    libssh2_session_set_blocking(m_Session, 0);
   
   
     qDebug() << QString("SCP session waiting to send file.");
     int rc = 0;
    do {
      rc = libssh2_session_handshake(m_Session, m_Socket->socketDescriptor());
    } while (rc == LIBSSH2_ERROR_EAGAIN);
   
   
     // タイマの開始
     if (rc) {
    QElapsedTimer elapsedTimer;
      qDebug() << "SSHのセッションの確立に失敗:" << rc;
     elapsedTimer.start();
      return;
     }
   
   
     int nread = 0,
     authenticateUser();
        total = 0;
}
     char mem[1024 * 100] = {};
void SSHClient::authenticateUser()
{
     int rc = 0;
     do {
     do {
       nread = File.read(mem, sizeof(mem));
       // パスワード認証を行う場合
       if(nread <= 0) {
      //rc = libssh2_userauth_password(m_Session,
          // EOF
      //                              m_User.toUtf8().constData(),
          break;
       //                              m_Password.toUtf8().constData());
      }
   
   
        auto ptr = mem;
      // 公開鍵認証を行う場合
        total += nread;
      rc = libssh2_userauth_publickey_fromfile(m_Session,
        auto prev = 0;
                                                m_User.toUtf8().constData(),
        do {
                                                "",  // クライアントPCに秘密鍵があり、
          ssize_t nwritten;
                                                    // リモートPC側に公開鍵が設置されている場合
          while ((nwritten = libssh2_channel_write(channel, ptr, nread)) == LIBSSH2_ERROR_EAGAIN) {
                                                m_PrivateKey.toUtf8().constData(),
              waitsocket(sock, session);
                                                m_Passphrase.isEmpty() ? nullptr : m_Passphrase.toUtf8().constData());
              prev = 0;
    } while (rc == LIBSSH2_ERROR_EAGAIN);
          }
   
   
          if (nwritten < 0) {
    if (rc) {
              qDebug() << QString("ERROR %1 total %2 / %3 prev %4").arg((int)nwritten)
      qDebug() << "認証に失敗:" << rc;
                                                                  .arg((long)total)
      return;
                                                                  .arg((int)nread)
    }
                                                                  .arg((int)prev);
              break;
          }
          else {
              prev = nread;
   
   
              // nwritten indicates how many bytes were written this time.
    openChannel();
              nread -= nwritten;
}
              ptr += nwritten;
          }
      } while (nread);
    } while (!nread);  // only continue if nread was drained.
   
   
     File.close();
void SSHClient::openChannel()
{
     int rc = 0;
    do {
        m_Channel = libssh2_channel_open_session(m_Session);
    } while (m_Channel == nullptr && libssh2_session_last_error(m_Session, nullptr, nullptr, 0) == LIBSSH2_ERROR_EAGAIN);
   
   
     // 経過時間をミリ秒単位で取得
     if (!m_Channel) {
    try {
       qDebug() << "チャンネルのオープンに失敗";
      qint64 duration = elapsedTimer.elapsed() == 0 ? throw DivideByZeroException() : elapsedTimer.elapsed();
      return;
       qDebug() << QString("%1 bytes in %2 milli-seconds makes %3 bytes/sec").arg(static_cast<long>(total))
                                                                            .arg(duration)
                                                                            .arg(QString::number((double)((total * 1000) / duration), 'f', 1));
     }
     }
     catch (const DivideByZeroException &ex) {
       qDebug() << ex.what();
     executeCommand();
       qDebug() << QString("Transfer rate could not be calculated.");
}
 
void SSHClient::executeCommand()
{
    int rc = 0;
    do {
       rc = libssh2_channel_exec(m_Channel, "ls -la");
    } while (rc == LIBSSH2_ERROR_EAGAIN);
    if (rc) {
       qDebug() << "lsコマンドの実行に失敗:" << rc;
      return;
     }
     }
   
   
     qDebug() << QString("Sending EOF");
     // lsコマンドの出力結果を取得を開始
     while(libssh2_channel_send_eof(channel) == LIBSSH2_ERROR_EAGAIN);
     QTimer::singleShot(0, this, &SSHClient::readOutput);
}
   
   
     qDebug() << QString("Waiting for EOF");
void SSHClient::onReadyRead()
     while(libssh2_channel_wait_eof(channel) == LIBSSH2_ERROR_EAGAIN);
{
     readOutput();
}
void SSHClient::readOutput()
{
     if (!m_Channel) return;
   
   
     qDebug() << QString("Waiting for channel to close");
     QByteArray buffer;
    while(libssh2_channel_wait_closed(channel) == LIBSSH2_ERROR_EAGAIN);
    buffer.resize(1024);
    int rc = 0;
    while (rc != LIBSSH2_ERROR_EAGAIN) {
      rc = libssh2_channel_read(m_Channel, buffer.data(), buffer.size());
      if (rc > 0) {
          qDebug().noquote() << QString::fromUtf8(buffer.constData(), rc);
      }
      else if (rc < 0) {
          qDebug() << "チャンネルの読み取りエラー:" << rc;
          closeChannel();
          return;
      }
    }
   
   
     return 0;
     // チャンネルがEOFかどうかを確認
    if (libssh2_channel_eof(m_Channel) == 1) {
      closeChannel();
    }
    else {
      // 続きを読み込む
      QTimer::singleShot(0, this, &SSHClient::readOutput);
    }
  }
  }
   
   
  int waitsocket(libssh2_socket_t socket_fd, LIBSSH2_SESSION *session)
  void SSHClient::closeChannel()
  {
  {
     struct timeval timeout = {};
     if (!m_Channel) return;
     timeout.tv_sec = 10;
     timeout.tv_usec = 0;
    int rc = 0;
    do {
      rc = libssh2_channel_close(m_Channel);
    } while (rc == LIBSSH2_ERROR_EAGAIN);
     if (rc == 0) {
      int exitcode    = libssh2_channel_get_exit_status(m_Channel);
      char *exitsignal = nullptr;
      libssh2_channel_get_exit_signal(m_Channel, &exitsignal, nullptr, nullptr, nullptr, nullptr, nullptr);
      if (exitsignal) {
          qDebug() << "Exit signal:" << exitsignal;
      }
      else {
          qDebug() << "Exit code:" << exitcode;
      }
    }
   
    libssh2_channel_free(m_Channel);
     m_Channel = nullptr;
   
   
     fd_set fd;
     // Disconnect from the host
     FD_ZERO(&fd);
     m_Socket->disconnectFromHost();
    FD_SET(socket_fd, &fd);
}
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
   
   
    // now make sure we wait in the correct direction.
int main(int argc, char *argv[])
     auto dir = libssh2_session_block_directions(session);
{
     QCoreApplication a(argc, argv);
   
   
     fd_set *writefd = nullptr;
     // パスワード認証を行う場合
     fd_set *readfd  = nullptr;
     //SSHClient client("<リモートPC側のIPアドレスまたはホスト名>", <リモートPCのポート番号>,
    if(dir & LIBSSH2_SESSION_BLOCK_INBOUND)    readfd  = &fd;
     //                "<リモートPC側のユーザ名>", "<リモートPC側のユーザパスワード>");
     if(dir & LIBSSH2_SESSION_BLOCK_OUTBOUND)   writefd = &fd;
   
   
     auto rc = select((int)(socket_fd + 1), readfd, writefd, nullptr, &timeout);
     // 公開鍵認証を行う場合
    SSHClient client("<リモートPC側のIPアドレスまたはホスト名>", <リモートPCのポート番号>,
                    "<リモートPC側のユーザ名>",
                    "<公開鍵ファイルのパス>", // クライアントPCに秘密鍵があり、リモートPC側に公開鍵が設置されている場合は空欄 ("") にする
                    "<秘密鍵ファイルのパス>",
                    "<秘密鍵のパスフレーズ>");
   
   
     return rc;
    client.connectToHost();
     return a.exec();
  }
  }
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
== SCPコマンドの使用例 ==
libSSHライブラリおよびlibSSH2ライブラリを使用したSCPコマンドの使用例は、以下に示すページに記載している。<br>
* [[Qtの基礎_-_SCP#libSSHライブラリを使用したSCPコマンドの使用例|libSSHライブラリを使用したSCPコマンドの使用例]]
* [[Qtの基礎_-_SCP#libSSH2ライブラリを使用したSCPコマンドの使用例|libSSH2ライブラリを使用したSCPコマンドの使用例]]
<br><br>
== sshdコマンドの使用 ==
==== OpenSSHのソースコードのダウンロード ====
[https://www.openssh.com/portable.html OpenSSHの公式Webサイト]にアクセスして、ソースコードをダウンロードする。<br>
ダウンロードしたファイルを解凍する。<br>
tar xf openssh-<バージョン>.tar.gz
<br>
このディレクトリ内に必要なヘッダファイル等が存在する。<br>
<br>
なお、OpenSSHのライセンスの全てのコンポーネントは、BSDライセンス、もしくはそれよりも自由なライセンスに属している。<br>
<br>
==== sshd -tコマンド ====
以下の例では、openSSHライブラリを使用して、<code>sshd -t</code>コマンドと同様、指定された設定ファイルの解析と妥当性を確認している。<br>
<br>
# <code>initialize_server_options</code>関数を呼び出して、サーバオプションを初期化する。
# コマンドライン引数からSSHの設定ファイルのパスを取得する。<br>引数が指定されていない場合は、デフォルトの"sshd_config"ファイルを使用する。
# <code>parse_server_config_depth</code>関数を呼び出して、指定されたSSHの設定ファイルを解析する。<br>解析に成功した場合は<code>0</code>、失敗した場合は<code>0以外</code>の値を返す。
# <code>validate_server_config</code>関数を呼び出して、解析された設定ファイルの妥当性を確認する。<br>確認に成功した場合は<code>0</code>、失敗した場合は<code>0以外</code>の値を返す。
# SSHの設定ファイルの解析と妥当性の結果に応じて、成功または失敗のメッセージを表示している。
<br>
<br>
  <syntaxhighlight lang="c++">
  <syntaxhighlight lang="c++">
  // DivideByZeroException.h
  #include <QCoreApplication>
#include <QDebug>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sshbuf.h>
#include <sshkey.h>
#include <authfile.h>
#include <auth-options.h>
#include <servconf.h>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ServerOptions options;
    initialize_server_options(&options);
    // コマンドライン引数からSSHの設定ファイルのパスを取得
    QString configFile = "sshd_config";
    if (a.arguments().size() > 1) {
      configFile = a.arguments().at(1);
    }
    // SSHの設定ファイルの解析
    if (parse_server_config_depth(&options, configFile.toUtf8().constData(), NULL, 0) != 0) {
      qDebug() << QString("SSHの設定ファイルのパースに失敗: %1).arg(configFile);
      return -1;
    }
    // SSHの設定ファイルの妥当性を確認
    if (validate_server_config(&options) != 0) {
      qDebug() << QString("SSHの設定ファイルに誤りがあります: %1").arg(configFile);
      return -1;
    }
   
   
#ifndef DIVIDEBYZEROEXCEPTION_H
    qDebug() << QString("SSHの設定ファイル (%1) は正常です).arg(configFile);
#define DIVIDEBYZEROEXCEPTION_H
   
   
  #include <QException>
    return 0;
}
</syntaxhighlight>
<br>
==== sshd -Tコマンド ====
以下の例では、openSSHライブラリを使用して、<code>sshd -T</code>コマンドと同様、現在の設定オプションの値をダンプ形式で表示している。<br>
<br>
# <code>initialize_server_options</code>関数を呼び出して、サーバオプションを初期化する。
# <code>fill_default_server_options</code>関数を呼び出して、デフォルトのサーバオプションを設定する。
# <code>parse_server_config_depth</code>関数を呼び出して、sshd_configファイルを解析する。<br>解析に成功した場合は<code>0</code>、失敗した場合は<code>0以外</code>の値を返す。
# 解析に成功した場合は、<code>dump_config</code>関数を呼び出して、設定オプションのダンプを表示する。<br>これは、<code>sshd -T</code>コマンドと同様、現在の設定オプションの値を表示する。
<br>
<syntaxhighlight lang="c++">
#include <QCoreApplication>
#include <QDebug>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sshbuf.h>
#include <sshkey.h>
#include <authfile.h>
#include <auth-options.h>
  #include <servconf.h>
   
   
  class DivideByZeroException : public QException
  int main(int argc, char *argv[])
  {
  {
  public:
    QCoreApplication a(argc, argv);
     DivideByZeroException() {};
     virtual ~DivideByZeroException() {};
    // SSHの設定ファイルオプション
    ServerOptions options;
   
     initialize_server_options(&options);
     fill_default_server_options(&options);
   
   
     const char* what() const noexcept override {
     if (parse_server_config_depth(&options, "sshd_config", NULL, 0) != 0) {
       return "Divide by zero exception";
       qDebug() << "sshd_configファイルのパースに失敗";
      return -1;
     }
     }
};
   
   
  #endif // DIVIDEBYZEROEXCEPTION_H
    qDebug() << "========= Dump of configuration options =========";
    dump_config(&options);
    qDebug() << "================================================";
   
    return 0;
}
  </syntaxhighlight>
  </syntaxhighlight>
<br><br>
<br><br>


{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]