summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Jones <rjones@redhat.com>2009-04-02 20:46:55 +0100
committerRichard Jones <rjones@redhat.com>2009-04-02 20:46:55 +0100
commit163e399a001a300a53a4c99887742608d23e09ad (patch)
treecad1aa7b6563f642edc0d46193867dde0975696e
parent88f69eb03160a62d38a361a5ad68c6ba1e767a20 (diff)
downloadlibguestfs-163e399a001a300a53a4c99887742608d23e09ad.tar.gz
libguestfs-163e399a001a300a53a4c99887742608d23e09ad.tar.xz
libguestfs-163e399a001a300a53a4c99887742608d23e09ad.zip
Code to handle the daemon communications socket.
-rw-r--r--guestfs.pod9
-rw-r--r--src/guestfs.c116
-rw-r--r--src/guestfs.h6
3 files changed, 123 insertions, 8 deletions
diff --git a/guestfs.pod b/guestfs.pod
index 9202fb84..b0fa5f29 100644
--- a/guestfs.pod
+++ b/guestfs.pod
@@ -417,9 +417,9 @@ For example:
/* returns immediately */
}
- my_cb (guestfs_h *handle, void *data)
+ my_cb (guestfs_h *handle, void *data, XDR *xdr)
{
- retval = guestfs_nb_[action]_r (handle);
+ retval = guestfs_nb_[action]_r (handle, xdr);
/* ... */
}
@@ -429,6 +429,7 @@ high-level API.
=head2 guestfs_set_reply_callback
+ typedef void (*guestfs_reply_cb) (guestfs_h *g, void *opaque, XDR *xdr);
void guestfs_set_reply_callback (guestfs_h *handle,
guestfs_reply_cb cb,
void *opaque);
@@ -439,6 +440,8 @@ from the BUSY state to the READY state).
=head2 guestfs_set_log_message_callback
+ typedef void (*guestfs_log_message_cb) (guestfs_h *g, void *opaque,
+ char *buf, int len);
void guestfs_set_log_message_callback (guestfs_h *handle,
guestfs_log_message_cb cb,
void *opaque);
@@ -453,6 +456,7 @@ discarded.
=head2 guestfs_set_subprocess_quit_callback
+ typedef void (*guestfs_subprocess_quit_cb) (guestfs_h *g, void *opaque);
void guestfs_set_subprocess_quit_callback (guestfs_h *handle,
guestfs_subprocess_quit_cb cb,
void *opaque);
@@ -464,6 +468,7 @@ any state to the CONFIG state).
=head2 guestfs_set_launch_done_callback
+ typedef void (*guestfs_launch_done_cb) (guestfs_h *g, void *opaque);
void guestfs_set_launch_done_callback (guestfs_h *handle,
guestfs_ready_cb cb,
void *opaque);
diff --git a/src/guestfs.c b/src/guestfs.c
index a827157b..7e883035 100644
--- a/src/guestfs.c
+++ b/src/guestfs.c
@@ -29,6 +29,9 @@
#include <string.h>
#include <fcntl.h>
#include <time.h>
+#include <sys/select.h>
+#include <rpc/types.h>
+#include <rpc/xdr.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
@@ -50,8 +53,6 @@
#include <sys/un.h>
#endif
-#include <sys/select.h>
-
#include "guestfs.h"
static void error (guestfs_h *g, const char *fs, ...);
@@ -131,6 +132,12 @@ struct guestfs_h
void * reply_cb_internal_data;
guestfs_launch_done_cb launch_done_cb_internal;
void * launch_done_cb_internal_data;
+
+ /* Messages sent and received from the daemon. */
+ char *msg_in;
+ int msg_in_size, msg_in_allocated;
+ char *msg_out;
+ int msg_out_size;
};
guestfs_h *
@@ -206,7 +213,7 @@ guestfs_close (guestfs_h *g)
static void
default_error_cb (guestfs_h *g, void *data, const char *msg)
{
- fprintf (stderr, "libguestfs: %s\n", msg);
+ fprintf (stderr, "libguestfs: error: %s\n", msg);
}
static void
@@ -445,6 +452,7 @@ guestfs_launch (guestfs_h *g)
}
snprintf (unixsock, sizeof unixsock, "%s/sock", g->tmpdir);
+ unlink (unixsock);
if (pipe (wfd) == -1 || pipe (rfd) == -1) {
perrorf (g, "pipe");
@@ -587,6 +595,14 @@ guestfs_launch (guestfs_h *g)
connected:
/* Watch the file descriptors. */
+ free (g->msg_in);
+ g->msg_in = NULL;
+ g->msg_in_size = g->msg_in_allocated = 0;
+
+ free (g->msg_out);
+ g->msg_out = NULL;
+ g->msg_out_size = 0;
+
g->stdout_watch =
main_loop.add_handle (g, g->fd[1],
GUESTFS_HANDLE_READABLE,
@@ -769,14 +785,106 @@ stdout_event (void *data, int watch, int fd, int events)
static void
sock_read_event (void *data, int watch, int fd, int events)
{
- /*guestfs_h *g = (guestfs_h *) data;*/
+ guestfs_h *g = (guestfs_h *) data;
+ XDR xdr;
+ unsigned len;
+ int n;
+
+ if (g->verbose)
+ fprintf (stderr,
+ "sock_event: %p g->state = %d, fd = %d, events = 0x%x\n",
+ g, g->state, fd, events);
+
+ if (g->sock != fd) {
+ error (g, "sock_read_event: internal error: %d != %d", g->sock, fd);
+ return;
+ }
+
+ if (g->msg_in_size <= g->msg_in_allocated) {
+ g->msg_in_allocated += 4096;
+ g->msg_in = safe_realloc (g, g->msg_in, g->msg_in_allocated);
+ }
+ n = read (g->sock, g->msg_in + g->msg_in_size,
+ g->msg_in_allocated - g->msg_in_size);
+ if (n == 0)
+ /* Disconnected? Ignore it because stdout_watch will get called
+ * and will do the cleanup.
+ */
+ return;
+ if (n == -1) {
+ if (errno != EAGAIN)
+ perrorf (g, "read");
+ return;
+ }
+ g->msg_in_size += n;
+ /* Have we got enough of a message to be able to process it yet? */
+ if (g->msg_in_size < 4) return;
+ xdrmem_create (&xdr, g->msg_in, g->msg_in_size, XDR_DECODE);
+ if (!xdr_uint32_t (&xdr, &len)) {
+ error (g, "can't decode length word");
+ goto cleanup;
+ }
+ /* Length is normally the length of the message, but when guestfsd
+ * starts up it sends a "magic" value (longer than any possible
+ * message). Check for this.
+ */
+ if (len == 0xf5f5f5f5) {
+ if (g->state != LAUNCHING)
+ error (g, "received magic signature from guestfsd, but in state %d",
+ g->state);
+ else if (g->msg_in_size != 4)
+ error (g, "received magic signature from guestfsd, but msg size is %d",
+ g->msg_in_size);
+ else {
+ g->state = READY;
+ if (g->launch_done_cb_internal)
+ g->launch_done_cb_internal (g, g->launch_done_cb_internal_data);
+ if (g->launch_done_cb)
+ g->launch_done_cb (g, g->launch_done_cb_data);
+ }
+
+ goto cleanup;
+ }
+
+ if (g->msg_in_size < len) return; /* Need more of this message. */
+ /* This should not happen, and if it does it probably means we've
+ * lost all hope of synchronization.
+ */
+ if (g->msg_in_size > len) {
+ error (g, "len = %d, but msg_in_size = %d", len, g->msg_in_size);
+ goto cleanup;
+ }
+ /* Not in the expected state. */
+ if (g->state != BUSY)
+ error (g, "state %d != BUSY", g->state);
+
+ /* Push the message up to the higher layer. Note that unlike
+ * launch_done_cb / launch_done_cb_internal, we only call at
+ * most one of the callback functions here.
+ */
+ g->state = READY;
+ if (g->reply_cb_internal)
+ g->reply_cb_internal (g, g->reply_cb_internal_data, &xdr);
+ else if (g->reply_cb)
+ g->reply_cb (g, g->reply_cb, &xdr);
+
+ cleanup:
+ /* Free the message buffer if it's grown excessively large. */
+ if (g->msg_in_allocated > 65536) {
+ free (g->msg_in);
+ g->msg_in = NULL;
+ g->msg_in_size = g->msg_in_allocated = 0;
+ } else
+ g->msg_in_size = 0;
+
+ xdr_destroy (&xdr);
}
/* This is the default main loop implementation, using select(2). */
diff --git a/src/guestfs.h b/src/guestfs.h
index ead53072..4e032c66 100644
--- a/src/guestfs.h
+++ b/src/guestfs.h
@@ -24,6 +24,8 @@
* Go and read it now, I'll wait.
*/
+#include <rpc/xdr.h>
+
typedef struct guestfs_h guestfs_h;
/* Connection management. */
@@ -56,10 +58,10 @@ extern int guestfs_get_verbose (guestfs_h *g);
extern int guestfs_sync (guestfs_h *g);
/* Low-level event API. */
-typedef void (*guestfs_reply_cb) (guestfs_h *g, void *data /* , ... */);
+typedef void (*guestfs_reply_cb) (guestfs_h *g, void *data, XDR *xdr);
typedef void (*guestfs_log_message_cb) (guestfs_h *g, void *data, char *buf, int len);
typedef void (*guestfs_subprocess_quit_cb) (guestfs_h *g, void *data);
-typedef void (*guestfs_launch_done_cb) (guestfs_h *g, void *data /* , ... */);
+typedef void (*guestfs_launch_done_cb) (guestfs_h *g, void *data);
extern void guestfs_set_reply_callback (guestfs_h *g, guestfs_reply_cb cb, void *opaque);
extern void guestfs_set_log_message_callback (guestfs_h *g, guestfs_log_message_cb cb, void *opaque);