/* * Copyright (c) 2006 XenSource, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tcp.h" static int xmlrpc_request(const void *data, size_t len, void *user_handle, void *result_handle, xen_result_func result_func) { static char *xend_host = "localhost"; static char *xend_serv = "8005"; static struct sockaddr_un xend_unix = { .sun_family = PF_UNIX, .sun_path = "/var/run/xend/xmlrpc.sock", }; static char *xend_path = "/RPC2"; struct addrinfo ask; char head[256]; char reply[256]; char *body; int sock, lhead, lreply, lbody, rc, eof, header_seen; struct timeval tv; fd_set rd; tcp_verbose = 0; /* try tcp first */ memset(&ask,0,sizeof(ask)); ask.ai_socktype = SOCK_STREAM; ask.ai_family = PF_UNSPEC; sock = tcp_connect(&ask, NULL, NULL, xend_host, xend_serv); if (sock >= 0) goto connected; /* failing that unix sockets */ sock = socket(PF_UNIX, SOCK_STREAM, 0); if (0 == connect(sock, (struct sockaddr*)&xend_unix, sizeof(xend_unix))) goto connected; /* Hmm, didn't work */ return -1; connected: /* http header */ lhead = snprintf(head, sizeof(head), "POST %s HTTP/1.0\r\n" "Host: %s\r\n" "User-Agent: xenwatch\r\n" "Content-Type: text/xml\r\n" "Content-Length: %d\r\n" "\r\n", xend_path, xend_host, len); if (tcp_verbose) { write(2, head, lhead); write(2, data, len); } write(sock, head, lhead); rc = write(sock, data, len); if (rc != len) { fprintf(stderr,"Oops [FIXME]: unhandled partial write (%d/%d)\n", rc, len); return -1; } header_seen = 0; lreply = 0; eof = 0; while (!eof) { FD_ZERO(&rd); FD_SET(sock, &rd); tv.tv_sec = 3; tv.tv_usec = 0; if (1 == select(sock+1, &rd, NULL, NULL, &tv)) { rc = read(sock, reply + lreply, sizeof(reply) - lreply -1); switch (rc) { case -1: perror("read"); /* fall through */ case 0: eof = 1; break; default: lreply += rc; reply[lreply] = 0; if (header_seen) { result_func(reply, lreply, result_handle); lreply = 0; } else { body = strstr(reply, "\r\n\r\n"); if (!body) break; body += 4; lbody = lreply - (body - reply); header_seen = 1; lreply = 0; if (lbody) result_func(body, lbody, result_handle); } } } } close(sock); return 0; } static void print_error(xen_session *session) { int i; fprintf(stderr, "Error: %d", session->error_description_count); for (i = 0; i < session->error_description_count; i++) fprintf(stderr, " %s", session->error_description[i]); fprintf(stderr, "\n"); } int main(int argc, char **argv) { xen_session *session = NULL; xen_string_string_map *versions = NULL; xen_host host; int i, rc = 1; xmlInitParser(); xen_init(); session = xen_session_login_with_password(xmlrpc_request, NULL, NULL, NULL); if (!xen_session_get_this_host(session, &host)) goto out; if (!xen_host_get_software_version(session, &versions, host)) goto out; for (i = 0; i < versions->size; i++) { printf("%s: %s\n", versions->contents[i].key, versions->contents[i].val); } rc = 0; out: if (session && !session->ok) print_error(session); if (versions) xen_string_string_map_free(versions); if (session) xen_session_logout(session); xen_fini(); xmlCleanupParser(); return rc; }