📄 xen_common.c
字号:
/* * Copyright (c) 2006-2007 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 _XOPEN_SOURCE#include <assert.h>#include <stdarg.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <libxml/parser.h>#include <libxml/tree.h>#include <libxml/xmlsave.h>#include <libxml/xmlstring.h>#include <libxml/xpath.h>#include "xen/api/xen_common.h"#include "xen/api/xen_host.h"#include "xen_internal.h"#include "xen/api/xen_int_float_map.h"#include "xen/api/xen_int_int_map.h"#include "xen/api/xen_int_string_set_map.h"#include "xen/api/xen_string_string_map.h"/* * Whether to ignore missing structure entries. This is not something we * want to do, once the API has stabilised, as it indicates that the server is * broken, but at the moment, complaining is just slowing development down. */#define PERMISSIVE 1static xmlXPathCompExprPtr responsePath = NULL;static xmlXPathCompExprPtr faultPath = NULL;typedef struct{ size_t size; void *contents[];} arbitrary_map;typedef struct{ void *handle;} arbitrary_record;typedef struct{ bool is_record; union { char *handle; arbitrary_record *record; } u;} arbitrary_record_opt;static char *make_body(const char *, abstract_value [], int);static voidparse_result(xen_session *, const char *, const abstract_type *, void *);static voidadd_value(xmlNode *, const char *, const char *);static voidadd_param(xmlNode *, const char *, const char *);static xmlNode *add_param_struct(xmlNode *);static xmlNode *add_struct_array(xmlNode *, const char *);static xmlNode *add_nested_struct(xmlNode *, const char *);static voidadd_struct_member(xmlNode *, const char *, const char *, const char *);static voidadd_unnamed_value(xmlNode *, const char *, const char *, const char *);static voidadd_struct_value(const struct abstract_type *, void *, void (*)(xmlNode *, const char *, const char *, const char *), const char *, xmlNode *);static xmlNode *add_container(xmlNode *parent, const char *name);static voidcall_raw(xen_session *, const char *, abstract_value [], int, const abstract_type *, void *);static voidparse_structmap_value(xen_session *, xmlNode *, const abstract_type *, void *);static size_t size_of_member(const abstract_type *);static const char *get_val_as_string(const struct abstract_type *, void *, char *, size_t);voidxen_init(void){ responsePath = xmlXPathCompile( BAD_CAST( "/methodResponse/params/param/value/struct/member/value")); faultPath = xmlXPathCompile( BAD_CAST("/methodResponse/fault/value/struct/member/value"));}voidxen_fini(void){ xmlXPathFreeCompExpr(responsePath); xmlXPathFreeCompExpr(faultPath); responsePath = NULL; faultPath = NULL;}voidxen_session_record_free(xen_session_record *record){ if (record == NULL) { return; } free(record->uuid); xen_host_record_opt_free(record->this_host); free(record->this_user); free(record);}xen_session *xen_session_login_with_password(xen_call_func call_func, void *handle, const char *uname, const char *pwd){ abstract_value params[] = { { .type = &abstract_type_string, .u.string_val = uname }, { .type = &abstract_type_string, .u.string_val = pwd } }; xen_session *session = malloc(sizeof(xen_session)); session->call_func = call_func; session->handle = handle; session->session_id = NULL; session->ok = true; session->error_description = NULL; session->error_description_count = 0; call_raw(session, "session.login_with_password", params, 2, &abstract_type_string, &session->session_id); return session;}voidxen_session_logout(xen_session *session){ abstract_value params[] = { }; xen_call_(session, "session.logout", params, 0, NULL, NULL); if (session->error_description != NULL) { for (int i = 0; i < session->error_description_count; i++) { free(session->error_description[i]); } free(session->error_description); } free((char *)session->session_id); free(session);}voidxen_session_clear_error(xen_session *session){ if (session->error_description != NULL) { for (int i = 0; i < session->error_description_count; i++) { free(session->error_description[i]); } free(session->error_description); } session->error_description = NULL; session->error_description_count = 0; session->ok = true;}boolxen_session_get_uuid(xen_session *session, char **result, xen_session *self_session){ abstract_value params[] = { { .type = &abstract_type_string, .u.string_val = self_session->session_id } }; xen_call_(session, "session.get_uuid", params, 1, &abstract_type_string, result); return session->ok;}boolxen_session_get_this_host(xen_session *session, xen_host *result, xen_session *self_session){ abstract_value params[] = { { .type = &abstract_type_string, .u.string_val = self_session->session_id } }; xen_call_(session, "session.get_this_host", params, 1, &abstract_type_string, result); return session->ok;}boolxen_session_get_this_user(xen_session *session, char **result, xen_session *self_session){ abstract_value params[] = { { .type = &abstract_type_string, .u.string_val = self_session->session_id } }; xen_call_(session, "session.get_this_user", params, 1, &abstract_type_string, result); return session->ok;}boolxen_session_get_last_active(xen_session *session, time_t *result, xen_session *self_session){ abstract_value params[] = { { .type = &abstract_type_string, .u.string_val = self_session->session_id } }; xen_call_(session, "session.get_last_active", params, 1, &abstract_type_datetime, result); return session->ok;}static const struct_member xen_session_record_struct_members[] = { { .key = "uuid", .type = &abstract_type_string, .offset = offsetof(xen_session_record, uuid) }, { .key = "this_host", .type = &abstract_type_ref, .offset = offsetof(xen_session_record, this_host) }, { .key = "this_user", .type = &abstract_type_string, .offset = offsetof(xen_session_record, this_user) }, { .key = "last_active", .type = &abstract_type_datetime, .offset = offsetof(xen_session_record, last_active) }, };const abstract_type xen_session_record_abstract_type_ = { .typename = STRUCT, .struct_size = sizeof(xen_session_record), .member_count = sizeof(xen_session_record_struct_members) / sizeof(struct_member), .members = xen_session_record_struct_members };boolxen_session_get_record(xen_session *session, xen_session_record **result, xen_session *self_session){ abstract_value param_values[] = { { .type = &abstract_type_string, .u.string_val = self_session->session_id } }; abstract_type result_type = xen_session_record_abstract_type_; *result = NULL; XEN_CALL_("session.get_record"); return session->ok;}#define X "%02x"#define UUID_FORMAT X X X X "-" X X "-" X X "-" X X "-" X X X X X Xboolxen_uuid_string_to_bytes(char *uuid, char **bytes){ unsigned int buf[16]; *bytes = NULL; if (strlen(uuid) != 36) return false; if (16 != sscanf(uuid, UUID_FORMAT, buf + 0, buf + 1, buf + 2, buf + 3, buf + 4, buf + 5, buf + 6, buf + 7, buf + 8, buf + 9, buf + 10, buf + 11, buf + 12, buf + 13, buf + 14, buf + 15)) { return false; } *bytes = malloc(16); if (*bytes == NULL) return false; for (int i = 0; i < 16; i++) { (*bytes)[i] = (char)buf[i]; } return true;}boolxen_uuid_bytes_to_string(char *bytes, char **uuid){ *uuid = malloc(37); if (*uuid == NULL) return false; sprintf(*uuid, UUID_FORMAT, bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]); return true;}#undef UUID_FORMAT#undef Xvoidxen_uuid_free(char *uuid){ free(uuid);}voidxen_uuid_bytes_free(char *bytes){ free(bytes);}/** * @param value A pointer to the correct location as per the given * result_type. Will be populated if the call succeeds. In that case, and if * value is a char **, the char * itself must be freed by the caller. */voidxen_call_(xen_session *s, const char *method_name, abstract_value params[], int param_count, const abstract_type *result_type, void *value){ abstract_value *full_params; if (!s->ok) { return; } full_params = malloc(sizeof(abstract_value) * (param_count + 1)); full_params[0].type = &abstract_type_string; full_params[0].u.string_val = s->session_id; memcpy(full_params + 1, params, param_count * sizeof(abstract_value)); call_raw(s, method_name, full_params, param_count + 1, result_type, value); free(full_params);}static boolbufferAdd(const void *data, size_t len, void *buffer){ return 0 == xmlBufferAdd((xmlBufferPtr)buffer, data, len);}static voidcall_raw(xen_session *s, const char *method_name, abstract_value params[], int param_count, const abstract_type *result_type, void *value){ xmlBufferPtr buffer = xmlBufferCreate(); char *body = make_body(method_name, params, param_count); int error_code = s->call_func(body, strlen(body), s->handle, buffer, &bufferAdd); free(body); if (error_code) { char **strings = malloc(2 * sizeof(char *)); strings[0] = xen_strdup_("TRANSPORT_FAULT"); strings[1] = malloc(20); snprintf(strings[1], 20, "%d", error_code); s->ok = false; s->error_description = strings; s->error_description_count = 2; } else { parse_result(s, (char *)xmlBufferContent(buffer), result_type, value); } xmlBufferFree(buffer);}static void server_error(xen_session *session, const char *error_string){ char **strings; if (!session->ok) { /* Don't wipe out the earlier error message with this one. */ return; } strings = malloc(2 * sizeof(char *)); strings[0] = xen_strdup_("SERVER_FAULT"); strings[1] = xen_strdup_(error_string); session->ok = false; session->error_description = strings; session->error_description_count = 2;}static void server_error_2(xen_session *session, const char *error_string, const char *param){ char **strings; if (!session->ok) { /* Don't wipe out the earlier error message with this one. */ return; } strings = malloc(3 * sizeof(char *)); strings[0] = xen_strdup_("SERVER_FAULT_2"); strings[1] = xen_strdup_(error_string); strings[2] = xen_strdup_(param); session->ok = false; session->error_description = strings; session->error_description_count = 3;}static bool is_node(xmlNode *n, char *type){ return n->type == XML_ELEMENT_NODE && 0 == strcmp((char *)n->name, type);}static bool is_container_node(xmlNode *n, char *type){ return is_node(n, type) && n->children != NULL && n->children == n->last && n->children->type == XML_ELEMENT_NODE;}/** * @return The contents of the given value, or NULL if this is not a node with * the given type. If not NULL, the result must be freed with xmlFree(). */static xmlChar *string_from_value(xmlNode *n, char *type){ /* <value><type>XYZ</type></value> is normal, but the XML-RPC spec also allows <value>XYZ</value> where XYZ is to be interpreted as a string. */ if (is_container_node(n, "value") && 0 == strcmp((char *)n->children->name, type)) { return n->children->children == NULL ? xmlStrdup(BAD_CAST("")) : xmlNodeGetContent(n->children->children); } else if (0 == strcmp(type, "string") && is_node(n, "value")) { return n->children == NULL ? xmlStrdup(BAD_CAST("")) : xmlNodeGetContent(n->children); } else { return NULL; }}/** * Find the name node that is a child of the given one, and return its * contents, or NULL if this has no such node. If not NULL, the result must * be freed with xmlFree(). */static xmlChar *string_from_name(xmlNode *n){ xmlNode *cur = n->children; while (cur != NULL) { if (0 == strcmp((char *)cur->name, "name")) { return xmlNodeGetContent(cur); } cur = cur->next; } return NULL;}static int count_children(xmlNode *n, const char *name)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -