OpenSolaris_b135/lib/fm/libldom/sparc/ldom_xmpp_client.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/*
 * ldom_xmpp_client.c	Extensible Messaging and Presence Protocol (XMPP)
 *
 * Implement an xmpp client to subscribe for domain events from the ldmd.
 * Notify fmd module clients upon receiving the events.
 *
 */

#include "ldom_xmpp_client.h"
#include "ldom_alloc.h"
#include "ldom_utils.h"

#include <stdio.h>
#include <signal.h>
#include <strings.h>
#include <unistd.h>
#include <errno.h>

#include <netdb.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <libxml/parser.h>
#include <openssl/ssl.h>

typedef enum conn_state {
	CONN_STATE_UNKNOWN,
	CONN_STATE_TLS,
	CONN_STATE_FEATURE,
	CONN_STATE_LDM_INTERFACE,
	CONN_STATE_LDM_EVENT,
	CONN_STATE_DONE,
	CONN_STATE_FAILURE,
	CONN_STATE_MAX
} conn_state_t;

typedef struct xmpp_conn {
	int			fd;
	int			state;
	boolean_t		tls_started;
	SSL			*ssl;
	xmlParserCtxtPtr	parser;
} xmpp_conn_t;

/* Forward declaration */
static int iowrite(xmpp_conn_t *conn, char *buf, int size);
static void start_element(void *state, const xmlChar *name,
	const xmlChar **attrs);
static void end_element(void *state, const xmlChar *name);
static void error_func(void *state, const char *msg, ...);
static void xmpp_close(xmpp_conn_t *conn);
static int start_tls(xmpp_conn_t *conn);
static void handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size);
static void handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size);

static int xmpp_enable = 0;
static int xmpp_thr_sig = SIGTERM;
static pthread_t xmpp_tid = 0;
static pthread_mutex_t xmpp_tid_lock = PTHREAD_MUTEX_INITIALIZER;

static client_list_t clt_list = { NULL, NULL, PTHREAD_MUTEX_INITIALIZER };


#define	FUNCTION_ADD(_function, _pointer, _lib, _func_name, _ret)	\
	_function = (_pointer)dlsym(_lib, _func_name);			\
	if (_function == NULL) {					\
		_ret += -1;						\
	}

/*
 * Prototypes and pointers to functions needed from libssl.
 */
typedef void (*SSL_load_error_strings_pt)(void);
typedef int (*SSL_library_init_pt)(void);
typedef SSL_CTX *(*SSL_CTX_new_pt)(const SSL_METHOD *method);
typedef SSL_METHOD *(*SSLv23_client_method_pt)(void);
typedef int (*SSL_write_pt)(SSL *ssl, const void *buf, int num);
typedef int (*SSL_CTX_use_PrivateKey_file_pt)(SSL_CTX *ctx, const char *file,
    int type);
typedef void (*RAND_seed_pt)(const void *buf, int num);
typedef int (*SSL_get_error_pt)(const SSL *ssl, int ret);
typedef long (*ERR_get_error_pt)(void);
typedef char *(*ERR_error_string_pt)(unsigned long e, char *buf);
typedef int (*SSL_connect_pt)(SSL *ssl);
typedef int (*SSL_CTX_use_certificate_chain_file_pt)(SSL_CTX *ctx,
    const char *file);
typedef int (*SSL_set_fd_pt)(SSL *ssl, int fd);
typedef void (*SSL_free_pt)(SSL *ssl);
typedef int (*SSL_read_pt)(SSL *ssl, void *buf, int num);
typedef SSL *(*SSL_new_pt)(SSL_CTX *ctx);
typedef SSL_CTX *(*SSL_get_SSL_CTX_pt)(const SSL *ssl);
typedef void (*SSL_CTX_free_pt)(SSL_CTX *ctx);

static SSL_load_error_strings_pt SSL_load_error_strings_f = NULL;
static SSL_library_init_pt SSL_library_init_f = NULL;
static SSL_CTX_new_pt SSL_CTX_new_f = NULL;
static SSLv23_client_method_pt SSLv23_client_method_f = NULL;
static SSL_write_pt SSL_write_f = NULL;
static SSL_CTX_use_PrivateKey_file_pt SSL_CTX_use_PrivateKey_file_f = NULL;
static RAND_seed_pt RAND_seed_f = NULL;
static SSL_get_error_pt SSL_get_error_f = NULL;
static ERR_get_error_pt ERR_get_error_f = NULL;
static ERR_error_string_pt ERR_error_string_f = NULL;
static SSL_connect_pt SSL_connect_f = NULL;
static SSL_CTX_use_certificate_chain_file_pt
SSL_CTX_use_certificate_chain_file_f = NULL;
static SSL_set_fd_pt SSL_set_fd_f = NULL;
static SSL_free_pt SSL_free_f = NULL;
static SSL_read_pt SSL_read_f = NULL;
static SSL_new_pt SSL_new_f = NULL;
static SSL_get_SSL_CTX_pt SSL_get_SSL_CTX_f = NULL;
static SSL_CTX_free_pt SSL_CTX_free_f = NULL;

static void *xmpp_dl = NULL;

static ldom_event_info_t event_table[] = {
	{ LDOM_EVENT_UNKNOWN, "unknown" },
	{ LDOM_EVENT_ADD, "add-domain" },
	{ LDOM_EVENT_REMOVE, "remove-domain" },
	{ LDOM_EVENT_BIND, "bind-domain" },
	{ LDOM_EVENT_UNBIND, "unbind-domain" },
	{ LDOM_EVENT_START, "start-domain" },
	{ LDOM_EVENT_STOP, "stop-domain" },
	{ LDOM_EVENT_RESET, "domain-reset" },
	{ LDOM_EVENT_PANIC, "panic-domain" },
	{ LDOM_EVENT_MAX, NULL }
};
static int event_table_size = \
		sizeof (event_table) / sizeof (ldom_event_info_t);

static xmlSAXHandler xml_handler = {
	NULL,		/* internalSubsetSAXFunc */
	NULL,		/* isStandaloneSAXFunc */
	NULL,		/* hasInternalSubsetSAXFunc */
	NULL,		/* hasExternalSubsetSAXFunc */
	NULL,		/* resolveEntitySAXFunc */
	NULL,		/* getEntitySAXFunc */
	NULL,		/* entityDeclSAXFunc */
	NULL,		/* notationDeclSAXFunc */
	NULL,		/* attributeDeclSAXFunc */
	NULL,		/* elementDeclSAXFunc */
	NULL,		/* unparsedEntityDeclSAXFunc */
	NULL,		/* setDocumentLocatorSAXFunc */
	NULL,		/* startDocumentSAXFunc */
	NULL,		/* endDocumentSAXFunc */
	start_element,	/* startElementSAXFunc */
	end_element,	/* endElementSAXFunc */
	NULL,		/* referenceSAXFunc */
	NULL,		/* charactersSAXFunc */
	NULL,		/* ignorableWhitespaceSAXFunc */
	NULL,		/* processingInstructionSAXFunc */
	NULL,		/* commentSAXFunc */
	NULL,		/* warningSAXFunc */
	error_func,	/* errorSAXFunc */
	NULL,		/* fatalErrorSAXFunc */
	NULL,		/* getParameterEntitySAXFunc */
	NULL,		/* cdataBlockSAXFunc */
	NULL,		/* externalSubsetSAXFunc */
	0,		/* unsigned int */
	NULL,		/* void * _private */
	NULL,		/* startElementNsSAX2Func */
	NULL,		/* endElementNsSAX2Func */
	NULL		/* xmlStructuredErrorFunc */
};

static void
end_element(void *state, const xmlChar *name)
{
	xmpp_conn_t	*conn = (xmpp_conn_t *)state;

	if (xmlStrcmp(name, STREAM_NODE) == 0) {
		conn->state = CONN_STATE_DONE;
	} else if (xmlStrcmp(name, STARTTLS_NODE) == 0) {
		(void) iowrite(conn, START_TLS, strlen(START_TLS));
	} else if (xmlStrcmp(name, PROCEED_NODE) == 0) {
		if (start_tls(conn)) {
			conn->state = CONN_STATE_FAILURE;
		}
	} else if (xmlStrcmp(name, FEATURE_NODE) == 0) {
		if (conn->state == CONN_STATE_TLS) {
			conn->state = CONN_STATE_FEATURE;
			(void) iowrite(conn, (char *)LDM_REG_DOMAIN_EVENTS,
			    strlen((char *)LDM_REG_DOMAIN_EVENTS));
		}
	} else if (xmlStrcmp(name, XML_LDM_INTERFACE) == 0) {
		conn->state = CONN_STATE_LDM_INTERFACE;
	} else if (xmlStrcmp(name, XML_LDM_EVENT) == 0) {
		conn->state = CONN_STATE_LDM_EVENT;
	} else if (xmlStrcmp(name, XML_FAILURE) == 0) {
		conn->state = CONN_STATE_FAILURE;
	}
}

/*ARGSUSED*/
static void
start_element(void *state, const xmlChar *name, const xmlChar **attrs)
{
}

/*ARGSUSED*/
static void
error_func(void *state, const char *msg, ...)
{
}

static int
xmpp_connect(xmpp_conn_t *conn)
{
	int sock;
	struct sockaddr_in serveraddr;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
		return (-1);
	}

	serveraddr.sin_family = AF_INET;
	serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
	serveraddr.sin_port = htons(XMPP_DEFAULT_PORT);
	if (connect(sock, (struct sockaddr *)(&serveraddr),
	    sizeof (struct sockaddr_in)) < 0) {
		return (-1);
	}

	(void) bzero(conn, sizeof (xmpp_conn_t));
	conn->fd = sock;
	conn->tls_started = B_FALSE;

	conn->parser = xmlCreatePushParserCtxt(&xml_handler, (void *) conn,
	    NULL, NULL, NULL);
	if (conn->parser == NULL) {
		return (-1);
	}

	return (0);
}

static void
xmpp_close(xmpp_conn_t *conn)
{
	(void) close(conn->fd);
	conn->fd = -1;
	conn->state = CONN_STATE_UNKNOWN;
	if (conn->parser != NULL) {
		xmlFreeParserCtxt(conn->parser);
		conn->parser = NULL;
	}
	if (conn->tls_started) {
		SSL_free_f(conn->ssl);
		conn->ssl = NULL;
	}
	conn->tls_started = B_FALSE;
}

static int
ioread(xmpp_conn_t *conn, char *buf, int size)
{
	int count;
	if (conn->tls_started) {
		count = SSL_read_f(conn->ssl, buf, size);
	} else {
		count = read(conn->fd, buf, size);
	}
	if (count <= 0) {
		conn->state = CONN_STATE_FAILURE;
	}

	return (count);
}

static int
iowrite(xmpp_conn_t *conn, char *buf, int size)
{
	int count;

	if (conn->tls_started) {
		count = SSL_write_f(conn->ssl, buf, size);
	} else {
		count = send(conn->fd, buf, size, 0);
	}
	if (count <= 0) {
		conn->state = CONN_STATE_FAILURE;
	}

	return (count);
}

/*
 * notify_event()
 * Description:
 *     Notify all clients an event by going through the client list and invoke
 *     the callback functions.
 */
static void
notify_event(ldom_event_t event, char *ldom_name)
{
	client_info_t *p;

	(void) pthread_mutex_lock(&clt_list.lock);

	for (p = clt_list.head; p != NULL; p = p->next) {
		p->cb(ldom_name, event, p->data);
	}

	(void) pthread_mutex_unlock(&clt_list.lock);
}

/*
 * xmpp_client_thr()
 * Description:
 *     The main entry fo the xmpp client thread.
 */
/*ARGSUSED*/
static void *
xmpp_client_thr(void *data)
{
	int rc = 0;
	int cnt;
	char buf[XMPP_BUF_SIZE];
	xmpp_conn_t conn;

	while (xmpp_enable) {
		/* clear the conn struct */
		bzero(&conn, sizeof (xmpp_conn_t));

		/* keep making a connection until successfully */
		do {
			if (rc = xmpp_connect(&conn))
				(void) sleep(XMPP_SLEEP);
		} while (rc != 0 && xmpp_enable);

		/* write the stream node */
		cnt = iowrite(&conn, (char *)STREAM_START,
		    strlen((char *)STREAM_START));
		if (cnt != strlen((char *)STREAM_START)) {
			xmpp_close(&conn);
			(void) sleep(XMPP_SLEEP);
			continue;
		}

		/* process input */
		while ((conn.state != CONN_STATE_FAILURE) &&
		    (conn.state != CONN_STATE_DONE) && xmpp_enable) {

			/*
			 * Assume the document size of a ldmd response is
			 * less than 1KB. This assumption is valid with the
			 * current ldmd implementation.
			 * Should the document size exceeds 1KB, the buffer
			 * size should be revisited accordingly.
			 */
			(void) memset(buf, 0, XMPP_BUF_SIZE);
			cnt = ioread(&conn, buf, XMPP_BUF_SIZE);
			if (cnt <= 0)
				break;
			if (rc = xmlParseChunk(conn.parser, buf, cnt, 0)) {
				conn.state = CONN_STATE_FAILURE;
			}

			switch (conn.state) {
			case CONN_STATE_LDM_INTERFACE:
				handle_ldm_resp(&conn, buf, cnt);
				break;
			case CONN_STATE_LDM_EVENT:
				handle_ldm_event(&conn, buf, cnt);
				break;
			default:
				break;
			}

			/*
			 * For now, the parser is reset after every read.
			 * It should only be reset once after the ssl is opened
			 * in the start_tls().
			 */
			(void) xmlCtxtResetPush(conn.parser, NULL, NULL, NULL,
			    NULL);
		}
		xmpp_close(&conn);
		(void) sleep(XMPP_SLEEP);
	}
	return (NULL);
}

/*
 * find_client()
 * Description:
 *     Walk to the list to find a libldom client
 */
static client_info_t *
find_client(ldom_hdl_t *lhp)
{
	client_info_t *p;

	for (p = clt_list.head; p != NULL; p = p->next) {
		if (p->lhp == lhp)
			return (p);
	}

	return (NULL);
}

/*
 * xmpp_add_client()
 * Description:
 *     Add a libldom client from the client list.
 */
int
xmpp_add_client(ldom_hdl_t *lhp, ldom_reg_cb_t cb, ldom_cb_arg_t data)
{
	client_info_t *clt;

	(void) pthread_mutex_lock(&clt_list.lock);
	if (find_client(lhp)) {
		/* already exists */
		(void) pthread_mutex_unlock(&clt_list.lock);
		return (-1);
	}

	/* new client */
	clt = (client_info_t *)ldom_alloc(sizeof (client_info_t));
	clt->lhp = lhp;
	clt->cb = cb;
	clt->data = data;
	clt->next = NULL;
	clt->prev = NULL;

	if (clt_list.head == NULL && clt_list.tail == NULL) {
		clt_list.head = clt;
		clt_list.tail = clt;
	} else {
		/* append to the list */
		clt->prev = clt_list.tail;
		clt_list.tail->next  = clt;
		clt_list.tail = clt;
	}

	(void) pthread_mutex_unlock(&clt_list.lock);
	return (0);
}

/*
 * xmpp_remove_client()
 * Description:
 *     Remove a libldom client from the client list.
 */
int
xmpp_remove_client(ldom_hdl_t *lhp)
{
	client_info_t *p;

	(void) pthread_mutex_lock(&clt_list.lock);
	if ((p = find_client(lhp)) == NULL) {
		/* not present */
		(void) pthread_mutex_unlock(&clt_list.lock);
		return (-1);
	}

	if (clt_list.head == p && clt_list.tail == p) {
		/* single item list */
		clt_list.head = NULL;
		clt_list.tail = NULL;
	} else if (clt_list.head == p) {
		/* delete the head */
		clt_list.head = p->next;
		clt_list.head->prev = NULL;
	} else if (clt_list.tail == p) {
		/* delete the tail */
		clt_list.tail = p->prev;
		clt_list.tail->next = NULL;
	} else {
		/* delete a middle node */
		p->next->prev = p->prev;
		p->prev->next = p->next;
	}
	ldom_free(p, sizeof (client_info_t));

	(void) pthread_mutex_unlock(&clt_list.lock);
	return (0);
}

/*
 * xmpp_stop()
 * Description:
 *     Stop the xmpp client thread
 */
/*ARGSUSED*/
void
xmpp_stop(void)
{
	(void) pthread_mutex_lock(&xmpp_tid_lock);
	xmpp_enable = 0;
	if (xmpp_tid) {
		(void) pthread_kill(xmpp_tid, xmpp_thr_sig);
		(void) pthread_join(xmpp_tid, NULL);
		xmpp_tid = 0;
	}
	(void) pthread_mutex_unlock(&xmpp_tid_lock);
}

/*
 * xmpp_start()
 * Description:
 *     Start the xmpp client thread if have not done so.
 */
void
xmpp_start(void)
{
	xmpp_conn_t conn;

	/* Check if the xmmp thread has already started */
	(void) pthread_mutex_lock(&xmpp_tid_lock);
	if (xmpp_tid != 0) {
		(void) pthread_mutex_unlock(&xmpp_tid_lock);
		return;
	}

	/* Check if the ldmd supports xmpp by opening a connection */
	if (xmpp_connect(&conn)) {
		(void) pthread_mutex_unlock(&xmpp_tid_lock);
		return;
	}
	xmpp_close(&conn);
	xmpp_enable = 1;

	/*
	 * create xmpp client thread for receiving domain events
	 * xmpp_thr_sig stores the signal number that is not currently masked.
	 * It is used to stop the client thread.
	 */
	xmpp_thr_sig = ldom_find_thr_sig();
	(void) pthread_create(&xmpp_tid, NULL, xmpp_client_thr, NULL);

	(void) pthread_mutex_unlock(&xmpp_tid_lock);

	/*
	 * Register a function to stop the above thread upon a termination
	 */
	(void) atexit(xmpp_stop);
}

/*
 * This routine will run through the first time we get a remote XMPP
 * connection. After that we will not need to do this again. It cannot be run
 * from main thread at start as we need to alert remote users if the TLS
 * handshake failed.
 */
static int
load_SSL_lib()
{
	int ret = 0;

	/* If we have already opened the library no need to do it again. */
	if (xmpp_dl != NULL)
		return (0);

	/*
	 * If the libssl.so in not in the default path, attempt to open it
	 * under /usr/sfw/lib.
	 */
	xmpp_dl = dlopen("libssl.so", RTLD_NOW);
	if (xmpp_dl == NULL) {
		xmpp_dl = dlopen("/usr/sfw/lib/libssl.so", RTLD_NOW);
		if (xmpp_dl == NULL)
			return (-1);
	}

	FUNCTION_ADD(SSL_load_error_strings_f, SSL_load_error_strings_pt,
	    xmpp_dl, "SSL_load_error_strings", ret);
	FUNCTION_ADD(SSL_library_init_f, SSL_library_init_pt, xmpp_dl,
	    "SSL_library_init", ret);
	FUNCTION_ADD(SSL_CTX_new_f, SSL_CTX_new_pt, xmpp_dl,
	    "SSL_CTX_new", ret);
	FUNCTION_ADD(SSLv23_client_method_f, SSLv23_client_method_pt, xmpp_dl,
	    "SSLv23_client_method", ret);
	FUNCTION_ADD(SSL_write_f, SSL_write_pt, xmpp_dl, "SSL_write", ret);
	FUNCTION_ADD(SSL_CTX_use_PrivateKey_file_f,
	    SSL_CTX_use_PrivateKey_file_pt, xmpp_dl,
	    "SSL_CTX_use_PrivateKey_file", ret);
	FUNCTION_ADD(RAND_seed_f, RAND_seed_pt, xmpp_dl, "RAND_seed", ret);
	FUNCTION_ADD(SSL_get_error_f, SSL_get_error_pt, xmpp_dl,
	    "SSL_get_error", ret);
	FUNCTION_ADD(ERR_get_error_f, ERR_get_error_pt, xmpp_dl,
	    "ERR_get_error", ret);
	FUNCTION_ADD(ERR_error_string_f, ERR_error_string_pt, xmpp_dl,
	    "ERR_error_string", ret);
	FUNCTION_ADD(SSL_connect_f, SSL_connect_pt, xmpp_dl, "SSL_connect",
	    ret);
	FUNCTION_ADD(SSL_CTX_use_certificate_chain_file_f,
	    SSL_CTX_use_certificate_chain_file_pt, xmpp_dl,
	    "SSL_CTX_use_certificate_chain_file", ret);
	FUNCTION_ADD(SSL_set_fd_f, SSL_set_fd_pt, xmpp_dl, "SSL_set_fd", ret);
	FUNCTION_ADD(SSL_free_f, SSL_free_pt, xmpp_dl, "SSL_free", ret);
	FUNCTION_ADD(SSL_read_f, SSL_read_pt, xmpp_dl, "SSL_read", ret);
	FUNCTION_ADD(SSL_new_f, SSL_new_pt, xmpp_dl, "SSL_new", ret);
	FUNCTION_ADD(SSL_get_SSL_CTX_f, SSL_get_SSL_CTX_pt, xmpp_dl,
	    "SSL_get_SSL_CTX", ret);
	FUNCTION_ADD(SSL_CTX_free_f, SSL_CTX_free_pt, xmpp_dl,
	    "SSL_CTX_free", ret);

	if (ret < 0)
		return (-1);
	else
		return (0);
}

/*
 * start_tls()
 * Description:
 *     Load the libssl.so if has not done so and open a ssl connection.
 *     It is assumed that there is one xmpp thread to use the ssl connection.
 *     If multi-thread xmpp clients use the ssl connection, addtional work is
 *     needed to ensure the usage of the ssl be thread-safe.
 */
static int
start_tls(xmpp_conn_t *conn)
{
	int		rv, urand_fd;
	SSL_CTX		*ssl_ctx;
	char		rand_buf[RAND_BUF_SIZE];

	rv = load_SSL_lib();
	if (rv == -1) {
		return (rv);
	}

	urand_fd = open("/dev/random", O_RDONLY);
	if (urand_fd == -1) {
		return (-1);
	}
	(void) read(urand_fd, rand_buf, RAND_BUF_SIZE);

	SSL_library_init_f();
	RAND_seed_f(rand_buf, RAND_BUF_SIZE);

	ssl_ctx = SSL_CTX_new_f(SSLv23_client_method_f());
	if (ssl_ctx == NULL) {
		return (-1);
	}
	conn->ssl = SSL_new_f(ssl_ctx);
	rv = SSL_set_fd_f(conn->ssl, conn->fd);
	if (rv == 0) {
		return (-1);
	}
	rv = SSL_connect_f(conn->ssl);
	if (rv != 1) {
		return (-1);
	}
	conn->tls_started = B_TRUE;
	conn->state = CONN_STATE_TLS;

	(void) iowrite(conn, STREAM_START, strlen(STREAM_START));

	return (0);
}

/*
 * Find and return the first-level subnode (if any) of 'node' which has name
 * 'name'.
 */
xmlNodePtr
xml_find_subnode(xmlNodePtr node, const xmlChar *name)
{
	xmlNodePtr subnode;

	if (node == NULL)
		return (NULL);

	subnode = node->xmlChildrenNode;
	while (subnode != NULL) {
		if (((char *)subnode->name != NULL) &&
		    (xmlStrcmp(subnode->name, name) == 0))
			break;
		subnode = subnode->next;
	}

	return (subnode);
}

/*
 * handle_ldm_resp()
 * Description:
 *     Parse the ldmd response of the domain event registration for the failure
 *     status. If found, set the connection to failure so that it will be
 *     closed and a new xmpp connection is established.
 */
void
handle_ldm_resp(xmpp_conn_t *conn, char *buf, size_t buf_size)
{
	xmlDocPtr	xml_output;
	xmlNodePtr	root, resp, status, cmd, action;
	char		*status_str, *action_str;

	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
		return;
	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
		return;

	/* get the cmd node */
	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
		return;
	if (strcmp((char *)cmd->name, (char *)XML_CMD) != 0)
		return;

	/* get the action node and make sure it is the reg-domain-events */
	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
		return;
	}
	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
		return;
	if (strcmp(action_str, XML_REGISTER_ACTION) != 0) {
		xmlFree(action_str);
		return;
	}
	xmlFree(action_str);

	/* check the status of the response */
	if ((resp = xml_find_subnode(cmd, XML_RESPONSE)) == NULL)
		return;
	if ((status = xml_find_subnode(resp, XML_STATUS)) == NULL)
		return;
	if ((status_str = (char *)xmlNodeGetContent(status)) == NULL)
		return;
	if (strcmp(status_str, (char *)XML_FAILURE) == 0) {
		conn->state = CONN_STATE_FAILURE;
	}
	xmlFree(status_str);
}

/*
 * handle_ldm_event()
 * Description:
 *     Parse the LDM_event for the ldom name and domain action. Then invokes
 *     the clients's callback to notify them the event.
 */
/*ARGSUSED*/
void
handle_ldm_event(xmpp_conn_t *conn, char *buf, size_t buf_size)
{
	int		i;
	xmlDocPtr	xml_output;
	xmlNodePtr	root, cmd, action, data, envelope, content;
	char		*action_str, *ldom_name;
	ldom_event_t	event = LDOM_EVENT_UNKNOWN;

	if ((xml_output = xmlParseMemory((const char *)buf, buf_size)) == NULL)
		return;
	if ((root = xmlDocGetRootElement(xml_output)) == NULL)
		return;

	/* get the action such as bind-domain, unbind-domain, etc. */
	if ((cmd = xml_find_subnode(root, XML_CMD)) == NULL)
		return;
	if ((action = xml_find_subnode(cmd, XML_ACTION)) == NULL) {
		return;
	}
	if ((action_str = (char *)xmlNodeGetContent(action)) == NULL)
		return;
	for (i = 0; i < event_table_size; i++) {
		if (event_table[i].name != NULL &&
		    strcasecmp(event_table[i].name, action_str) == 0) {
			event = event_table[i].id;
			break;
		}
	}
	xmlFree(action_str);

	/* get the ldom name */
	data = xml_find_subnode(cmd, XML_DATA);
	envelope = xml_find_subnode(data, XML_ENVELOPE);
	content = xml_find_subnode(envelope, XML_CONTENT);
	if ((ldom_name = (char *)xmlGetProp(content, XML_ATTR_ID)) == NULL)
		return;

	/* Notifies all the clients the event */
	if (VALID_LDOM_EVENT(event)) {
		notify_event(event, ldom_name);
	}

	xmlFree(ldom_name);
}