Hey,
On Tue, 2007-01-30 at 17:42 +0000, Richard W.M. Jones wrote:
This patch is just for discussion. It's not in a state to be
applied,
even if it were accepted (which is a long-shot at present anyway).
Cool stuff on getting this far.
Okay, some comments to start with:
- From past dealings with SunRPC and CORBA and the like, the choice
of SunRPC makes me pretty nervous. The amount of code we'd be
adding to libvirt to support SunRPC over the different transports
makes me even more nervous. I wouldn't fancy having to debug
problems there, or add another transport, for example.
I'm pretty jaded of RPC systems in general, though. So, I'd suggest
either a homegrown binary protocol like we're using now or, if it
turns out to be fairly simple, XML RPC.
- Wrt. the TLS support - as recommended by the RFC AFAIR, new
protocols are supposed to negotiate TLS at connection time rather
than having a separate port for TLS (as Dan does with qemud)
- There doesn't seem to be any authentication with TLS support.
That's definitely necessary, even if it's just cert based.
- If libvirtd is going to be a pure proxy, I don't think the UNIX
transport is going useful.
- Also, if it's just a proxy, couldn't this be launched by xinetd?
- I'd advocate merging qemud into libvirtd, but you could have a long
discussion either way on that one.
- The ssh and ext transports just seem like hacks, especially if the
ssh transport won't support authentication (both ways). If people
want to use SSH, they can just set up their own tunnel.
- Wrt. coding style - libvirt has a *fairly* consistent coding style
throughout and I think that helps with the maintainability of any
project. Deviations are already starting to creep in (e.g. not
using studlyCaps in places) ... but we should try and stem that
tide IMHO (even though the current coding style wouldn't be my
favourite)
* SunRPC is stateless so we need to hand out a cookie to
represent the virConnectPtr handle on the server side.
However if the client dies without explicitly calling
close, we have no way to know, and so the cookie/handle
on the server side lives forever.
The server side context should be the file descriptor - i.e. there
should be only a single open() call per fd, and so only a single
virConnectPtr per fd ... so if socket is closed by the remote side, we
know we can call close() on the virConnectPtr. There shouldn't be a need
for cookies, IMHO.
(Perhaps this "single open() call per connection" implies that there
shouldn't be an open() RPC, but rather that happens as part of the
initial negotiation stage)
+ /* driver private data
+ * (Ought to replace the above ad-hoc Xen data, IMHO anyway.
+ * Currently only the 'remote' driver uses this.
+ * - RWMJ).
+ */
+ void *private;
+
Yep, that'd be a nice cleanup - e.g. I have this patch to make qemud
and xen not share the "handle" member:
http://www.gnome.org/~markmc/code/libvirt-networking/libvirt-qemu-dont-sh...
+// See:
http://people.redhat.com/drepper/userapi-ipv6.html
+static int
+make_sockets (int *fds, int max_fds, int *nfds_r, const char *service)
+{
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ memset (&hints, 0, sizeof hints);
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+
+ int e = getaddrinfo (NULL, service, &hints, &ai);
+ if (e != 0) {
+ fprintf (stderr, "getaddrinfo: %s\n", gai_strerror (e));
+ return -1;
+ }
+
+ struct addrinfo *runp = ai;
+ while (runp && *nfds_r < max_fds) {
+ fds[*nfds_r] = socket (runp->ai_family, runp->ai_socktype,
+ runp->ai_protocol);
+ if (fds[*nfds_r] == -1) {
+ perror ("socket");
+ return -1;
+ }
+
+ int opt = 1;
+ setsockopt (fds[*nfds_r], SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
+
+ if (bind (fds[*nfds_r], runp->ai_addr, runp->ai_addrlen) == -1) {
+ if (errno != EADDRINUSE) {
+ perror ("bind");
+ return -1;
+ }
+ close (fds[*nfds_r]);
+ }
+ else {
+ if (listen (fds[*nfds_r], SOMAXCONN) == -1) {
+ perror ("listen");
+ return -1;
+ }
+ ++*nfds_r;
+ }
+ runp = runp->ai_next;
+ }
+
+ freeaddrinfo (ai);
I'm really not a big fan of this way of doing IPv6 support because:
- getaddrinfo() is a pretty complicated function, so the code above
is pretty obtuse without a thorough read of the getaddrinfo() man
page
- you really want to end up with *either* a single IPv6 socket or and
IPv4 socket ... the above code can end up with multiple sockets.
Here's what I prefer to do:
---
struct sockaddr_in addr_in;
struct sockaddr *addr;
socklen_t addrlen;
#ifdef ENABLE_IPV6
struct sockaddr_in6 addr_in6;
memset(&addr_in6, 0, sizeof(addr_in6));
addr_in6.sin6_family = AF_INET6;
addr_in6.sin6_port = htons(port);
addr_in6.sin6_addr = localOnly ? in6addr_loopback : in6addr_any;
addr = (struct sockaddr *)&addr_in6;
addrlen = sizeof(addr_in6);
sock = socket(AF_INET6, SOCK_STREAM, 0);
#endif
if (sock < 0) {
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
memset(&addr_in, 0, sizeof(addr_in));
addr_in.sin_family = AF_INET;
addr_in.sin_port = htons(port);
addr_in.sin_addr.s_addr = localOnly ? htonl(INADDR_LOOPBACK) : htonl(INADDR_ANY);
addr = (struct sockaddr *)&addr_in;
addrlen = sizeof(addr_in);
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one)) < 0) {
close(sock);
return -1;
}
if (bind(sock, addr, addrlen) < 0) {
close(sock);
return -1;
}
----
+static int
+remote_open (virConnectPtr conn, const char *name,
+ int flags __attribute__((unused)))
This function is huge, and extremely hard to verify. Recommend
splitting it up a lot. Perhaps when you use libxml's URI parsing etc. it
won't be so bad, though.
Also, libvirt has ATTRIBUTE_UNUSED.
+ switch (proto) {
+ case proto_unknown:
+ abort (); /* Internal error in this function. */
+
+ case proto_tls:
+ case proto_tcp: {
....
+ proto == proto_tls
+ ? clntgnutls_create (r->ai_family, r->ai_addr, r->ai_addrlen, xcred,
+ LIBVIRTREMOTE, LIBVIRTREMOTE_VERS1,
+ &private.sock, 0, 0)
+ : clnttcp2_create (r->ai_family, r->ai_addr, r->ai_addrlen,
+ LIBVIRTREMOTE, LIBVIRTREMOTE_VERS1,
+ &private.sock, 0, 0);
+ if (private.cl)
+ goto tcp_connected;
+ }
+
+ freeaddrinfo (res);
+ error (conn, VIR_ERR_RPC,
+ clnt_spcreateerror ("could not create SunRPC client"));
+ goto failed;
+
+ tcp_connected:
+ freeaddrinfo (res);
A goto in a switch() statement? ... that's a whole litter of cute
little puppies you've killed, right there! :-)
HTH,
Mark.