On 04.01.2012 00:47, Peter Krempa wrote:
This patch adds a glue layer to enable using libssh2 code with the
network client code.
As in the original client implementation, shell code is sent to the
server to detect correct options for netcat.
*src/rpc/virnetclient.c:
*src/rpc/virnetclient.h: Add function to handle connection to a libvirt
daemon using the libssh2 transport.
---
src/rpc/virnetclient.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++-
src/rpc/virnetclient.h | 11 ++++++
2 files changed, 100 insertions(+), 2 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 469c6a5..b0cb8d2 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -383,6 +383,72 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
return virNetClientNew(sock, NULL);
}
+virNetClientPtr virNetClientNewLibSSH(const char *host,
+ const char *port,
+ const char *username,
+ const char *password,
+ const char *netcat,
+ const char *socketPath,
+ const char *knownHostsFile,
+ const char *hostkeyVerify,
+ const char *privkey,
+ virConnectAuthPtr auth)
+{
+ virNetSocketPtr sock;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ char *nc = NULL;
+
+ if (!host)
+ host = "localhost";
+
+ if (!port)
+ port = "22";
+
+ if (!username)
+ username = "root";
+
+ if (netcat) {
+ virBufferEscapeShell(&buf, netcat);
+ nc = virBufferContentAndReset(&buf);
+ } else {
+ nc = strdup("nc");
+ }
+
+ if (!nc) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ virBufferAsprintf(&buf,
+ "sh -c "
+ "'if '%s' -q 2>&1 | grep \"requires an
argument\" >/dev/null 2>&1; then "
+ "ARG=-q0;"
+ "else "
+ "ARG=;"
+ "fi;"
+ "'%s' $ARG -U %s'",
+ nc, nc, socketPath);
I wonder if we can reuse the code from virNetSocketNewConnectSSH().
+
+ VIR_FREE(nc);
+
+ if (virBufferError(&buf)) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ nc = virBufferContentAndReset(&buf);
+
+ if (virNetSocketNewConnectLibSSH(host, port, username, password, nc,
+ knownHostsFile, hostkeyVerify,
+ privkey, auth, &sock) != 0) {
+ VIR_FREE(nc);
+ return NULL;
+ }
+
+ VIR_FREE(nc);
+ return virNetClientNew(sock, NULL);
+}
+
virNetClientPtr virNetClientNewExternal(const char **cmdargv)
{
virNetSocketPtr sock;
@@ -964,6 +1030,7 @@ virNetClientIOWriteMessage(virNetClientPtr client,
virNetClientCallPtr thecall)
{
ssize_t ret = 0;
+ virErrorPtr err;
if (thecall->msg->bufferOffset < thecall->msg->bufferLength) {
ret = virNetSocketWrite(client->sock,
@@ -971,8 +1038,18 @@ virNetClientIOWriteMessage(virNetClientPtr client,
thecall->msg->bufferLength -
thecall->msg->bufferOffset);
if (ret > 0 || virNetSocketHasPendingData(client->sock))
thecall->sentSomeData = true;
- if (ret <= 0)
+ if (ret <= 0) {
+ if ((err = virGetLastError())) {
+ if (err->domain == VIR_FROM_LIBSSH &&
+ err->code == VIR_ERR_LIBSSH_REMOTE_COMMAND) {
+ virResetLastError();
+ virNetError(VIR_ERR_LIBSSH_REMOTE_COMMAND,
+ _("Remote daemon is not running or remote "
+ "command has failed"));
+ }
+ }
return ret;
+ }
thecall->msg->bufferOffset += ret;
}
@@ -1637,6 +1714,7 @@ void virNetClientIncomingEvent(virNetSocketPtr sock,
void *opaque)
{
virNetClientPtr client = opaque;
+ virErrorPtr err;
virNetClientLock(client);
@@ -1657,7 +1735,16 @@ void virNetClientIncomingEvent(virNetSocketPtr sock,
}
if (virNetClientIOHandleInput(client) < 0) {
- VIR_WARN("Something went wrong during async message processing");
+ /* translate error message if we're using libssh transport */
+ if ((err = virGetLastError()) &&
+ (err->domain == VIR_FROM_LIBSSH &&
+ err->code == VIR_ERR_LIBSSH_REMOTE_COMMAND)) {
+ virNetError(VIR_ERR_NO_CONNECT, "%s",
+ _("Remote daemon is not running or remote command
"
+ "has failed"));
+ } else {
+ VIR_WARN("Something went wrong during async message processing");
+ }
virNetSocketRemoveIOCallback(sock);
}
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h
index 61d51e1..9157852 100644
--- a/src/rpc/virnetclient.h
+++ b/src/rpc/virnetclient.h
@@ -49,6 +49,17 @@ virNetClientPtr virNetClientNewSSH(const char *nodename,
const char *keyfile,
const char *path);
+virNetClientPtr virNetClientNewLibSSH(const char *host,
+ const char *port,
+ const char *username,
+ const char *password,
+ const char *netcat,
+ const char *socketPath,
+ const char *knownHostsFile,
+ const char *hostkeyVerify,
+ const char *privkey,
+ virConnectAuthPtr auth);
+
virNetClientPtr virNetClientNewExternal(const char **cmdargv);
void virNetClientRef(virNetClientPtr client);
Otherwise looking good.