* configure.in Makefile.am proxy/Makefile.am proxy/libvirt_proxy.c

proxy/proxy.h proxy/proxy_client.c src/internal.h src/xen_internal.c
  src/xend_internal.c: started working on a proxy to access xend
  for unpriviledged users to avoid opening xend HTTP service to
  serve those read-only operations.
Daniel
This commit is contained in:
Daniel Veillard 2006-06-28 18:19:13 +00:00
parent b62cdc1405
commit 27b7a8be52
11 changed files with 1269 additions and 5 deletions

View File

@ -1,3 +1,11 @@
Wed Jun 28 19:23:25 CEST 2006 Daniel Veillard <veillard@redhat.com>
* configure.in Makefile.am proxy/Makefile.am proxy/libvirt_proxy.c
proxy/proxy.h proxy/proxy_client.c src/internal.h src/xen_internal.c
src/xend_internal.c: started working on a proxy to access xend
for unpriviledged users to avoid opening xend HTTP service to
serve those read-only operations.
Mon Jun 26 16:05:27 CEST 2006 Daniel Veillard <veillard@redhat.com>
* configure.in libvirt.spec.in docs/examples/* include/Makefile.am

View File

@ -1,6 +1,6 @@
## Process this file with automake to produce Makefile.in
SUBDIRS = src include docs @PYTHON_SUBDIR@ tests
SUBDIRS = src include docs @PYTHON_SUBDIR@ tests proxy
EXTRA_DIST = libvirt.spec.in libvirt.spec COPYING.LIB \
libvirt.pc.in libvirt.pc TODO AUTHORS ChangeLog \

View File

@ -256,4 +256,4 @@ AC_OUTPUT(Makefile src/Makefile include/Makefile docs/Makefile \
libvirt.pc libvirt.spec \
include/libvirt/Makefile include/libvirt/libvirt.h \
python/Makefile python/tests/Makefile \
tests/Makefile)
tests/Makefile proxy/Makefile)

View File

@ -44,7 +44,8 @@ typedef enum {
VIR_FROM_SEXPR, /* Error in the S-Epression code */
VIR_FROM_XML, /* Error in the XML code */
VIR_FROM_DOM, /* Error when operating on a domain */
VIR_FROM_RPC /* Error in the XML-RPC code */
VIR_FROM_RPC, /* Error in the XML-RPC code */
VIR_FROM_PROXY /* Error in the proxy code */
} virErrorDomain;

25
proxy/Makefile.am Normal file
View File

@ -0,0 +1,25 @@
## Process this file with automake to produce Makefile.in
INCLUDES = -I$(top_builddir)/include -I@top_srcdir@/include \
-I@top_srcdir@/proxy -I@top_srcdir@/src @LIBXML_CFLAGS@ \
-DBINDIR=\""$(libexecdir)"\" \
-DBUILDDIR=\""$(top_builddir)"\" \
-DXEN_RO
bin_PROGRAMS = libvirt_proxy
LIBS=
libvirt_proxy_SOURCES = libvirt_proxy.c @top_srcdir@/src/xend_internal.c \
@top_srcdir@/src/xen_internal.c @top_srcdir@/src/virterror.c \
@top_srcdir@/src/sexpr.c
libvirt_proxy_LDFLAGS =
libvirt_proxy_DEPENDENCIES =
libvirt_proxy_LDADD =
noinst_PROGRAMS= test_proxy
test_proxy_SOURCES = proxy_client.c
test_proxy_LDFLAGS =
test_proxy_DEPENDENCIES =
test_proxy_LDADD =

514
proxy/libvirt_proxy.c Normal file
View File

@ -0,0 +1,514 @@
/*
* proxy_svr.c: root suid proxy server for Xen access to APIs with no
* side effects from unauthenticated clients.
*
* Copyright (C) 2006 Red Hat, Inc.
*
* See COPYING.LIB for the License of this software
*
* Daniel Veillard <veillard@redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include "proxy.h"
#include "internal.h"
#include "xen_internal.h"
static int fdServer = -1;
static int debug = 0;
static int done = 0;
#define MAX_CLIENT 64
static int nbClients = 0; /* client 0 is the unix listen socket */
static struct pollfd pollInfos[MAX_CLIENT + 1];
static virConnect conninfos;
static virConnectPtr conn = &conninfos;
/************************************************************************
* *
* Interfaces with the Xen hypervisor *
* *
************************************************************************/
/**
* proxyInitXen:
*
* Initialize the communication layer with Xen
*
* Returns 0 or -1 in case of error
*/
static int
proxyInitXen(void) {
int ret;
ret = xenHypervisorOpen(conn, NULL, VIR_DRV_OPEN_QUIET);
if (ret < 0) {
fprintf(stderr, "Failed to open Xen hypervisor\n");
return(-1);
}
ret = xenDaemonOpen_unix(conn, "/var/lib/xend/xend-socket");
if (ret < 0) {
fprintf(stderr, "Failed to connect to Xen daemon\n");
return(-1);
}
return(0);
}
/************************************************************************
* *
* Processing of the unix socket to listen for clients *
* *
************************************************************************/
/**
* proxyCloseUnixSocket:
*
* close the unix socket
*
* Returns 0 or -1 in case of error
*/
static int
proxyCloseUnixSocket(void) {
int ret;
if (fdServer < 0)
return(0);
ret = close(fdServer);
if (debug > 0)
fprintf(stderr, "closing unix socket %d: %d\n", fdServer, ret);
fdServer = -1;
pollInfos[0].fd = -1;
return(ret);
}
/**
* proxyListenUnixSocket:
* @path: the fileame for the socket
*
* create a new abstract socket based on that path and listen on it
*
* Returns the associated file descriptor or -1 in case of failure
*/
static int
proxyListenUnixSocket(const char *path) {
int fd;
struct sockaddr_un addr;
if (fdServer >= 0)
return(fdServer);
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Failed to create unix socket");
return(-1);
}
/*
* Abstract socket do not hit the filesystem, way more secure and
* garanteed to be atomic
*/
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
addr.sun_path[0] = '\0';
strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
/*
* now bind the socket to that address and listen on it
*/
if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Failed to bind to socket %s\n", path);
close(fd);
return (-1);
}
if (listen(fd, 30 /* backlog */ ) < 0) {
fprintf(stderr, "Failed to listen to socket %s\n", path);
close(fd);
return (-1);
}
if (debug > 0)
fprintf(stderr, "opened and bound unix socket %d\n", fd);
fdServer = fd;
pollInfos[0].fd = fd;
pollInfos[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
return (fd);
}
/**
* proxyAcceptClientSocket:
*
* Process a request to the unix socket
*
* Returns the filedescriptor of the new client or -1 in case of error
*/
static int
proxyAcceptClientSocket(void) {
int client;
socklen_t client_addrlen;
struct sockaddr client_addr;
retry:
client_addrlen = sizeof(client_addr);
client = accept(pollInfos[0].fd, &client_addr, &client_addrlen);
if (client < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "accept connection on socket %d interrupted\n",
pollInfos[0].fd);
goto retry;
}
fprintf(stderr, "Failed to accept incoming connection on socket %d\n",
pollInfos[0].fd);
done = 1;
return(-1);
}
if (nbClients >= MAX_CLIENT) {
fprintf(stderr, "Too many client registered\n");
close(client);
return(-1);
}
nbClients++;
pollInfos[nbClients].fd = client;
pollInfos[nbClients].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
if (debug > 0)
fprintf(stderr, "accept connection on socket %d for client %d\n",
client, nbClients);
return(client);
}
/************************************************************************
* *
* Processing of client sockets *
* *
************************************************************************/
/**
* proxyCloseClientSocket:
* @nr: client number
*
* Close the socket from that client, and recompact the pollInfo array
*
* Returns 0 in case of success and -1 in case of error
*/
static int
proxyCloseClientSocket(int nr) {
int ret;
ret = close(pollInfos[nr].fd);
if (ret != 0)
fprintf(stderr, "Failed to close socket %d from client %d\n",
pollInfos[nr].fd, nr);
else if (debug > 0)
fprintf(stderr, "Closed socket %d from client %d\n",
pollInfos[nr].fd, nr);
if (nr < nbClients) {
memmove(&pollInfos[nr], &pollInfos[nr + 1],
(nbClients - nr) * sizeof(pollInfos[0]));
}
nbClients--;
return(ret);
}
/**
* proxyCloseClientSockets:
*
* Close all the sockets from the clients
*/
static void
proxyCloseClientSockets(void) {
int i, ret;
for (i = 1;i <= nbClients;i++) {
ret = close(pollInfos[i].fd);
if (ret != 0)
fprintf(stderr, "Failed to close socket %d from client %d\n",
pollInfos[i].fd, i);
else if (debug > 0)
fprintf(stderr, "Closed socket %d from client %d\n",
pollInfos[i].fd, i);
}
nbClients = 0;
}
/**
* proxyWriteClientSocket:
* @nr: the client number
* @req: pointer to the packet
*
* Send back a packet to the client. If it seems write would be blocking
* then try to disconnect from it.
*
* Return 0 in case of success and -1 in case of error.
*/
static int
proxyWriteClientSocket(int nr, virProxyPacketPtr req) {
int ret;
if ((nr <= 0) || (nr > nbClients) || (req == NULL) ||
(req->len < sizeof(virProxyPacket)) || (req->len > 4096) ||
(pollInfos[nr].fd < 0)) {
fprintf(stderr, "write to client %d in error", nr);
proxyCloseClientSocket(nr);
return(-1);
}
retry:
ret = write(pollInfos[nr].fd, (char *) req, req->len);
if (ret < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "write socket %d to client %d interrupted\n",
pollInfos[nr].fd, nr);
goto retry;
}
fprintf(stderr, "write %d bytes to socket %d from client %d failed\n",
req->len, pollInfos[nr].fd, nr);
proxyCloseClientSocket(nr);
return(-1);
}
if (ret == 0) {
if (debug)
fprintf(stderr, "end of stream from client %d on socket %d\n",
nr, pollInfos[nr].fd);
proxyCloseClientSocket(nr);
return(-1);
}
if (ret != req->len) {
fprintf(stderr, "write %d of %d bytes to socket %d from client %d\n",
ret, req->len, pollInfos[nr].fd, nr);
proxyCloseClientSocket(nr);
return(-1);
}
if (debug)
fprintf(stderr, "wrote %d bytes to client %d on socket %d\n",
ret, nr, pollInfos[nr].fd);
return(0);
}
/**
* proxyReadClientSocket:
* @nr: the client number
*
* Process a read from a client socket
*/
static int
proxyReadClientSocket(int nr) {
char buffer[4096];
virProxyPacketPtr req;
int ret;
retry:
ret = read(pollInfos[nr].fd, buffer, sizeof(virProxyPacket));
if (ret < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "read socket %d from client %d interrupted\n",
pollInfos[nr].fd, nr);
goto retry;
}
fprintf(stderr, "Failed to read socket %d from client %d\n",
pollInfos[nr].fd, nr);
proxyCloseClientSocket(nr);
return(-1);
}
if (ret == 0) {
if (debug)
fprintf(stderr, "end of stream from client %d on socket %d\n",
nr, pollInfos[nr].fd);
proxyCloseClientSocket(nr);
return(-1);
}
if (debug)
fprintf(stderr, "read %d bytes from client %d on socket %d\n",
ret, nr, pollInfos[nr].fd);
req = (virProxyPacketPtr) &buffer[0];
if ((req->version != PROXY_PROTO_VERSION) ||
(req->len < sizeof(virProxyPacket)))
goto comm_error;
if (debug)
fprintf(stderr, "Gor command %d from client %d\n", req->command, nr);
switch (req->command) {
case VIR_PROXY_NONE:
if (req->len != sizeof(virProxyPacket))
goto comm_error;
break;
case VIR_PROXY_VERSION:
if (req->len != sizeof(virProxyPacket))
goto comm_error;
TODO;
req->data.larg = 3 * 1000000 + 2;
break;
case VIR_PROXY_NODE_INFO:
case VIR_PROXY_LIST:
case VIR_PROXY_NUM_DOMAIN:
case VIR_PROXY_LOOKUP_ID:
case VIR_PROXY_LOOKUP_UUID:
case VIR_PROXY_LOOKUP_NAME:
case VIR_PROXY_MAX_MEMORY:
case VIR_PROXY_DOMAIN_INFO:
break;
default:
goto comm_error;
}
ret = proxyWriteClientSocket(nr, req);
return(ret);
comm_error:
fprintf(stderr,
"Communication error with client %d: malformed packet\n", nr);
proxyCloseClientSocket(nr);
return(-1);
}
/************************************************************************
* *
* Main loop processing *
* *
************************************************************************/
/**
* proxyProcessRequests:
*
* process requests and timers
*/
static void
proxyProcessRequests(void) {
int exit_timeout = 30;
int ret, i;
while (!done) {
/*
* wait for requests, with a one second timeout
*/
ret = poll(&pollInfos[0], nbClients + 1, 1000);
if (ret == 0) { /* timeout */
if (nbClients == 0) {
exit_timeout--;
if (exit_timeout == 0) {
done = 1;
if (debug > 0) {
fprintf(stderr, "Exitting after 30s without clients\n");
}
}
} else
exit_timeout = 30;
if (debug > 1)
fprintf(stderr, "poll timeout\n");
continue;
} else if (ret < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "poll syscall interrupted\n");
continue;
}
fprintf(stderr, "poll syscall failed\n");
break;
}
/*
* there have been I/O to process
*/
exit_timeout = 30;
if (pollInfos[0].revents != 0) {
if (pollInfos[0].revents & POLLIN) {
proxyAcceptClientSocket();
} else {
fprintf(stderr, "Got an error %d on incoming socket %d\n",
pollInfos[0].revents, pollInfos[0].fd);
break;
}
}
/*
* process the clients in reverse order since on error or disconnect
* pollInfos is compacted to remove the given client.
*/
for (i = nbClients;i > 0;i--) {
if (pollInfos[i].revents & POLLIN) {
proxyReadClientSocket(i);
} else if (pollInfos[i].revents != 0) {
fprintf(stderr, "Got an error %d on client %d socket %d\n",
pollInfos[i].revents, i, pollInfos[i].fd);
proxyCloseClientSocket(i);
}
}
}
}
/**
* proxyMainLoop:
*
* main loop for the proxy, continually try to keep the unix socket
* open, serve client requests, and process timing events.
*/
static void
proxyMainLoop(void) {
while (! done) {
if (proxyListenUnixSocket(PROXY_SOCKET_PATH) < 0)
break;
proxyProcessRequests();
proxyCloseUnixSocket();
}
proxyCloseClientSockets();
proxyCloseUnixSocket();
}
/**
* usage:
*
* dump on stdout informations about the program
*/
static void
usage(const char *progname) {
printf("Usage: %s [-v] [-v]\n", progname);
printf(" option -v increase the verbosity level for debugging\n");
printf("This is a proxy for xen services used by libvirt to offer\n");
printf("safe and fast status information on the Xen virtualization.\n");
printf("This need not be run manually it's started automatically.\n");
}
/**
* main:
*
* Check that we are running with root priviledges, initialize the
* connections to the daemon and or hypervisor, and then run the main loop
*/
int main(int argc, char **argv) {
int i;
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-v")) {
debug++;
} else {
usage(argv[0]);
exit(1);
}
}
if (geteuid() != 0) {
fprintf(stderr, "%s must be run as root or suid\n", argv[0]);
/* exit(1); */
}
proxyInitXen();
proxyMainLoop();
exit(0);
}

68
proxy/proxy.h Normal file
View File

@ -0,0 +1,68 @@
/*
* proxy.h: common definitions for proxy usage
*
* Copyright (C) 2006 Red Hat, Inc.
*
* See COPYING.LIB for the License of this software
*
* Daniel Veillard <veillard@redhat.com>
*/
#ifndef __LIBVIR_PROXY_H__
#define __LIBVIR_PROXY_H__
#include <libvirt/libvirt.h>
#ifdef __cplusplus
extern "C" {
#endif
#define PROXY_SOCKET_PATH "/tmp/livirt_proxy_conn"
#define PROXY_PROTO_VERSION 1
/*
* the command allowed though the proxy
*/
typedef enum {
VIR_PROXY_NONE = 0,
VIR_PROXY_VERSION = 1,
VIR_PROXY_NODE_INFO = 2,
VIR_PROXY_LIST = 3,
VIR_PROXY_NUM_DOMAIN = 4,
VIR_PROXY_LOOKUP_ID = 5,
VIR_PROXY_LOOKUP_UUID = 6,
VIR_PROXY_LOOKUP_NAME = 7,
VIR_PROXY_MAX_MEMORY = 8,
VIR_PROXY_DOMAIN_INFO = 9
} virProxyCommand;
/*
* structure used by the client to make a request to the proxy
* and by the proxy when answering the client.
* the size may not be fixed, it's passed as len.
*/
struct _virProxyPacket {
unsigned short version; /* version of the proxy protocol */
unsigned short command; /* command number a virProxyCommand */
unsigned short serial; /* command serial number */
unsigned short len; /* the length of the request */
union {
char string[8]; /* string data */
int arg; /* or int argument */
long larg; /* or long argument */
} data;
};
typedef struct _virProxyPacket virProxyPacket;
typedef virProxyPacket *virProxyPacketPtr;
/*
* Functions callable from libvirt library
*/
int xenProxyInit(virConnectPtr conn);
void xenProxyClose(virConnectPtr conn);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __LIBVIR_PROXY_H__ */

632
proxy/proxy_client.c Normal file
View File

@ -0,0 +1,632 @@
/*
* proxy_client.c: client side of the communication with the libvirt proxy.
*
* Copyright (C) 2006 Red Hat, Inc.
*
* See COPYING.LIB for the License of this software
*
* Daniel Veillard <veillard@redhat.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include "proxy.h"
#include "internal.h"
#define STANDALONE
static int debug = 1;
/************************************************************************
* *
* Error handling *
* *
************************************************************************/
/**
* virProxyError:
* @conn: the connection if available
* @error: the error noumber
* @info: extra information string
*
* Handle an error at the xend daemon interface
*/
static void
virProxyError(virConnectPtr conn, virErrorNumber error, const char *info)
{
const char *errmsg;
if (error == VIR_ERR_OK)
return;
#if 0
errmsg = __virErrorMsg(error, info);
__virRaiseError(conn, NULL, VIR_FROM_XEND, error, VIR_ERR_ERROR,
errmsg, info, NULL, 0, 0, errmsg, info);
#endif
}
/************************************************************************
* *
* Automatic startup of the proxy server if it is not running *
* *
************************************************************************/
/**
* virProxyFindServerPath:
*
* Tries to find the path to the gam_server binary.
*
* Returns path on success or NULL in case of error.
*/
static const char *
virProxyFindServerPath(void)
{
static const char *serverPaths[] = {
#ifdef STANDALONE
"./libvirt_proxy",
BUILDDIR "/proxy/libvirt_proxy",
#endif
BINDIR "/libvirt_proxy",
NULL
};
int i;
const char *debugProxy = getenv("LIBVIRT_DEBUG_PROXY");
if (debugProxy)
return(debugProxy);
for (i = 0; serverPaths[i]; i++) {
if (access(serverPaths[i], X_OK | R_OK) == 0) {
return serverPaths[i];
}
}
return NULL;
}
/**
* virProxyForkServer:
*
* Forks and try to launch the proxy server processing the requests for
* libvirt when communicating with Xen.
*
* Returns 0 in case of success or -1 in case of detected error.
*/
static int
virProxyForkServer(void)
{
const char *proxyPath = virProxyFindServerPath();
int ret, pid, status;
if (!proxyPath) {
fprintf(stderr, "failed to find libvirt_proxy\n");
return(-1);
}
if (debug)
fprintf(stderr, "Asking to launch %s\n", proxyPath);
/* Become a daemon */
pid = fork();
if (pid == 0) {
long open_max;
long i;
/* don't hold open fd opened from the client of the library */
open_max = sysconf (_SC_OPEN_MAX);
for (i = 0; i < open_max; i++)
fcntl (i, F_SETFD, FD_CLOEXEC);
setsid();
if (fork() == 0) {
execl(proxyPath, proxyPath, NULL);
fprintf(stderr, "failed to exec %s\n", proxyPath);
}
/*
* calling exit() generate troubles for termination handlers
*/
_exit(0);
}
/*
* do a waitpid on the intermediate process to avoid zombies.
*/
retry_wait:
ret = waitpid(pid, &status, 0);
if (ret < 0) {
if (errno == EINTR)
goto retry_wait;
}
return (0);
}
/************************************************************************
* *
* Processing of client sockets *
* *
************************************************************************/
/**
* virProxyOpenClientSocket:
* @path: the fileame for the socket
*
* try to connect to the socket open by libvirt_proxy
*
* Returns the associated file descriptor or -1 in case of failure
*/
static int
virProxyOpenClientSocket(const char *path) {
int fd;
struct sockaddr_un addr;
int trials = 0;
retry:
fd = socket(PF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
fprintf(stderr, "Failed to create unix socket");
return(-1);
}
/*
* Abstract socket do not hit the filesystem, way more secure and
* garanteed to be atomic
*/
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
addr.sun_path[0] = '\0';
strncpy(&addr.sun_path[1], path, (sizeof(addr) - 4) - 2);
/*
* now bind the socket to that address and listen on it
*/
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
fprintf(stderr, "Failed to connect to socket %s\n", path);
close(fd);
if (trials < 3) {
if (virProxyForkServer() < 0)
return(-1);
trials++;
usleep(5000 * trials * trials);
goto retry;
}
return (-1);
}
if (debug > 0)
fprintf(stderr, "connected to unix socket %s via %d\n", path, fd);
return (fd);
}
/**
* virProxyCloseClientSocket:
* @fd: the file descriptor for the socket
*
* Close the socket from that client
*
* Returns 0 in case of success and -1 in case of error
*/
static int
virProxyCloseClientSocket(int fd) {
int ret;
if (fd < 0)
return(-1);
ret = close(fd);
if (ret != 0)
fprintf(stderr, "Failed to close socket %d\n", fd);
else if (debug > 0)
fprintf(stderr, "Closed socket %d\n", fd);
return(ret);
}
/**
* virProxyReadClientSocket:
* @fd: the socket
* @buffer: the target memory area
* @len: the lenght in bytes
*
* Process a read from a client socket
*
* Returns the number of byte read or -1 in case of error.
*/
static int
virProxyReadClientSocket(int fd, char *buffer, int len) {
int ret;
if ((fd < 0) || (buffer == NULL) || (len < 0))
return(-1);
retry:
ret = read(fd, buffer, len);
if (ret < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "read socket %d interrupted\n", fd);
goto retry;
}
fprintf(stderr, "Failed to read socket %d\n", fd);
return(-1);
}
if (debug)
fprintf(stderr, "read %d bytes from socket %d\n",
ret, fd);
return(ret);
}
/**
* virProxyWriteClientSocket:
* @fd: the socket
* @data: the data
* @len: the lenght of data in bytes
*
* Process a read from a client socket
*/
static int
virProxyWriteClientSocket(int fd, const char *data, int len) {
int ret;
if ((fd < 0) || (data == NULL) || (len < 0))
return(-1);
retry:
ret = write(fd, data, len);
if (ret < 0) {
if (errno == EINTR) {
if (debug > 0)
fprintf(stderr, "write socket %d, %d bytes interrupted\n",
fd, len);
goto retry;
}
fprintf(stderr, "Failed to write to socket %d\n", fd);
return(-1);
}
if (debug)
fprintf(stderr, "wrote %d bytes to socket %d\n",
len, fd);
return(0);
}
/************************************************************************
* *
* Proxy commands processing *
* *
************************************************************************/
/**
* xenProxyClose:
* @conn: pointer to the hypervisor connection
*
* Shutdown the Xen proxy communication layer
*/
void
xenProxyClose(virConnectPtr conn) {
if ((conn == NULL) || (conn->proxy < 0))
return;
virProxyCloseClientSocket(conn->proxy);
conn->proxy = -1;
}
static int
xenProxyCommand(virConnectPtr conn, virProxyPacketPtr request,
virProxyPacketPtr *answer) {
static int serial = 0;
int ret;
virProxyPacketPtr res = NULL;
char packet[4096];
if ((conn == NULL) || (conn->proxy < 0))
return(-1);
/*
* normal communication serial numbers are in 0..4095
*/
++serial;
if (serial >= 4096)
serial = 0;
request->version = PROXY_PROTO_VERSION;
request->serial = serial;
ret = virProxyWriteClientSocket(conn->proxy, (const char *) request,
request->len);
if (ret < 0)
return(-1);
retry:
if (answer == NULL) {
/* read in situ */
ret = virProxyReadClientSocket(conn->proxy, (char *) request,
sizeof(virProxyPacket));
if (ret < 0)
return(-1);
if (ret != sizeof(virProxyPacket)) {
fprintf(stderr,
"Communication error with proxy: got %d bytes of %d\n",
ret, sizeof(virProxyPacket));
xenProxyClose(conn);
return(-1);
}
res = request;
if (res->len != sizeof(virProxyPacket)) {
fprintf(stderr,
"Communication error with proxy: expected %d bytes got %d\n",
sizeof(virProxyPacket), res->len);
xenProxyClose(conn);
return(-1);
}
} else {
/* read in packet and duplicate if needed */
ret = virProxyReadClientSocket(conn->proxy, &packet[0],
sizeof(virProxyPacket));
if (ret < 0)
return(-1);
if (ret != sizeof(virProxyPacket)) {
fprintf(stderr,
"Communication error with proxy: got %d bytes of %d\n",
ret, sizeof(virProxyPacket));
xenProxyClose(conn);
return(-1);
}
res = (virProxyPacketPtr) &packet[0];
if ((res->len < sizeof(virProxyPacket)) ||
(res->len > sizeof(packet))) {
fprintf(stderr,
"Communication error with proxy: got %d bytes packet\n",
res->len);
xenProxyClose(conn);
return(-1);
}
if (res->len > sizeof(virProxyPacket)) {
ret = virProxyReadClientSocket(conn->proxy, &packet[ret],
res->len - ret);
if (ret != (int) (res->len - sizeof(virProxyPacket))) {
fprintf(stderr,
"Communication error with proxy: got %d bytes of %d\n",
ret, sizeof(virProxyPacket));
xenProxyClose(conn);
return(-1);
}
}
}
/*
* do more checks on the incoming packet.
*/
if ((res == NULL) || (res->version != PROXY_PROTO_VERSION) ||
(res->len < sizeof(virProxyPacket))) {
fprintf(stderr,
"Communication error with proxy: malformed packet\n");
xenProxyClose(conn);
return(-1);
}
if (res->serial != serial) {
TODO /* Asynchronous communication */
fprintf(stderr, "gor asynchronous packet number %d\n", res->serial);
goto retry;
}
if (answer != NULL)
*answer = res;
return(0);
}
/**
* xenProxyInit:
* @conn: pointer to the hypervisor connection
*
* Try to initialize the Xen proxy communication layer
*
* Returns 0 in case of success, and -1 in case of failure
*/
int
xenProxyInit(virConnectPtr conn) {
virProxyPacket req;
int ret;
int fd;
if (conn == NULL)
return(-1);
if (conn->proxy <= 0) {
fd = virProxyOpenClientSocket(PROXY_SOCKET_PATH);
if (fd < 0) {
return(-1);
}
conn->proxy = fd;
}
memset(&req, 0, sizeof(req));
req.command = VIR_PROXY_NONE;
req.len = sizeof(req);
ret = xenProxyCommand(conn, &req, NULL);
if ((ret < 0) || (req.command != VIR_PROXY_NONE)) {
xenProxyClose(conn);
return(-1);
}
return(0);
}
/************************************************************************
* *
* Driver entry points *
* *
************************************************************************/
/**
* xenProxyGetVersion:
* @conn: pointer to the Xen Daemon block
* @hvVer: return value for the version of the running hypervisor (OUT)
*
* Get the version level of the Hypervisor running.
*
* Returns -1 in case of error, 0 otherwise. if the version can't be
* extracted by lack of capacities returns 0 and @hvVer is 0, otherwise
* @hvVer value is major * 1,000,000 + minor * 1,000 + release
*/
static int
xenProxyGetVersion(virConnectPtr conn, unsigned long *hvVer)
{
virProxyPacket req;
int ret;
if (!VIR_IS_CONNECT(conn)) {
virProxyError(conn, VIR_ERR_INVALID_CONN, __FUNCTION__);
return (-1);
}
if (hvVer == NULL) {
virProxyError(conn, VIR_ERR_INVALID_ARG, __FUNCTION__);
return (-1);
}
memset(&req, 0, sizeof(req));
req.command = VIR_PROXY_VERSION;
req.len = sizeof(req);
ret = xenProxyCommand(conn, &req, NULL);
if (ret < 0) {
xenProxyClose(conn);
return(-1);
}
*hvVer = req.data.larg;
return(0);
}
/**
* xenProxyNodeGetInfo:
* @conn: pointer to the Xen Daemon block
* @info: pointer to a virNodeInfo structure allocated by the user
*
* Extract hardware information about the node.
*
* Returns 0 in case of success and -1 in case of failure.
*/
static int
xenProxyNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info) {
}
/**
* xenProxyListDomains:
* @conn: pointer to the hypervisor connection
* @ids: array to collect the list of IDs of active domains
* @maxids: size of @ids
*
* Collect the list of active domains, and store their ID in @maxids
* TODO: this is quite expensive at the moment since there isn't one
* xend RPC providing both name and id for all domains.
*
* Returns the number of domain found or -1 in case of error
*/
static int
xenProxyListDomains(virConnectPtr conn, int *ids, int maxids)
{
}
/**
* xenProxyNumOfDomains:
* @conn: pointer to the hypervisor connection
*
* Provides the number of active domains.
*
* Returns the number of domain found or -1 in case of error
*/
static int
xenProxyNumOfDomains(virConnectPtr conn)
{
}
/**
* xenProxyLookupByID:
* @conn: pointer to the hypervisor connection
* @id: the domain ID number
*
* Try to find a domain based on the hypervisor ID number
*
* Returns the domain name (to be freed) or NULL in case of failure
*/
static char *
xenProxyLookupByID(virConnectPtr conn, int id) {
}
/**
* xenProxyLookupByUUID:
* @conn: pointer to the hypervisor connection
* @uuid: the raw UUID for the domain
*
* Try to lookup a domain on xend based on its UUID.
*
* Returns the domain id or -1 in case of error
*/
static int
xenProxyLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
}
/**
* xenProxyDomainLookupByName:
* @conn: A xend instance
* @name: The name of the domain
*
* This method looks up information about a domain based on its name
*
* Returns domain id or -1 in case of error
*/
static int
xenProxyDomainLookupByName(virConnectPtr conn, const char *domname)
{
}
/**
* xenProxyDomainGetMaxMemory:
* @domain: pointer to the domain block
*
* Ask the Xen Daemon for the maximum memory allowed for a domain
*
* Returns the memory size in kilobytes or 0 in case of error.
*/
unsigned long
xenProxyDomainGetMaxMemory(virDomainPtr domain)
{
}
/**
* xenProxyDomainGetInfo:
* @domain: a domain object
* @info: pointer to a virDomainInfo structure allocated by the user
*
* This method looks up information about a domain and update the
* information block provided.
*
* Returns 0 in case of success, -1 in case of error
*/
int
xenProxyDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
{
}
#ifdef STANDALONE
int main(int argc, char **argv) {
int ret;
unsigned long ver;
virConnect conn;
memset(&conn, 0, sizeof(conn));
ret = xenProxyInit(&conn);
if (ret == 0) {
ret = xenProxyGetVersion(&conn, &ver);
if (ret != 0) {
fprintf(stderr, "Failed to get version from proxy\n");
} else {
printf("Proxy running with version %lu\n", ver);
}
xenProxyClose(&conn);
}
exit(0);
}
#endif

View File

@ -101,7 +101,8 @@ struct _virConnect {
/* extra data needed by drivers */
int handle; /* internal handle used for hypercall */
struct xs_handle *xshandle; /* handle to talk to the xenstore */
struct xs_handle *xshandle;/* handle to talk to the xenstore */
int proxy; /* file descriptor if using the proxy */
/* connection to xend */
int type; /* PF_UNIX or PF_INET */

View File

@ -53,6 +53,7 @@ static const char * xenHypervisorGetType(virConnectPtr conn);
static unsigned long xenHypervisorGetMaxMemory(virDomainPtr domain);
static int xenHypervisorInit(void);
#ifndef XEN_RO
static virDriver xenHypervisorDriver = {
VIR_DRV_XEN_HYPERVISOR,
"Xen",
@ -88,6 +89,7 @@ static virDriver xenHypervisorDriver = {
NULL, /* domainSave */
NULL /* domainRestore */
};
#endif /* !XEN_RO */
/**
* virXenError:
@ -175,6 +177,7 @@ done:
}
#ifndef XEN_RO
/**
* xenHypervisorRegister:
*
@ -187,6 +190,7 @@ void xenHypervisorRegister(void)
virRegisterDriver(&xenHypervisorDriver);
}
#endif /* !XEN_RO */
/**
* xenHypervisorOpen:

View File

@ -48,6 +48,7 @@ static virDomainPtr xenDaemonCreateLinux(virConnectPtr conn,
const char *xmlDesc,
unsigned int flags);
#ifndef XEN_RO
static virDriver xenDaemonDriver = {
VIR_DRV_XEN_DAEMON,
"XenDaemon",
@ -93,6 +94,7 @@ void xenDaemonRegister(void)
{
virRegisterDriver(&xenDaemonDriver);
}
#endif /* !XEN_RO */
/**
* xend_connection_type:
@ -1322,6 +1324,7 @@ xend_log(virConnectPtr xend, char *buffer, size_t n_buffer)
******
******
*****************************************************************/
#ifndef XEN_RO
/**
* xend_parse_sexp_desc:
* @root: the root of the parsed S-Expression
@ -1509,6 +1512,7 @@ xend_parse_sexp_desc(struct sexpr *root)
free(ret);
return (NULL);
}
#endif /* !XEN_RO */
/**
* sexpr_to_xend_domain_info:
@ -1591,6 +1595,7 @@ sexpr_to_xend_node_info(struct sexpr *root, virNodeInfoPtr info)
return (0);
}
#ifndef XEN_RO
/**
* sexpr_to_domain:
* @conn: an existing virtual connection block
@ -1636,7 +1641,7 @@ error:
virFreeDomain(conn, ret);
return(NULL);
}
#endif /* !XEN_RO */
/*****************************************************************
******
@ -1649,6 +1654,7 @@ error:
******
******
*****************************************************************/
#ifndef XEN_RO
/**
* xenDaemonOpen:
* @conn: an existing virtual connection block
@ -1699,6 +1705,7 @@ xenDaemonOpen(virConnectPtr conn, const char *name, int flags)
return(ret);
}
#endif /* !XEN_RO */
/**
* xenDaemonClose:
@ -1958,6 +1965,7 @@ xenDaemonDomainSetMemory(virDomainPtr domain, unsigned long memory)
"target", buf, NULL);
}
#ifndef XEN_RO
/**
* xenDaemonDomainDumpXML:
* @domain: a domain object
@ -1988,6 +1996,7 @@ xenDaemonDomainDumpXML(virDomainPtr domain)
return (ret);
}
#endif /* !XEN_RO */
/**
* xenDaemonDomainGetInfo:
@ -2022,6 +2031,7 @@ xenDaemonDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
return (ret);
}
#ifndef XEN_RO
/**
* xenDaemonDomainLookupByName:
* @conn: A xend instance
@ -2053,6 +2063,7 @@ error:
sexpr_free(root);
return(ret);
}
#endif
/**
* xenDaemonNodeGetInfo: