#define VIR_FROM_THIS VIR_FROM_REMOTE
+#define SSH_BUF_SIZE (1024 * 1024)
+
VIR_LOG_INIT("remote.remote_ssh_helper");
struct virRemoteSSHHelperBuffer {
struct virRemoteSSHHelper {
bool quit;
virNetSocketPtr sock;
+ int sockEvents;
int stdinWatch;
+ int stdinEvents;
int stdoutWatch;
+ int stdoutEvents;
struct virRemoteSSHHelperBuffer sockToTerminal;
struct virRemoteSSHHelperBuffer terminalToSock;
}
+static void
+virRemoteSSHHelperUpdateEvents(virRemoteSSHHelperPtr proxy)
+{
+ int sockEvents = 0;
+ int stdinEvents = 0;
+ int stdoutEvents = 0;
+
+ if (proxy->terminalToSock.offset != 0)
+ sockEvents |= VIR_EVENT_HANDLE_WRITABLE;
+ if (proxy->terminalToSock.offset < proxy->terminalToSock.length)
+ stdinEvents |= VIR_EVENT_HANDLE_READABLE;
+
+ if (proxy->sockToTerminal.offset != 0)
+ stdoutEvents |= VIR_EVENT_HANDLE_WRITABLE;
+ if (proxy->sockToTerminal.offset < proxy->sockToTerminal.length)
+ sockEvents |= VIR_EVENT_HANDLE_READABLE;
+
+ if (sockEvents != proxy->sockEvents) {
+ VIR_DEBUG("Update sock events %d -> %d", proxy->sockEvents, sockEvents);
+ virNetSocketUpdateIOCallback(proxy->sock, sockEvents);
+ proxy->sockEvents = sockEvents;
+ }
+ if (stdinEvents != proxy->stdinEvents) {
+ VIR_DEBUG("Update stdin events %d -> %d", proxy->stdinEvents, stdinEvents);
+ virEventUpdateHandle(proxy->stdinWatch, stdinEvents);
+ proxy->stdinEvents = stdinEvents;
+ }
+ if (stdoutEvents != proxy->stdoutEvents) {
+ VIR_DEBUG("Update stdout events %d -> %d", proxy->stdoutEvents, stdoutEvents);
+ virEventUpdateHandle(proxy->stdoutWatch, stdoutEvents);
+ proxy->stdoutEvents = stdoutEvents;
+ }
+}
+
static void
virRemoteSSHHelperEventOnSocket(virNetSocketPtr sock,
int events,
proxy->sockToTerminal.offset;
int got;
- if (avail < 1024) {
- if (VIR_REALLOC_N(proxy->sockToTerminal.data,
- proxy->sockToTerminal.length + 1024) < 0) {
- virRemoteSSHHelperShutdown(proxy);
- return;
- }
- proxy->sockToTerminal.length += 1024;
- avail += 1024;
+ if (avail == 0) {
+ VIR_DEBUG("Unexpectedly called with no space in buffer");
+ goto cleanup;
}
got = virNetSocketRead(sock,
return;
}
proxy->sockToTerminal.offset += got;
- if (proxy->sockToTerminal.offset)
- virEventUpdateHandle(proxy->stdoutWatch,
- VIR_EVENT_HANDLE_WRITABLE);
}
if (events & VIR_EVENT_HANDLE_WRITABLE &&
proxy->terminalToSock.offset) {
ssize_t done;
- size_t avail;
done = virNetSocketWrite(proxy->sock,
proxy->terminalToSock.data,
proxy->terminalToSock.offset);
virRemoteSSHHelperShutdown(proxy);
return;
}
+
memmove(proxy->terminalToSock.data,
proxy->terminalToSock.data + done,
proxy->terminalToSock.offset - done);
proxy->terminalToSock.offset -= done;
-
- avail = proxy->terminalToSock.length - proxy->terminalToSock.offset;
- if (avail > 1024) {
- ignore_value(VIR_REALLOC_N(proxy->terminalToSock.data,
- proxy->terminalToSock.offset + 1024));
- proxy->terminalToSock.length = proxy->terminalToSock.offset + 1024;
- }
}
- if (!proxy->terminalToSock.offset)
- virNetSocketUpdateIOCallback(proxy->sock,
- VIR_EVENT_HANDLE_READABLE);
if (events & VIR_EVENT_HANDLE_ERROR ||
events & VIR_EVENT_HANDLE_HANGUP) {
virRemoteSSHHelperShutdown(proxy);
+ return;
}
+
+ cleanup:
+ virRemoteSSHHelperUpdateEvents(proxy);
}
proxy->terminalToSock.offset;
int got;
- if (avail < 1024) {
- if (VIR_REALLOC_N(proxy->terminalToSock.data,
- proxy->terminalToSock.length + 1024) < 0) {
- virRemoteSSHHelperShutdown(proxy);
- return;
- }
- proxy->terminalToSock.length += 1024;
- avail += 1024;
+ if (avail == 0) {
+ VIR_DEBUG("Unexpectedly called with no space in buffer");
+ goto cleanup;
}
got = read(fd,
}
proxy->terminalToSock.offset += got;
- if (proxy->terminalToSock.offset)
- virNetSocketUpdateIOCallback(proxy->sock,
- VIR_EVENT_HANDLE_READABLE |
- VIR_EVENT_HANDLE_WRITABLE);
}
if (events & VIR_EVENT_HANDLE_ERROR) {
virRemoteSSHHelperShutdown(proxy);
return;
}
+
+ cleanup:
+ virRemoteSSHHelperUpdateEvents(proxy);
}
if (events & VIR_EVENT_HANDLE_WRITABLE &&
proxy->sockToTerminal.offset) {
ssize_t done;
- size_t avail;
done = write(fd,
proxy->sockToTerminal.data,
proxy->sockToTerminal.offset);
proxy->sockToTerminal.data + done,
proxy->sockToTerminal.offset - done);
proxy->sockToTerminal.offset -= done;
-
- avail = proxy->sockToTerminal.length - proxy->sockToTerminal.offset;
- if (avail > 1024) {
- ignore_value(VIR_REALLOC_N(proxy->sockToTerminal.data,
- proxy->sockToTerminal.offset + 1024));
- proxy->sockToTerminal.length = proxy->sockToTerminal.offset + 1024;
- }
}
- if (!proxy->sockToTerminal.offset)
- virEventUpdateHandle(proxy->stdoutWatch, 0);
-
if (events & VIR_EVENT_HANDLE_ERROR) {
virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("IO error stdout"));
virRemoteSSHHelperShutdown(proxy);
virRemoteSSHHelperShutdown(proxy);
return;
}
+
+ virRemoteSSHHelperUpdateEvents(proxy);
}
int ret = -1;
virRemoteSSHHelper proxy = {
.sock = sock,
+ .sockEvents = VIR_EVENT_HANDLE_READABLE,
.stdinWatch = -1,
+ .stdinEvents = VIR_EVENT_HANDLE_READABLE,
.stdoutWatch = -1,
+ .stdoutEvents = 0,
+ .sockToTerminal = {
+ .offset = 0,
+ .length = SSH_BUF_SIZE,
+ .data = g_new0(char, SSH_BUF_SIZE),
+ },
+ .terminalToSock = {
+ .offset = 0,
+ .length = SSH_BUF_SIZE,
+ .data = g_new0(char, SSH_BUF_SIZE),
+ },
};
virEventRegisterDefaultImpl();